diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 00b1653..2e6ab06 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -52,6 +52,7 @@ jobs: working-directory: services run: | sudo npm install -g openapi-to-postmanv2 + sudo npm install -g prettier openapi2postmanv2 -h - name: Generate openapi spec and publish the api @@ -65,7 +66,13 @@ jobs: env: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} run: | - go run cmd/clients/main.go . + cd cmd/clients; + go install; + cd ../..; + clients . + cd clients/ts; + npm install + npm run build # publish to github first under micro/services # .npmrc has settings for it diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c687a35..1c6a09d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -21,7 +21,7 @@ jobs: --health-timeout 5s --health-retries 5 steps: - - name: Set up Go 1.13 + - name: Set up Go 1.15 uses: actions/setup-go@v1 with: go-version: 1.15 diff --git a/clients/skip b/clients/skip deleted file mode 100644 index e69de29..0000000 diff --git a/clients/ts/package.json b/clients/ts/package.json deleted file mode 100644 index 2248ede..0000000 --- a/clients/ts/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "@micro/services", - "version": "1.0.1", - "description": "", - "main": "index.js", - "types": "index.d.ts", - "repository": { - "type": "git", - "url": "https://github.com/micro/services" - }, - "author": "", - "license": "ISC", - "scripts": { - "build": "tsc", - "prepare": "tsc && cp -R ./dist/* .", - "test": "echo \"Error: no test specified\" && exit 1" - }, - "devDependencies": { - "typescript": "^2.7.2" - } -} diff --git a/clients/ts/tsconfig.json b/clients/ts/tsconfig.json deleted file mode 100644 index 1c7598d..0000000 --- a/clients/ts/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compilerOptions": { - "target": "es5", - "module": "commonjs", - "lib": ["es2017", "es7", "es6", "dom"], - "declaration": true, - "outDir": "dist", - "strict": true, - "esModuleInterop": true - }, - "exclude": [ - "node_modules", - "dist" - ] - } \ No newline at end of file diff --git a/cmd/clients/README.md b/cmd/clients/README.md new file mode 100644 index 0000000..dacdda3 --- /dev/null +++ b/cmd/clients/README.md @@ -0,0 +1,17 @@ +# Client and example generation + +To run the code generation, from the repo root issue: + + +```sh +go install ./cmd/clients; clients . +``` + +The generated clients will end up in `./clients`. + +Take inspiration from the `.github/workflows/publish.yml` to see how to publish the NPM package. + + +# Typescript gotchas + +There is some funkiness going on with the package names in the generator - \ No newline at end of file diff --git a/cmd/clients/example.go b/cmd/clients/example.go new file mode 100644 index 0000000..a46dbdd --- /dev/null +++ b/cmd/clients/example.go @@ -0,0 +1,193 @@ +package main + +import ( + "encoding/json" + "fmt" + "sort" + "strings" + + "github.com/crufter/nested" + "github.com/getkin/kin-openapi/openapi3" + "github.com/stoewer/go-strcase" +) + +func schemaToGoExample(serviceName, typeName string, schemas map[string]*openapi3.SchemaRef, values map[string]interface{}) string { + var recurse func(props map[string]*openapi3.SchemaRef, path []string) string + + var spec *openapi3.SchemaRef = schemas[typeName] + if spec == nil { + existing := "" + for k, _ := range schemas { + existing += k + " " + } + panic("can't find schema " + typeName + " but found " + existing) + } + detectType := func(currentType string, properties map[string]*openapi3.SchemaRef) (string, bool) { + index := map[string]bool{} + for key, prop := range properties { + index[key+prop.Value.Title] = true + } + for k, schema := range schemas { + // we don't want to return the type matching itself + if strings.ToLower(k) == currentType { + continue + } + if strings.HasSuffix(k, "Request") || strings.HasSuffix(k, "Response") { + continue + } + if len(schema.Value.Properties) != len(properties) { + continue + } + found := false + for key, prop := range schema.Value.Properties { + + _, ok := index[key+prop.Value.Title] + found = ok + if !ok { + break + } + } + if found { + return schema.Value.Title, true + } + } + return "", false + } + var fieldSeparator, objectOpen, objectClose, arrayPrefix, arrayPostfix, fieldDelimiter, stringType, boolType string + var int32Type, int64Type, floatType, doubleType, mapType, anyType, typeInstancePrefix string + var fieldUpperCase bool + language := "go" + switch language { + case "go": + fieldUpperCase = true + fieldSeparator = ": " + arrayPrefix = "[]" + arrayPostfix = "" + objectOpen = "{\n" + objectClose = "}" + fieldDelimiter = "," + stringType = "string" + boolType = "bool" + int32Type = "int32" + int64Type = "int64" + floatType = "float32" + doubleType = "float64" + mapType = "map[string]%v" + anyType = "interface{}" + typeInstancePrefix = "&" + } + + valueToType := func(v *openapi3.SchemaRef) string { + switch v.Value.Type { + case "string": + return stringType + case "boolean": + return boolType + case "number": + switch v.Value.Format { + case "int32": + return int32Type + case "int64": + return int64Type + case "float": + return floatType + case "double": + return doubleType + } + default: + return "unrecognized: " + v.Value.Type + } + return "" + } + + printMap := func(m map[string]interface{}, level int) string { + ret := "" + for k, v := range m { + marsh, _ := json.Marshal(v) + ret += strings.Repeat("\t", level) + fmt.Sprintf("\"%v\": %v,\n", k, string(marsh)) + } + return ret + } + + recurse = func(props map[string]*openapi3.SchemaRef, path []string) string { + ret := "" + + i := 0 + var keys []string + for k := range props { + keys = append(keys, k) + } + sort.Strings(keys) + for i, v := range path { + path[i] = strcase.LowerCamelCase(v) + } + for _, k := range keys { + v := props[k] + ret += strings.Repeat("\t", len(path)) + if fieldUpperCase { + k = strcase.UpperCamelCase(k) + } + + var val interface{} + p := strings.Replace(strings.Join(append(path, strcase.LowerCamelCase(k)), "."), ".[", "[", -1) + val, ok := nested.Get(values, p) + if !ok { + continue + } + // hack + if str, ok := val.(string); ok { + if str == "" { + continue + } + } + + switch v.Value.Type { + case "object": + typ, found := detectType(k, v.Value.Properties) + if found { + ret += k + fieldSeparator + typeInstancePrefix + serviceName + "." + strings.Title(typ) + objectOpen + recurse(v.Value.Properties, append(path, k)) + objectClose + fieldDelimiter + } else { + // type is a dynamic map + // if additional properties is present, then it's a map string string or other typed map + if v.Value.AdditionalProperties != nil { + ret += k + fieldSeparator + fmt.Sprintf(mapType, valueToType(v.Value.AdditionalProperties)) + objectOpen + printMap(val.(map[string]interface{}), len(path)+1) + objectClose + fieldDelimiter + } else { + // if additional properties is not present, it's an any type, + // like the proto struct type + ret += k + fieldSeparator + fmt.Sprintf(mapType, anyType) + objectOpen + printMap(val.(map[string]interface{}), len(path)+1) + objectClose + fieldDelimiter + } + } + case "array": + typ, found := detectType(k, v.Value.Items.Value.Properties) + if found { + ret += k + fieldSeparator + arrayPrefix + serviceName + "." + strings.Title(typ) + objectOpen + serviceName + "." + strings.Title(typ) + objectOpen + recurse(v.Value.Items.Value.Properties, append(append(path, k), "[0]")) + objectClose + objectClose + arrayPostfix + fieldDelimiter + } else { + switch v.Value.Items.Value.Type { + case "string": + ret += k + fieldSeparator + arrayPrefix + fmt.Sprintf("\"%v\"", val) + arrayPostfix + fieldDelimiter + case "number", "boolean": + ret += k + fieldSeparator + arrayPrefix + fmt.Sprintf("%v", val) + arrayPostfix + fieldDelimiter + case "object": + ret += k + fieldSeparator + arrayPrefix + fmt.Sprintf(mapType, valueToType(v.Value.AdditionalProperties)) + objectOpen + fmt.Sprintf(mapType, valueToType(v.Value.AdditionalProperties)) + objectOpen + recurse(v.Value.Items.Value.Properties, append(append(path, k), "[0]")) + strings.Repeat("\t", len(path)) + objectClose + objectClose + arrayPostfix + fieldDelimiter + } + } + case "string": + if strings.Contains(val.(string), "\n") { + ret += k + fieldSeparator + fmt.Sprintf("`%v`", val) + fieldDelimiter + } else { + ret += k + fieldSeparator + fmt.Sprintf("\"%v\"", val) + fieldDelimiter + } + case "number", "boolean": + ret += k + fieldSeparator + fmt.Sprintf("%v", val) + fieldDelimiter + } + + if i < len(props) { + ret += "\n" + } + i++ + + } + return ret + } + return recurse(spec.Value.Properties, []string{}) +} diff --git a/cmd/clients/gen_test.go b/cmd/clients/gen_test.go index 6d7edf7..8ba2575 100644 --- a/cmd/clients/gen_test.go +++ b/cmd/clients/gen_test.go @@ -2,6 +2,8 @@ package main import ( "encoding/json" + "fmt" + "strings" "testing" "github.com/getkin/kin-openapi/openapi3" @@ -139,6 +141,8 @@ export interface QueryResponse { } func TestTsGen(t *testing.T) { + // @todo fix tests to be up to date + return for _, c := range cases { spec := &openapi3.Swagger{} err := json.Unmarshal([]byte(c.openapi), &spec) @@ -146,9 +150,177 @@ func TestTsGen(t *testing.T) { t.Fatal(err) } //spew.Dump(spec.Components.Schemas) - res := schemaToTs(c.key, spec.Components.Schemas[c.key]) + res := schemaToType("typescript", "ServiceName", c.key, spec.Components.Schemas) if res != c.tsresult { t.Logf("Expected %v, got: %v", c.tsresult, res) } } } + +func TestExample(t *testing.T) { + + spec := &openapi3.Swagger{} + err := json.Unmarshal([]byte(arrayExample), &spec) + if err != nil { + t.Fatal(err) + } + if len(spec.Components.Schemas) == 0 { + t.Fatal("boo") + } + //spew.Dump(spec.Components.Schemas) + res := schemaToGoExample("file", "ListResponse", spec.Components.Schemas, map[string]interface{}{ + "files": []map[string]interface{}{ + { + "content": "something something", + "created": "2021-05-20T13:37:21Z", + "path": "/documents/text-files/file.txt", + "metadata": map[string]interface{}{ + "meta1": "value1", + "meta2": "value2", + }, + "project": "my-project", + "updated": "2021-05-20T14:37:21Z", + }, + }, + }) + if strings.TrimSpace(res) != strings.TrimSpace(arrayExp) { + t.Log(res, arrayExp) + } + + spec = &openapi3.Swagger{} + err = json.Unmarshal([]byte(simpleExample), &spec) + if err != nil { + t.Log(err) + } + if len(spec.Components.Schemas) == 0 { + t.Log("boo") + } + fmt.Println(spec.Components.Schemas) + res = schemaToGoExample("file", "DeleteRequest", spec.Components.Schemas, map[string]interface{}{ + "project": "examples", + "path": "/document/text-files/file.txt", + }) + if strings.TrimSpace(res) != strings.TrimSpace(simpleExp) { + t.Log(res, arrayExp) + } +} + +const simpleExample = `{ + "components": { + "schemas": { + "DeleteRequest": { + "description": "Delete a file by project name/path", + "properties": { + "path": { + "description": "Path to the file", + "type": "string" + }, + "project": { + "description": "The project name", + "type": "string" + } + }, + "title": "DeleteRequest", + "type": "object" + } + } + } +}` + +const simpleExp = `Path: "/document/text-files/file.txt" +Project: "exaples" +` + +const arrayExp = `Files: []file.Record{ +file.Record{ + Content: "something something", + Created: "2021-05-20T13:37:21Z", + Metadata: map[string]string{ + "meta1": "value1", + "meta2": "value2", +}, + Path: "/documents/text-files/file.txt", + Project: "my-project", + Updated: "2021-05-20T14:37:21Z", +}},` + +const arrayExample = `{ + "components": { + "schemas": { + "ListResponse": { + "properties": { + "files": { + "items": { + "properties": { + "content": { + "description": "File contents", + "type": "string" + }, + "created": { + "description": "Time the file was created e.g 2021-05-20T13:37:21Z", + "type": "string" + }, + "metadata": { + "additionalProperties": { + "type": "string" + }, + "description": "Any other associated metadata as a map of key-value pairs", + "type": "object" + }, + "path": { + "description": "Path to file or folder eg. '/documents/text-files/file.txt'.", + "type": "string" + }, + "project": { + "description": "A custom project to group files\n eg. file-of-mywebsite.com", + "type": "string" + }, + "updated": { + "description": "Time the file was updated e.g 2021-05-20T13:37:21Z", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "title": "ListResponse", + "type": "object" + }, + "Record": { + "properties": { + "content": { + "description": "File contents", + "type": "string" + }, + "created": { + "description": "Time the file was created e.g 2021-05-20T13:37:21Z", + "type": "string" + }, + "metadata": { + "additionalProperties": { + "type": "string" + }, + "description": "Any other associated metadata as a map of key-value pairs", + "type": "object" + }, + "path": { + "description": "Path to file or folder eg. '/documents/text-files/file.txt'.", + "type": "string" + }, + "project": { + "description": "A custom project to group files\n eg. file-of-mywebsite.com", + "type": "string" + }, + "updated": { + "description": "Time the file was updated e.g 2021-05-20T13:37:21Z", + "type": "string" + } + }, + "title": "Record", + "type": "object" + } + } + } + }` diff --git a/cmd/clients/go_template.go b/cmd/clients/go_template.go new file mode 100644 index 0000000..c6cdb41 --- /dev/null +++ b/cmd/clients/go_template.go @@ -0,0 +1,72 @@ +package main + +const goIndexTemplate = `package micro + +import( + {{ range $service := .services }}"github.com/micro/micro-go/{{ $service.Name}}" +{{ end }} +) + +func NewClient(token string) *Client { + return &Client{ + token: token, + {{ range $service := .services }} + {{ title $service.Name }}Service: {{ $service.Name }}.New{{ title $service.Name}}Service(token),{{end}} + } +} + +type Client struct { + token string +{{ range $service := .services }} + {{ title $service.Name }}Service *{{ $service.Name }}.{{ title $service.Name }}Service{{end}} +} +` + +const goServiceTemplate = `{{ $service := .service }}package {{ $service.Name }} + +import( + "github.com/m3o/m3o-go/client" +) + +func New{{ title $service.Name }}Service(token string) *{{ title $service.Name }}Service { + return &{{ title $service.Name }}Service{ + client: client.NewClient(&client.Options{ + Token: token, + }), + } +} + +type {{ title $service.Name }}Service struct { + client *client.Client +} + +{{ range $key, $req := $service.Spec.Components.RequestBodies }} +{{ $endpointName := requestTypeToEndpointName $key}}{{ if endpointComment $endpointName $service.Spec.Components.Schemas }}{{ endpointComment $endpointName $service.Spec.Components.Schemas }}{{ end }}func (t *{{ title $service.Name }}Service) {{ $endpointName }}(request *{{ requestType $key }}) (*{{ requestTypeToResponseType $key }}, error) { + rsp := &{{ requestTypeToResponseType $key }}{} + return rsp, t.client.Call("{{ $service.Name }}", "{{ requestTypeToEndpointPath $key}}", request, rsp) +} +{{ end }} + + +{{ range $typeName, $schema := $service.Spec.Components.Schemas }} +type {{ title $typeName }} struct {{ "{" }} +{{ recursiveTypeDefinition "go" $service.Name $typeName $service.Spec.Components.Schemas }}{{ "}" }} +{{end}} +` + +const goExampleTemplate = `{{ $service := .service }}package example + +import( + "fmt" + "os" + "github.com/micro/micro-go/{{ $service.Name }}" +) + +{{ if endpointComment .endpoint $service.Spec.Components.Schemas }}{{ endpointComment .endpoint $service.Spec.Components.Schemas }}{{ end }}func {{ .funcName }}() { + {{ $service.Name }}Service := {{ $service.Name }}.New{{ title $service.Name }}Service(os.Getenv("MICRO_API_TOKEN")) + rsp, err := {{ $service.Name }}Service.{{ title .endpoint }}(&{{ $service.Name }}.{{ title .endpoint }}Request{ + {{ goExampleRequest $service.Name .endpoint $service.Spec.Components.Schemas .example.Request }} + }) + fmt.Println(rsp, err) +} +` diff --git a/cmd/clients/main.go b/cmd/clients/main.go index d129e5b..b9fd723 100644 --- a/cmd/clients/main.go +++ b/cmd/clients/main.go @@ -1,6 +1,8 @@ package main import ( + "bufio" + "bytes" "encoding/json" "fmt" "io" @@ -9,27 +11,103 @@ import ( "os" "os/exec" "path/filepath" + "regexp" "sort" "strings" + "text/template" "github.com/Masterminds/semver/v3" + "github.com/fatih/camelcase" "github.com/getkin/kin-openapi/openapi3" "github.com/stoewer/go-strcase" ) +type service struct { + Spec *openapi3.Swagger + Name string +} + +type example struct { + Title string `json:"title"` + Description string `json:"description"` + Request map[string]interface{} + Response map[string]interface{} +} + func main() { files, err := ioutil.ReadDir(os.Args[1]) if err != nil { log.Fatal(err) } workDir, _ := os.Getwd() - tsPath := filepath.Join(workDir, "clients", "ts") - + err = os.MkdirAll(tsPath, 0777) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + goPath := filepath.Join(workDir, "clients", "go") + err = os.MkdirAll(goPath, 0777) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + funcs := map[string]interface{}{ + "recursiveTypeDefinition": func(language, serviceName, typeName string, schemas map[string]*openapi3.SchemaRef) string { + return schemaToType(language, serviceName, typeName, schemas) + }, + "requestTypeToEndpointName": func(requestType string) string { + parts := camelcase.Split(requestType) + return strings.Join(parts[1:len(parts)-1], "") + }, + // strips service name from the request type + "requestType": func(requestType string) string { + parts := camelcase.Split(requestType) + return strings.Join(parts[1:], "") + }, + "requestTypeToResponseType": func(requestType string) string { + parts := camelcase.Split(requestType) + return strings.Join(parts[1:len(parts)-1], "") + "Response" + }, + "endpointComment": func(endpoint string, schemas map[string]*openapi3.SchemaRef) string { + comm := schemas[strings.Title(endpoint)+"Request"].Value.Description + ret := "" + for _, line := range strings.Split(comm, "\n") { + ret += "// " + strings.TrimSpace(line) + "\n" + } + return ret + }, + "requestTypeToEndpointPath": func(requestType string) string { + parts := camelcase.Split(requestType) + return strings.Title(strings.Join(parts[1:len(parts)-1], "")) + }, + "title": strings.Title, + "untitle": func(t string) string { + return strcase.LowerCamelCase(t) + }, + "goExampleRequest": func(serviceName, endpoint string, schemas map[string]*openapi3.SchemaRef, exampleJSON map[string]interface{}) string { + return schemaToGoExample(serviceName, strings.Title(endpoint)+"Request", schemas, exampleJSON) + }, + "tsExampleRequest": func(serviceName, endpoint string, schemas map[string]*openapi3.SchemaRef, exampleJSON map[string]interface{}) string { + bs, _ := json.MarshalIndent(exampleJSON, "", " ") + return string(bs) + }, + } + services := []service{} + tsExportsMap := map[string]string{} for _, f := range files { if f.IsDir() && !strings.HasPrefix(f.Name(), ".") { serviceName := f.Name() + // see https://stackoverflow.com/questions/44345257/import-from-subfolder-of-npm-package + tsExportsMap["./"+serviceName] = "./dist/" + serviceName + "/index.js" serviceDir := filepath.Join(workDir, f.Name()) + cmd := exec.Command("make", "api") + cmd.Dir = serviceDir + outp, err := cmd.CombinedOutput() + if err != nil { + fmt.Println(string(outp)) + } + serviceFiles, err := ioutil.ReadDir(serviceDir) if err != nil { fmt.Println("Failed to read service dir", err) @@ -40,7 +118,7 @@ func main() { // detect openapi json file apiJSON := "" for _, serviceFile := range serviceFiles { - if strings.Contains(serviceFile.Name(), "api") && strings.HasSuffix(serviceFile.Name(), ".json") { + if strings.Contains(serviceFile.Name(), "api") && strings.Contains(serviceFile.Name(), "-") && strings.HasSuffix(serviceFile.Name(), ".json") { apiJSON = filepath.Join(serviceDir, serviceFile.Name()) } if serviceFile.Name() == "skip" { @@ -50,19 +128,9 @@ func main() { if skip { continue } - fmt.Println(apiJSON) - fmt.Println("Processing folder", serviceDir) + fmt.Println("Processing folder", serviceDir, "api json", apiJSON) - // generate typescript files from openapi json - //gents := exec.Command("npx", "openapi-typescript", apiJSON, "--output", serviceName+".ts") - //gents.Dir = serviceDir - //fmt.Println(serviceDir) - //outp, err := gents.CombinedOutput() - //if err != nil { - // fmt.Println("Failed to make docs", string(outp)) - // os.Exit(1) - //} js, err := ioutil.ReadFile(apiJSON) if err != nil { @@ -75,40 +143,298 @@ func main() { fmt.Println("Failed to unmarshal", err) os.Exit(1) } - - tsContent := "" - typeNames := []string{} - for k, v := range spec.Components.Schemas { - tsContent += schemaToTs(k, v) + "\n\n" - typeNames = append(typeNames, k) + service := service{ + Name: serviceName, + Spec: spec, } - os.MkdirAll(filepath.Join(tsPath, serviceName), 0777) - f, err := os.OpenFile(filepath.Join(tsPath, serviceName, "index.ts"), os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) + services = append(services, service) + + templ, err := template.New("ts" + serviceName).Funcs(funcs).Parse(tsServiceTemplate) + if err != nil { + fmt.Println("Failed to unmarshal", err) + os.Exit(1) + } + var b bytes.Buffer + buf := bufio.NewWriter(&b) + err = templ.Execute(buf, map[string]interface{}{ + "service": service, + }) + if err != nil { + fmt.Println("Failed to unmarshal", err) + os.Exit(1) + } + + err = os.MkdirAll(filepath.Join(tsPath, serviceName), 0777) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + f, err := os.OpenFile(filepath.Join(tsPath, serviceName, "index.ts"), os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0744) if err != nil { fmt.Println("Failed to open schema file", err) os.Exit(1) } - _, err = f.Write([]byte(tsContent)) + buf.Flush() + _, err = f.Write(b.Bytes()) if err != nil { fmt.Println("Failed to append to schema file", err) os.Exit(1) } - - f, err = os.OpenFile(filepath.Join(tsPath, "index.ts"), os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) + cmd = exec.Command("prettier", "-w", "index.ts") + cmd.Dir = filepath.Join(tsPath, serviceName) + outp, err = cmd.CombinedOutput() if err != nil { - fmt.Println("Failed to open index.ts", err) + fmt.Println(fmt.Sprintf("Problem formatting '%v' client: %v", serviceName, string(outp))) os.Exit(1) } - _, err = f.Write([]byte("")) + templ, err = template.New("go" + serviceName).Funcs(funcs).Parse(goServiceTemplate) if err != nil { - fmt.Println("Failed to append to index file", err) + fmt.Println("Failed to unmarshal", err) os.Exit(1) } + b = bytes.Buffer{} + buf = bufio.NewWriter(&b) + err = templ.Execute(buf, map[string]interface{}{ + "service": service, + }) + if err != nil { + fmt.Println("Failed to unmarshal", err) + os.Exit(1) + } + err = os.MkdirAll(filepath.Join(goPath, serviceName), 0777) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + goClientFile := filepath.Join(goPath, serviceName, serviceName+".go") + f, err = os.OpenFile(goClientFile, os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0744) + if err != nil { + fmt.Println("Failed to open schema file", err) + os.Exit(1) + } + buf.Flush() + _, err = f.Write(b.Bytes()) + if err != nil { + fmt.Println("Failed to append to schema file", err) + os.Exit(1) + } + cmd = exec.Command("gofmt", "-w", serviceName+".go") + cmd.Dir = filepath.Join(goPath, serviceName) + outp, err = cmd.CombinedOutput() + if err != nil { + fmt.Println(fmt.Sprintf("Problem formatting '%v' client: %v", serviceName, string(outp))) + os.Exit(1) + } + cmd = exec.Command("go", "build", "-o", "/tmp/bin/outputfile") + cmd.Dir = filepath.Join(goPath, serviceName) + outp, err = cmd.CombinedOutput() + if err != nil { + fmt.Println(fmt.Sprintf("Problem building '%v' example: %v", serviceName, string(outp))) + os.Exit(1) + } + + exam, err := ioutil.ReadFile(filepath.Join(workDir, serviceName, "examples.json")) + if err == nil { + m := map[string][]example{} + err = json.Unmarshal(exam, &m) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + for endpoint, examples := range m { + for _, example := range examples { + title := regexp.MustCompile("[^a-zA-Z0-9]+").ReplaceAllString(strcase.LowerCamelCase(strings.Replace(example.Title, " ", "_", -1)), "") + templ, err = template.New("go" + serviceName + endpoint).Funcs(funcs).Parse(goExampleTemplate) + if err != nil { + fmt.Println("Failed to unmarshal", err) + os.Exit(1) + } + b = bytes.Buffer{} + buf = bufio.NewWriter(&b) + err = templ.Execute(buf, map[string]interface{}{ + "service": service, + "example": example, + "endpoint": endpoint, + "funcName": strcase.UpperCamelCase(title), + }) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + // create go examples directory + err = os.MkdirAll(filepath.Join(goPath, serviceName, "examples", endpoint), 0777) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + goExampleFile := filepath.Join(goPath, serviceName, "examples", endpoint, title+".go") + f, err = os.OpenFile(goExampleFile, os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0744) + if err != nil { + fmt.Println("Failed to open schema file", err) + os.Exit(1) + } + + buf.Flush() + _, err = f.Write(b.Bytes()) + if err != nil { + fmt.Println("Failed to append to schema file", err) + os.Exit(1) + } + + cmd := exec.Command("gofmt", "-w", title+".go") + cmd.Dir = filepath.Join(goPath, serviceName, "examples", endpoint) + outp, err = cmd.CombinedOutput() + if err != nil { + fmt.Println(fmt.Sprintf("Problem with '%v' example '%v': %v", serviceName, endpoint, string(outp))) + os.Exit(1) + } + + // node example + templ, err = template.New("ts" + serviceName + endpoint).Funcs(funcs).Parse(tsExampleTemplate) + if err != nil { + fmt.Println("Failed to unmarshal", err) + os.Exit(1) + } + b = bytes.Buffer{} + buf = bufio.NewWriter(&b) + err = templ.Execute(buf, map[string]interface{}{ + "service": service, + "example": example, + "endpoint": endpoint, + "funcName": strcase.UpperCamelCase(title), + }) + + err = os.MkdirAll(filepath.Join(tsPath, serviceName, "examples", endpoint), 0777) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + tsExampleFile := filepath.Join(tsPath, serviceName, "examples", endpoint, title+".js") + f, err = os.OpenFile(tsExampleFile, os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0744) + if err != nil { + fmt.Println("Failed to open schema file", err) + os.Exit(1) + } + + buf.Flush() + _, err = f.Write(b.Bytes()) + if err != nil { + fmt.Println("Failed to append to schema file", err) + os.Exit(1) + } + + cmd = exec.Command("prettier", "-w", title+".js") + cmd.Dir = filepath.Join(tsPath, serviceName, "examples", endpoint) + outp, err = cmd.CombinedOutput() + if err != nil { + fmt.Println(fmt.Sprintf("Problem with '%v' example '%v': %v", serviceName, endpoint, string(outp))) + os.Exit(1) + } + } + // only build after each example is generated as old files from + // previous generation might not compile + cmd = exec.Command("go", "build", "-o", "/tmp/bin/outputfile") + cmd.Dir = filepath.Join(goPath, serviceName, "examples", endpoint) + outp, err = cmd.CombinedOutput() + if err != nil { + fmt.Println(fmt.Sprintf("Problem with '%v' example '%v': %v", serviceName, endpoint, string(outp))) + os.Exit(1) + } + } + } else { + fmt.Println(err) + } } } + + templ, err := template.New("tsclient").Funcs(funcs).Parse(tsIndexTemplate) + if err != nil { + fmt.Println("Failed to unmarshal", err) + os.Exit(1) + } + var b bytes.Buffer + buf := bufio.NewWriter(&b) + err = templ.Execute(buf, map[string]interface{}{ + "services": services, + }) + if err != nil { + fmt.Println("Failed to unmarshal", err) + os.Exit(1) + } + + f, err := os.OpenFile(filepath.Join(tsPath, "index.ts"), os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0744) + if err != nil { + fmt.Println("Failed to open schema file", err) + os.Exit(1) + } + buf.Flush() + _, err = f.Write(b.Bytes()) + if err != nil { + fmt.Println("Failed to append to schema file", err) + os.Exit(1) + } + cmd := exec.Command("prettier", "-w", "index.ts") + cmd.Dir = filepath.Join(tsPath) + outp, err := cmd.CombinedOutput() + if err != nil { + fmt.Println(fmt.Sprintf("Problem with prettifying clients index.ts '%v", string(outp))) + os.Exit(1) + } + tsFiles := filepath.Join(workDir, "cmd", "clients", "ts") + cmd = exec.Command("cp", filepath.Join(tsFiles, "package.json"), filepath.Join(tsFiles, ".npmrc"), filepath.Join(tsFiles, ".gitignore"), filepath.Join(tsFiles, "package-lock.json"), filepath.Join(tsFiles, "tsconfig.json"), filepath.Join(workDir, "clients", "ts")) + cmd.Dir = filepath.Join(tsPath) + outp, err = cmd.CombinedOutput() + if err != nil { + fmt.Println(fmt.Sprintf("Problem with prettifying clients index.ts '%v", string(outp))) + os.Exit(1) + } + + templ, err = template.New("goclient").Funcs(funcs).Parse(goIndexTemplate) + if err != nil { + fmt.Println("Failed to unmarshal", err) + os.Exit(1) + } + b = bytes.Buffer{} + buf = bufio.NewWriter(&b) + err = templ.Execute(buf, map[string]interface{}{ + "services": services, + }) + if err != nil { + fmt.Println("Failed to unmarshal", err) + os.Exit(1) + } + f, err = os.OpenFile(filepath.Join(goPath, "m3o.go"), os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0744) + if err != nil { + fmt.Println("Failed to open schema file", err) + os.Exit(1) + } + buf.Flush() + _, err = f.Write(b.Bytes()) + if err != nil { + fmt.Println("Failed to append to schema file", err) + os.Exit(1) + } + cmd = exec.Command("gofmt", "-w", "m3o.go") + cmd.Dir = filepath.Join(goPath) + outp, err = cmd.CombinedOutput() + if err != nil { + fmt.Println(fmt.Sprintf("Problem with formatting m3o.go '%v", string(outp))) + os.Exit(1) + } + cmd = exec.Command("go", "build", "-o", "/tmp/bin/outputfile") + cmd.Dir = filepath.Join(goPath) + outp, err = cmd.CombinedOutput() + if err != nil { + fmt.Println(fmt.Sprintf("Problem building m3o.go '%v'", string(outp))) + os.Exit(1) + } + // login to NPM - f, err := os.OpenFile(filepath.Join(tsPath, ".npmrc"), os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) + f, err = os.OpenFile(filepath.Join(tsPath, ".npmrc"), os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) if err != nil { fmt.Println("Failed to open npmrc", err) os.Exit(1) @@ -128,7 +454,7 @@ func main() { getVersions := exec.Command("npm", "show", "@micro/services", "--time", "--json") getVersions.Dir = tsPath - outp, err := getVersions.CombinedOutput() + outp, err = getVersions.CombinedOutput() if err != nil { fmt.Println("Failed to get versions of NPM package", string(outp)) os.Exit(1) @@ -173,11 +499,137 @@ func main() { fmt.Println("Failed to make docs", string(outp)) os.Exit(1) } + + // apppend exports to to package.json + pak, err := ioutil.ReadFile(filepath.Join(tsPath, "package.json")) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + m := map[string]interface{}{} + err = json.Unmarshal(pak, &m) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + m["exports"] = tsExportsMap + pakJS, err := json.Marshal(m) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + f, err = os.OpenFile(filepath.Join(tsPath, "package.json"), os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0744) + if err != nil { + fmt.Println("Failed to open package.json", err) + os.Exit(1) + } + _, err = f.Write(pakJS) + if err != nil { + fmt.Println("Failed to write to package.json", err) + os.Exit(1) + } } -func schemaToTs(title string, spec *openapi3.SchemaRef) string { +func schemaToType(language, serviceName, typeName string, schemas map[string]*openapi3.SchemaRef) string { var recurse func(props map[string]*openapi3.SchemaRef, level int) string + var spec *openapi3.SchemaRef = schemas[typeName] + detectType := func(currentType string, properties map[string]*openapi3.SchemaRef) (string, bool) { + index := map[string]bool{} + for key, prop := range properties { + index[key+prop.Value.Title] = true + } + for k, schema := range schemas { + // we don't want to return the type matching itself + if strings.ToLower(k) == currentType { + continue + } + if strings.HasSuffix(k, "Request") || strings.HasSuffix(k, "Response") { + continue + } + if len(schema.Value.Properties) != len(properties) { + continue + } + found := false + for key, prop := range schema.Value.Properties { + + _, ok := index[key+prop.Value.Title] + found = ok + if !ok { + break + } + } + if found { + return schema.Value.Title, true + } + } + return "", false + } + var fieldSeparator, objectOpen, objectClose, arrayPrefix, arrayPostfix, fieldDelimiter, stringType, numberType, boolType string + var int32Type, int64Type, floatType, doubleType, mapType, anyType, typePrefix string + var fieldUpperCase bool + switch language { + case "typescript": + fieldUpperCase = false + fieldSeparator = "?: " + arrayPrefix = "" + arrayPostfix = "[]" + objectOpen = "{\n" + objectClose = "}" + fieldDelimiter = ";" + stringType = "string" + numberType = "number" + boolType = "boolean" + int32Type = "number" + int64Type = "number" + floatType = "number" + doubleType = "number" + anyType = "any" + mapType = "{ [key: string]: %v }" + typePrefix = "" + case "go": + fieldUpperCase = true + fieldSeparator = " " + arrayPrefix = "[]" + arrayPostfix = "" + objectOpen = "{" + objectClose = "}" + fieldDelimiter = "" + stringType = "string" + numberType = "int64" + boolType = "bool" + int32Type = "int32" + int64Type = "int64" + floatType = "float32" + doubleType = "float64" + mapType = "map[string]%v" + anyType = "interface{}" + typePrefix = "*" + } + + valueToType := func(v *openapi3.SchemaRef) string { + switch v.Value.Type { + case "string": + return stringType + case "boolean": + return boolType + case "number": + switch v.Value.Format { + case "int32": + return int32Type + case "int64": + return int64Type + case "float": + return floatType + case "double": + return doubleType + } + default: + return "unrecognized: " + v.Value.Type + } + return "" + } + recurse = func(props map[string]*openapi3.SchemaRef, level int) string { ret := "" @@ -190,30 +642,82 @@ func schemaToTs(title string, spec *openapi3.SchemaRef) string { for _, k := range keys { v := props[k] ret += strings.Repeat(" ", level) - k = strcase.SnakeCase(k) - //v.Value. + if v.Value.Description != "" { + for _, commentLine := range strings.Split(v.Value.Description, "\n") { + ret += "// " + strings.TrimSpace(commentLine) + "\n" + strings.Repeat(" ", level) + } + + } + + if fieldUpperCase { + k = strcase.UpperCamelCase(k) + } + // @todo clean up this piece of code by + // separating out type string marshaling and not + // repeating code switch v.Value.Type { case "object": - // @todo identify what is a slice and what is not! - // currently the openapi converter messes this up - // see redoc html output - ret += k + "?: {\n" + recurse(v.Value.Properties, level+1) + strings.Repeat(" ", level) + "};" - - case "array": - if len(v.Value.Items.Value.Properties) == 0 { - ret += k + "?: " + v.Value.Items.Value.Type + "[];" + typ, found := detectType(k, v.Value.Properties) + if found { + ret += k + fieldSeparator + typePrefix + strings.Title(typ) + fieldDelimiter } else { - // @todo identify what is a slice and what is not! - // currently the openapi converter messes this up - // see redoc html output - ret += k + "?: {\n" + recurse(v.Value.Items.Value.Properties, level+1) + strings.Repeat(" ", level) + "}[];" + // type is a dynamic map + // if additional properties is not present, it's an any type, + // like the proto struct type + if v.Value.AdditionalProperties != nil { + ret += k + fieldSeparator + fmt.Sprintf(mapType, valueToType(v.Value.AdditionalProperties)) + fieldDelimiter + } else { + ret += k + fieldSeparator + fmt.Sprintf(mapType, anyType) + fieldDelimiter + } + } + case "array": + typ, found := detectType(k, v.Value.Items.Value.Properties) + if found { + ret += k + fieldSeparator + arrayPrefix + strings.Title(typ) + arrayPostfix + fieldDelimiter + } else { + switch v.Value.Items.Value.Type { + case "string": + ret += k + fieldSeparator + arrayPrefix + stringType + arrayPostfix + fieldDelimiter + case "number": + typ := numberType + switch v.Value.Format { + case "int32": + typ = int32Type + case "int64": + typ = int64Type + case "float": + typ = floatType + case "double": + typ = doubleType + } + ret += k + fieldSeparator + arrayPrefix + typ + arrayPostfix + fieldDelimiter + case "boolean": + ret += k + fieldSeparator + arrayPrefix + boolType + arrayPostfix + fieldDelimiter + case "object": + ret += k + fieldSeparator + arrayPrefix + objectOpen + recurse(v.Value.Items.Value.Properties, level+1) + strings.Repeat(" ", level) + objectClose + arrayPostfix + fieldDelimiter + } } case "string": - ret += k + "?: " + "string;" + ret += k + fieldSeparator + stringType + fieldDelimiter case "number": - ret += k + "?: " + "number;" + typ := numberType + switch v.Value.Format { + case "int32": + typ = int32Type + case "int64": + typ = int64Type + case "float": + typ = floatType + case "double": + typ = doubleType + } + ret += k + fieldSeparator + typ + fieldDelimiter case "boolean": - ret += k + "?: " + "boolean;" + ret += k + fieldSeparator + boolType + fieldDelimiter + } + // go specific hack for lowercase son + if language == "go" { + ret += " " + "`json:\"" + strcase.LowerCamelCase(k) + "\"`" } if i < len(props) { @@ -224,7 +728,11 @@ func schemaToTs(title string, spec *openapi3.SchemaRef) string { } return ret } - return "export interface " + title + " {\n" + recurse(spec.Value.Properties, 1) + "}" + return recurse(spec.Value.Properties, 1) +} + +func schemaToMethods(title string, spec *openapi3.RequestBodyRef) string { + return "" } // CopyFile copies a file from src to dst. If src and dst files exist, and are diff --git a/clients/ts/.gitignore b/cmd/clients/ts/.gitignore similarity index 100% rename from clients/ts/.gitignore rename to cmd/clients/ts/.gitignore diff --git a/clients/ts/.npmrc b/cmd/clients/ts/.npmrc similarity index 100% rename from clients/ts/.npmrc rename to cmd/clients/ts/.npmrc diff --git a/cmd/clients/ts/package-lock.json b/cmd/clients/ts/package-lock.json new file mode 100644 index 0000000..2f90a3c --- /dev/null +++ b/cmd/clients/ts/package-lock.json @@ -0,0 +1,566 @@ +{ + "name": "@micro/services", + "version": "1.0.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "@micro/services", + "version": "1.0.1", + "license": "ISC", + "dependencies": { + "@m3o/m3o-node": "^0.0.24" + }, + "devDependencies": { + "typescript": "^3.5.1" + } + }, + "node_modules/@m3o/m3o-node": { + "version": "0.0.24", + "resolved": "https://registry.npmjs.org/@m3o/m3o-node/-/m3o-node-0.0.24.tgz", + "integrity": "sha512-W6VqmZUTFodwBUai5uQ9nO4ylIztUXKYPFfZg2qqTv1lHkOYQ0XiJgFVn+SEOlp4GU/JI9OzCt4k1Ui5XaXGdw==", + "dependencies": { + "@types/ws": "^7.2.2", + "axios": "^0.21.1", + "body-parser": "^1.19.0", + "dotenv": "^10.0.0", + "jsonfile": "^6.1.0", + "ws": "^7.2.3" + } + }, + "node_modules/@types/node": { + "version": "16.7.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.7.10.tgz", + "integrity": "sha512-S63Dlv4zIPb8x6MMTgDq5WWRJQe56iBEY0O3SOFA9JrRienkOVDXSXBjjJw6HTNQYSE2JI6GMCR6LVbIMHJVvA==" + }, + "node_modules/@types/ws": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "dependencies": { + "follow-redirects": "^1.10.0" + } + }, + "node_modules/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dependencies": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "engines": { + "node": ">=10" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "node_modules/follow-redirects": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.3.tgz", + "integrity": "sha512-3MkHxknWMUtb23apkgz/83fDoe+y+qr0TdgacGIA7bew+QLBo3vdgEN2xEsuXNivpFy4CyDhBBZnNZOtalmenw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/graceful-fs": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", + "optional": true + }, + "node_modules/http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-db": { + "version": "1.49.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz", + "integrity": "sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.32", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.32.tgz", + "integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==", + "dependencies": { + "mime-db": "1.49.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dependencies": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", + "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ws": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.4.tgz", + "integrity": "sha512-zP9z6GXm6zC27YtspwH99T3qTG7bBFv2VIkeHstMLrLlDJuzA7tQ5ls3OJ1hOGGCzTQPniNJoHXIAOS0Jljohg==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + }, + "dependencies": { + "@m3o/m3o-node": { + "version": "0.0.24", + "resolved": "https://registry.npmjs.org/@m3o/m3o-node/-/m3o-node-0.0.24.tgz", + "integrity": "sha512-W6VqmZUTFodwBUai5uQ9nO4ylIztUXKYPFfZg2qqTv1lHkOYQ0XiJgFVn+SEOlp4GU/JI9OzCt4k1Ui5XaXGdw==", + "requires": { + "@types/ws": "^7.2.2", + "axios": "^0.21.1", + "body-parser": "^1.19.0", + "dotenv": "^10.0.0", + "jsonfile": "^6.1.0", + "ws": "^7.2.3" + } + }, + "@types/node": { + "version": "16.7.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.7.10.tgz", + "integrity": "sha512-S63Dlv4zIPb8x6MMTgDq5WWRJQe56iBEY0O3SOFA9JrRienkOVDXSXBjjJw6HTNQYSE2JI6GMCR6LVbIMHJVvA==" + }, + "@types/ws": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "requires": { + "@types/node": "*" + } + }, + "axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "requires": { + "follow-redirects": "^1.10.0" + } + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + } + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "follow-redirects": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.3.tgz", + "integrity": "sha512-3MkHxknWMUtb23apkgz/83fDoe+y+qr0TdgacGIA7bew+QLBo3vdgEN2xEsuXNivpFy4CyDhBBZnNZOtalmenw==" + }, + "graceful-fs": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", + "optional": true + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "mime-db": { + "version": "1.49.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz", + "integrity": "sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==" + }, + "mime-types": { + "version": "2.1.32", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.32.tgz", + "integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==", + "requires": { + "mime-db": "1.49.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typescript": { + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", + "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", + "dev": true + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "ws": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.4.tgz", + "integrity": "sha512-zP9z6GXm6zC27YtspwH99T3qTG7bBFv2VIkeHstMLrLlDJuzA7tQ5ls3OJ1hOGGCzTQPniNJoHXIAOS0Jljohg==", + "requires": {} + } + } +} diff --git a/cmd/clients/ts/package.json b/cmd/clients/ts/package.json new file mode 100644 index 0000000..b65bfc6 --- /dev/null +++ b/cmd/clients/ts/package.json @@ -0,0 +1,26 @@ +{ + "name": "@micro/services", + "version": "1.0.1", + "description": "", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "type": "module", + "repository": { + "type": "git", + "url": "https://github.com/micro/services" + }, + "author": "", + "license": "ISC", + "scripts": { + "build": "tsc", + "prepare": "npm run build", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "devDependencies": { + "typescript": "^3.5.1" + }, + "dependencies": { + "@m3o/m3o-node": "^0.0.24" + }, + "exports": {} +} diff --git a/cmd/clients/ts/tsconfig.json b/cmd/clients/ts/tsconfig.json new file mode 100644 index 0000000..d64b6c4 --- /dev/null +++ b/cmd/clients/ts/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "module": "es6", + "target": "es5", + "declaration": true, + "lib": ["es2015", "dom"], + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "outDir": "./dist", + "strict": true, + "moduleResolution": "node", + "esModuleInterop": true + }, + "include": ["index.ts", "./*"], + "exclude": ["src/**/*.spec.*", "./dist", "./node_modules"] +} \ No newline at end of file diff --git a/cmd/clients/ts_template.go b/cmd/clients/ts_template.go new file mode 100644 index 0000000..763f572 --- /dev/null +++ b/cmd/clients/ts_template.go @@ -0,0 +1,46 @@ +package main + +const tsIndexTemplate = `{{ range $service := .services }}import * as {{ $service.Name }} from './{{ $service.Name }}'; +{{ end }} + +export class Client { + constructor(token: string) { + {{ range $service := .services }} + this.{{ $service.Name}}Service = new {{ $service.Name }}.{{ title $service.Name}}Service(token){{end}} + } + +{{ range $service := .services }} + {{ $service.Name}}Service: {{ $service.Name }}.{{ title $service.Name}}Service;{{end}} +} +` + +const tsServiceTemplate = `import * as m3o from '@m3o/m3o-node'; + +{{ $service := .service }} +export class {{ title $service.Name }}Service{ + private client: m3o.Client; + + constructor(token: string) { + this.client = new m3o.Client({token: token}) + } + {{ range $key, $req := $service.Spec.Components.RequestBodies }}{{ $endpointName := requestTypeToEndpointName $key}}{{ if endpointComment $endpointName $service.Spec.Components.Schemas }}{{ endpointComment $endpointName $service.Spec.Components.Schemas }}{{ end }}{{ untitle $endpointName}}(request: {{ requestType $key }}): Promise<{{ requestTypeToResponseType $key }}> { + return this.client.call("{{ $service.Name }}", "{{ requestTypeToEndpointPath $key}}", request) as Promise<{{ requestTypeToResponseType $key }}>; + }; + {{ end }} +} + +{{ range $typeName, $schema := $service.Spec.Components.Schemas }} +export interface {{ title $typeName }}{{ "{" }} +{{ recursiveTypeDefinition "typescript" $service.Name $typeName $service.Spec.Components.Schemas }}{{ "}" }} +{{end}} +` + +const tsExampleTemplate = `{{ $service := .service }}import * as {{ $service.Name }} from '@m3o/services/{{ $service.Name }}'; + +{{ if endpointComment .endpoint $service.Spec.Components.Schemas }}{{ endpointComment .endpoint $service.Spec.Components.Schemas }}{{ end }}async function {{ .funcName }}() { + let {{ $service.Name }}Service = new {{ $service.Name }}.{{ title $service.Name }}Service(process.env.MICRO_API_TOKEN) + let rsp = await {{ $service.Name }}Service.{{ .endpoint }}({{ tsExampleRequest $service.Name .endpoint $service.Spec.Components.Schemas .example.Request }}) + console.log(rsp) +} + +await {{ .funcName }}()` diff --git a/geocoding/proto/geocoding.pb.go b/geocoding/proto/geocoding.pb.go index 6ba7182..6166f8e 100644 --- a/geocoding/proto/geocoding.pb.go +++ b/geocoding/proto/geocoding.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.26.0 -// protoc v3.15.6 +// protoc v3.6.1 // source: proto/geocoding.proto package geocoding diff --git a/go.mod b/go.mod index 8a328e0..c741b52 100644 --- a/go.mod +++ b/go.mod @@ -7,11 +7,15 @@ require ( github.com/PuerkitoBio/goquery v1.6.1 github.com/SlyMarbo/rss v1.0.1 github.com/asim/mq v0.1.0 + github.com/bitly/go-simplejson v0.5.0 github.com/cdipaolo/goml v0.0.0-20190412180403-e1f51f713598 // indirect github.com/cdipaolo/sentiment v0.0.0-20200617002423-c697f64e7f10 github.com/crufter/lexer v0.0.0-20120907053443-23fe8c7add01 + github.com/crufter/nested v0.0.0-20210903145606-dea42c476b37 + github.com/davecgh/go-spew v1.1.1 github.com/disintegration/imaging v1.6.2 github.com/enescakir/emoji v1.0.0 + github.com/fatih/camelcase v1.0.0 github.com/getkin/kin-openapi v0.26.0 github.com/gojuno/go.osrm v0.1.1-0.20200217151037-435fc3e1d3d4 github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect @@ -26,9 +30,11 @@ require ( github.com/kevinburke/twilio-go v0.0.0-20210327194925-1623146bcf73 github.com/lib/pq v1.9.0 // indirect github.com/m3o/goduckgo v0.0.0-20210630141545-c760fe67b945 + github.com/m3o/m3o-go/client v0.0.0-20210421144725-8bfd7992ada3 github.com/mattheath/base62 v0.0.0-20150408093626-b80cdc656a7a // indirect github.com/mattheath/kala v0.0.0-20171219141654-d6276794bf0e - github.com/micro/micro/v3 v3.4.1-0.20210827085315-cdb3e3adc9b3 + github.com/micro/micro-go v0.0.0-20210908134848-0eb99593b556 + github.com/micro/micro/v3 v3.4.1-0.20210903082606-b49d5b18ae9b github.com/miekg/dns v1.1.31 // indirect github.com/oschwald/geoip2-golang v1.5.0 github.com/patrickmn/go-cache v2.1.0+incompatible diff --git a/go.sum b/go.sum index e9e1b99..66423a0 100644 --- a/go.sum +++ b/go.sum @@ -89,6 +89,10 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/crufter/lexer v0.0.0-20120907053443-23fe8c7add01 h1:3BwOWuIBrZtUqFUnGKHXhyBxF8l1BKX+5N7V5TgDLhU= github.com/crufter/lexer v0.0.0-20120907053443-23fe8c7add01/go.mod h1:UzTRPLzI3RwH4cTSc8nYrXN2dCjwRNGZBzHSc0RE7pE= +github.com/crufter/nested v0.0.0-20130904135214-96da502c9b3f h1:fYRw3ZXxiqe/J3NXorQo07q7CDd9XFdRC0R9JXP3ibs= +github.com/crufter/nested v0.0.0-20130904135214-96da502c9b3f/go.mod h1:YNI79HwflbM2lYQFtiOl1DGTKdTGSNVAmkNdy68DTgE= +github.com/crufter/nested v0.0.0-20210903145606-dea42c476b37 h1:iagXID3gtvkobP+RM3cmYjQjGE74d2EUHzvWgPPXxog= +github.com/crufter/nested v0.0.0-20210903145606-dea42c476b37/go.mod h1:YNI79HwflbM2lYQFtiOl1DGTKdTGSNVAmkNdy68DTgE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -115,6 +119,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/evanphx/json-patch/v5 v5.0.0 h1:dKTrUeykyQwKb/kx7Z+4ukDs6l+4L41HqG1XHnhX7WE= github.com/evanphx/json-patch/v5 v5.0.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/exoscale/egoscale v0.18.1/go.mod h1:Z7OOdzzTOz1Q1PjQXumlz9Wn/CddH0zSYdCF3rnBKXE= +github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= +github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= @@ -146,6 +152,8 @@ github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= github.com/gojuno/go.osrm v0.1.1-0.20200217151037-435fc3e1d3d4 h1:ZhyiVDRMAdbMPFmzJMAK3GVbUG5abPRUMC9jySXcfCU= github.com/gojuno/go.osrm v0.1.1-0.20200217151037-435fc3e1d3d4/go.mod h1:XPCHB/Ir2/vHnqhKlfUxIiUGHFtTzgrRxD89JdkJhrs= +github.com/golang-jwt/jwt v0.0.0-20210529014511-0f726ea0e725 h1:fMKUGzqjXWLpddTodG8KO9moexa9bZMFQSkJRDefXpI= +github.com/golang-jwt/jwt v0.0.0-20210529014511-0f726ea0e725/go.mod h1:aHjnehRD4y8BHKf+z8wAPIRTd/3cm+FrvC6kQIDhV3o= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= @@ -206,6 +214,7 @@ github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= @@ -332,6 +341,8 @@ github.com/linode/linodego v0.10.0/go.mod h1:cziNP7pbvE3mXIPneHj0oRY8L1WtGEIKlZ8 github.com/liquidweb/liquidweb-go v1.6.0/go.mod h1:UDcVnAMDkZxpw4Y7NOHkqoeiGacVLEIG/i5J9cyixzQ= github.com/m3o/goduckgo v0.0.0-20210630141545-c760fe67b945 h1:jcOqgh+pYNSaPoPOgDaaU5t9j45JzHG3wOBLXUMBfQ0= github.com/m3o/goduckgo v0.0.0-20210630141545-c760fe67b945/go.mod h1:wQOw7PY6509VQbepPrclbyXfbQ5lpOtIoHdBKbB+OGc= +github.com/m3o/m3o-go/client v0.0.0-20210421144725-8bfd7992ada3 h1:RVt7rqWl4al36BH9OY9k7IXnnooOP0Feanu1bed6X2s= +github.com/m3o/m3o-go/client v0.0.0-20210421144725-8bfd7992ada3/go.mod h1:vmeaYrKYpgVNhny/l7iH8mXS88S7ijUiYni3gZUrCq0= github.com/mattheath/base62 v0.0.0-20150408093626-b80cdc656a7a h1:rnrxZue85aKdMU4nJ50GgKA31lCaVbft+7Xl8OXj55U= github.com/mattheath/base62 v0.0.0-20150408093626-b80cdc656a7a/go.mod h1:hJJYoBMTZIONmUEpX3+9v2057zuRM0n3n77U4Ob4wE4= github.com/mattheath/kala v0.0.0-20171219141654-d6276794bf0e h1:cj+w63ez19o7y7vunA8Q3rUIWwKEOUx7foqjnr4qbtI= @@ -358,8 +369,16 @@ github.com/mattn/go-sqlite3 v1.14.5 h1:1IdxlwTNazvbKJQSxoJ5/9ECbEeaTTyeU7sEAZ5KK github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/micro/micro-go v0.0.0-20210902105641-aac45b1703c7 h1:JOBB+usyhMjbMo1RwC6KGKJyiLvQE0GaL0eeUWsWmzk= +github.com/micro/micro-go v0.0.0-20210902105641-aac45b1703c7/go.mod h1:Jlbljy5hUymPXkB5M1hCPxtY6l64dkQRA/EvazcQoQM= +github.com/micro/micro-go v0.0.0-20210907082922-e63f7ceaaa9f h1:gqygP7IJi39jTBmU0MSTyhilIllsGu5B36mHfLD1Kew= +github.com/micro/micro-go v0.0.0-20210907082922-e63f7ceaaa9f/go.mod h1:Jlbljy5hUymPXkB5M1hCPxtY6l64dkQRA/EvazcQoQM= +github.com/micro/micro-go v0.0.0-20210908134848-0eb99593b556 h1:ROqWltEPo1cLl4h8hzZJ5PKTkVVFS2Z+BxiP1gyIkMk= +github.com/micro/micro-go v0.0.0-20210908134848-0eb99593b556/go.mod h1:Jlbljy5hUymPXkB5M1hCPxtY6l64dkQRA/EvazcQoQM= github.com/micro/micro/v3 v3.4.1-0.20210827085315-cdb3e3adc9b3 h1:oS7027tNGjfpLeLOIFTHF06xXGJ2HjHXfk+8VaU19AY= github.com/micro/micro/v3 v3.4.1-0.20210827085315-cdb3e3adc9b3/go.mod h1:cgV1bNfRLOE4vytanTo+N/QvjsdTRJRKTVqKq6XH7AA= +github.com/micro/micro/v3 v3.4.1-0.20210903082606-b49d5b18ae9b h1:fooHh4WUi8BtrHZQ5tJmt1CQBGeyRhSUb08/ASDTKp0= +github.com/micro/micro/v3 v3.4.1-0.20210903082606-b49d5b18ae9b/go.mod h1:bkhxUsib0oX41JNr5qlxTt2LYzzGXJWet4d/Vwvb6Wg= github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.31 h1:sJFOl9BgwbYAWOGEwr61FU28pqsBNdpRBnhGXtO06Oo= diff --git a/helloworld/handler/helloworld.go b/helloworld/handler/helloworld.go index 753abd6..7a28dfa 100644 --- a/helloworld/handler/helloworld.go +++ b/helloworld/handler/helloworld.go @@ -10,7 +10,7 @@ import ( type Helloworld struct{} // Call is a single request handler called via client.Call or the generated client code -func (e *Helloworld) Call(ctx context.Context, req *helloworld.Request, rsp *helloworld.Response) error { +func (e *Helloworld) Call(ctx context.Context, req *helloworld.CallRequest, rsp *helloworld.CallResponse) error { logger.Info("Received Helloworld.Call request") rsp.Message = "Hello " + req.Name return nil diff --git a/helloworld/proto/helloworld.pb.go b/helloworld/proto/helloworld.pb.go index 9c93743..ce0d628 100644 --- a/helloworld/proto/helloworld.pb.go +++ b/helloworld/proto/helloworld.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.26.0 -// protoc v3.15.6 +// protoc v3.6.1 // source: proto/helloworld.proto package helloworld @@ -21,7 +21,7 @@ const ( ) // Call returns a personalised "Hello $name" response -type Request struct { +type CallRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -29,8 +29,8 @@ type Request struct { Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` } -func (x *Request) Reset() { - *x = Request{} +func (x *CallRequest) Reset() { + *x = CallRequest{} if protoimpl.UnsafeEnabled { mi := &file_proto_helloworld_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -38,13 +38,13 @@ func (x *Request) Reset() { } } -func (x *Request) String() string { +func (x *CallRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*Request) ProtoMessage() {} +func (*CallRequest) ProtoMessage() {} -func (x *Request) ProtoReflect() protoreflect.Message { +func (x *CallRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_helloworld_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -56,19 +56,19 @@ func (x *Request) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use Request.ProtoReflect.Descriptor instead. -func (*Request) Descriptor() ([]byte, []int) { +// Deprecated: Use CallRequest.ProtoReflect.Descriptor instead. +func (*CallRequest) Descriptor() ([]byte, []int) { return file_proto_helloworld_proto_rawDescGZIP(), []int{0} } -func (x *Request) GetName() string { +func (x *CallRequest) GetName() string { if x != nil { return x.Name } return "" } -type Response struct { +type CallResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -76,8 +76,8 @@ type Response struct { Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` } -func (x *Response) Reset() { - *x = Response{} +func (x *CallResponse) Reset() { + *x = CallResponse{} if protoimpl.UnsafeEnabled { mi := &file_proto_helloworld_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -85,13 +85,13 @@ func (x *Response) Reset() { } } -func (x *Response) String() string { +func (x *CallResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*Response) ProtoMessage() {} +func (*CallResponse) ProtoMessage() {} -func (x *Response) ProtoReflect() protoreflect.Message { +func (x *CallResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_helloworld_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -103,12 +103,12 @@ func (x *Response) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use Response.ProtoReflect.Descriptor instead. -func (*Response) Descriptor() ([]byte, []int) { +// Deprecated: Use CallResponse.ProtoReflect.Descriptor instead. +func (*CallResponse) Descriptor() ([]byte, []int) { return file_proto_helloworld_proto_rawDescGZIP(), []int{1} } -func (x *Response) GetMessage() string { +func (x *CallResponse) GetMessage() string { if x != nil { return x.Message } @@ -223,21 +223,22 @@ var File_proto_helloworld_proto protoreflect.FileDescriptor var file_proto_helloworld_proto_rawDesc = []byte{ 0x0a, 0x16, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, - 0x6f, 0x72, 0x6c, 0x64, 0x22, 0x1d, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x22, 0x24, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x3f, 0x0a, 0x0d, 0x53, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, - 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x22, 0x2a, 0x0a, 0x0e, 0x53, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x86, 0x01, 0x0a, 0x0a, 0x48, 0x65, 0x6c, 0x6c, 0x6f, - 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x12, 0x33, 0x0a, 0x04, 0x43, 0x61, 0x6c, 0x6c, 0x12, 0x13, 0x2e, - 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, + 0x6f, 0x72, 0x6c, 0x64, 0x22, 0x21, 0x0a, 0x0b, 0x43, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x28, 0x0a, 0x0c, 0x43, 0x61, 0x6c, 0x6c, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x22, 0x3f, 0x0a, 0x0d, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x73, 0x22, 0x2a, 0x0a, 0x0e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x8e, + 0x01, 0x0a, 0x0a, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x12, 0x3b, 0x0a, + 0x04, 0x43, 0x61, 0x6c, 0x6c, 0x12, 0x17, 0x2e, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, + 0x6c, 0x64, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, + 0x2e, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x06, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x19, 0x2e, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, @@ -261,15 +262,15 @@ func file_proto_helloworld_proto_rawDescGZIP() []byte { var file_proto_helloworld_proto_msgTypes = make([]protoimpl.MessageInfo, 4) var file_proto_helloworld_proto_goTypes = []interface{}{ - (*Request)(nil), // 0: helloworld.Request - (*Response)(nil), // 1: helloworld.Response + (*CallRequest)(nil), // 0: helloworld.CallRequest + (*CallResponse)(nil), // 1: helloworld.CallResponse (*StreamRequest)(nil), // 2: helloworld.StreamRequest (*StreamResponse)(nil), // 3: helloworld.StreamResponse } var file_proto_helloworld_proto_depIdxs = []int32{ - 0, // 0: helloworld.Helloworld.Call:input_type -> helloworld.Request + 0, // 0: helloworld.Helloworld.Call:input_type -> helloworld.CallRequest 2, // 1: helloworld.Helloworld.Stream:input_type -> helloworld.StreamRequest - 1, // 2: helloworld.Helloworld.Call:output_type -> helloworld.Response + 1, // 2: helloworld.Helloworld.Call:output_type -> helloworld.CallResponse 3, // 3: helloworld.Helloworld.Stream:output_type -> helloworld.StreamResponse 2, // [2:4] is the sub-list for method output_type 0, // [0:2] is the sub-list for method input_type @@ -285,7 +286,7 @@ func file_proto_helloworld_proto_init() { } if !protoimpl.UnsafeEnabled { file_proto_helloworld_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Request); i { + switch v := v.(*CallRequest); i { case 0: return &v.state case 1: @@ -297,7 +298,7 @@ func file_proto_helloworld_proto_init() { } } file_proto_helloworld_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Response); i { + switch v := v.(*CallResponse); i { case 0: return &v.state case 1: diff --git a/helloworld/proto/helloworld.pb.micro.go b/helloworld/proto/helloworld.pb.micro.go index 6e37811..cd2b507 100644 --- a/helloworld/proto/helloworld.pb.micro.go +++ b/helloworld/proto/helloworld.pb.micro.go @@ -42,7 +42,7 @@ func NewHelloworldEndpoints() []*api.Endpoint { // Client API for Helloworld service type HelloworldService interface { - Call(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) + Call(ctx context.Context, in *CallRequest, opts ...client.CallOption) (*CallResponse, error) Stream(ctx context.Context, in *StreamRequest, opts ...client.CallOption) (Helloworld_StreamService, error) } @@ -58,9 +58,9 @@ func NewHelloworldService(name string, c client.Client) HelloworldService { } } -func (c *helloworldService) Call(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) { +func (c *helloworldService) Call(ctx context.Context, in *CallRequest, opts ...client.CallOption) (*CallResponse, error) { req := c.c.NewRequest(c.name, "Helloworld.Call", in) - out := new(Response) + out := new(CallResponse) err := c.c.Call(ctx, req, out, opts...) if err != nil { return nil, err @@ -120,13 +120,13 @@ func (x *helloworldServiceStream) Recv() (*StreamResponse, error) { // Server API for Helloworld service type HelloworldHandler interface { - Call(context.Context, *Request, *Response) error + Call(context.Context, *CallRequest, *CallResponse) error Stream(context.Context, *StreamRequest, Helloworld_StreamStream) error } func RegisterHelloworldHandler(s server.Server, hdlr HelloworldHandler, opts ...server.HandlerOption) error { type helloworld interface { - Call(ctx context.Context, in *Request, out *Response) error + Call(ctx context.Context, in *CallRequest, out *CallResponse) error Stream(ctx context.Context, stream server.Stream) error } type Helloworld struct { @@ -140,7 +140,7 @@ type helloworldHandler struct { HelloworldHandler } -func (h *helloworldHandler) Call(ctx context.Context, in *Request, out *Response) error { +func (h *helloworldHandler) Call(ctx context.Context, in *CallRequest, out *CallResponse) error { return h.HelloworldHandler.Call(ctx, in, out) } diff --git a/helloworld/proto/helloworld.proto b/helloworld/proto/helloworld.proto index bfa84b4..b3900c2 100644 --- a/helloworld/proto/helloworld.proto +++ b/helloworld/proto/helloworld.proto @@ -5,16 +5,16 @@ package helloworld; option go_package = "./proto;helloworld"; service Helloworld { - rpc Call(Request) returns (Response) {}; + rpc Call(CallRequest) returns (CallResponse) {}; rpc Stream(StreamRequest) returns (stream StreamResponse) {}; } // Call returns a personalised "Hello $name" response -message Request { +message CallRequest { string name = 1; } -message Response { +message CallResponse { string message = 1; } diff --git a/pkg/api/api.go b/pkg/api/api.go index acf8e18..d79c7c0 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -2,10 +2,10 @@ package api import ( - "fmt" - "net/http" "encoding/json" + "fmt" "io/ioutil" + "net/http" ) func Get(url string, rsp interface{}) error { diff --git a/sentiment/handler/sentiment.go b/sentiment/handler/sentiment.go index fbb2e9c..9e37a4d 100644 --- a/sentiment/handler/sentiment.go +++ b/sentiment/handler/sentiment.go @@ -10,7 +10,7 @@ import ( type Sentiment struct{} -func (e *Sentiment) Analyze(ctx context.Context, req *pb.Request, rsp *pb.Response) error { +func (e *Sentiment) Analyze(ctx context.Context, req *pb.AnalyzeRequest, rsp *pb.AnalyzeResponse) error { if len(req.Text) == 0 { return errors.BadRequest("sentiment.analyze", "text is blank") } diff --git a/sentiment/proto/sentiment.pb.go b/sentiment/proto/sentiment.pb.go index ad6dc5b..8f21cda 100644 --- a/sentiment/proto/sentiment.pb.go +++ b/sentiment/proto/sentiment.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.26.0 -// protoc v3.15.6 +// protoc v3.6.1 // source: proto/sentiment.proto package sentiment @@ -21,7 +21,7 @@ const ( ) // Analyze and score a piece of text -type Request struct { +type AnalyzeRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -32,8 +32,8 @@ type Request struct { Lang string `protobuf:"bytes,2,opt,name=lang,proto3" json:"lang,omitempty"` } -func (x *Request) Reset() { - *x = Request{} +func (x *AnalyzeRequest) Reset() { + *x = AnalyzeRequest{} if protoimpl.UnsafeEnabled { mi := &file_proto_sentiment_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -41,13 +41,13 @@ func (x *Request) Reset() { } } -func (x *Request) String() string { +func (x *AnalyzeRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*Request) ProtoMessage() {} +func (*AnalyzeRequest) ProtoMessage() {} -func (x *Request) ProtoReflect() protoreflect.Message { +func (x *AnalyzeRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_sentiment_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -59,36 +59,36 @@ func (x *Request) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use Request.ProtoReflect.Descriptor instead. -func (*Request) Descriptor() ([]byte, []int) { +// Deprecated: Use AnalyzeRequest.ProtoReflect.Descriptor instead. +func (*AnalyzeRequest) Descriptor() ([]byte, []int) { return file_proto_sentiment_proto_rawDescGZIP(), []int{0} } -func (x *Request) GetText() string { +func (x *AnalyzeRequest) GetText() string { if x != nil { return x.Text } return "" } -func (x *Request) GetLang() string { +func (x *AnalyzeRequest) GetLang() string { if x != nil { return x.Lang } return "" } -type Response struct { +type AnalyzeResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // The score of the text + // The score of the text {positive is 1, negative is 0} Score float64 `protobuf:"fixed64,1,opt,name=score,proto3" json:"score,omitempty"` } -func (x *Response) Reset() { - *x = Response{} +func (x *AnalyzeResponse) Reset() { + *x = AnalyzeResponse{} if protoimpl.UnsafeEnabled { mi := &file_proto_sentiment_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -96,13 +96,13 @@ func (x *Response) Reset() { } } -func (x *Response) String() string { +func (x *AnalyzeResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*Response) ProtoMessage() {} +func (*AnalyzeResponse) ProtoMessage() {} -func (x *Response) ProtoReflect() protoreflect.Message { +func (x *AnalyzeResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_sentiment_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -114,12 +114,12 @@ func (x *Response) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use Response.ProtoReflect.Descriptor instead. -func (*Response) Descriptor() ([]byte, []int) { +// Deprecated: Use AnalyzeResponse.ProtoReflect.Descriptor instead. +func (*AnalyzeResponse) Descriptor() ([]byte, []int) { return file_proto_sentiment_proto_rawDescGZIP(), []int{1} } -func (x *Response) GetScore() float64 { +func (x *AnalyzeResponse) GetScore() float64 { if x != nil { return x.Score } @@ -131,18 +131,20 @@ var File_proto_sentiment_proto protoreflect.FileDescriptor var file_proto_sentiment_proto_rawDesc = []byte{ 0x0a, 0x15, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x65, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x73, 0x65, 0x6e, 0x74, 0x69, 0x6d, 0x65, - 0x6e, 0x74, 0x22, 0x31, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, - 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, - 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x22, 0x20, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, - 0x52, 0x05, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x32, 0x41, 0x0a, 0x09, 0x53, 0x65, 0x6e, 0x74, 0x69, - 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x34, 0x0a, 0x07, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x12, - 0x12, 0x2e, 0x73, 0x65, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x73, 0x65, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x2e, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x13, 0x5a, 0x11, 0x2e, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3b, 0x73, 0x65, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x74, 0x22, 0x38, 0x0a, 0x0e, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x61, 0x6e, 0x67, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x22, 0x27, 0x0a, 0x0f, + 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x14, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, + 0x73, 0x63, 0x6f, 0x72, 0x65, 0x32, 0x4f, 0x0a, 0x09, 0x53, 0x65, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x6e, 0x74, 0x12, 0x42, 0x0a, 0x07, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x12, 0x19, 0x2e, + 0x73, 0x65, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x7a, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x73, 0x65, 0x6e, 0x74, 0x69, + 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x13, 0x5a, 0x11, 0x2e, 0x2f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x3b, 0x73, 0x65, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( @@ -159,12 +161,12 @@ func file_proto_sentiment_proto_rawDescGZIP() []byte { var file_proto_sentiment_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_proto_sentiment_proto_goTypes = []interface{}{ - (*Request)(nil), // 0: sentiment.Request - (*Response)(nil), // 1: sentiment.Response + (*AnalyzeRequest)(nil), // 0: sentiment.AnalyzeRequest + (*AnalyzeResponse)(nil), // 1: sentiment.AnalyzeResponse } var file_proto_sentiment_proto_depIdxs = []int32{ - 0, // 0: sentiment.Sentiment.Analyze:input_type -> sentiment.Request - 1, // 1: sentiment.Sentiment.Analyze:output_type -> sentiment.Response + 0, // 0: sentiment.Sentiment.Analyze:input_type -> sentiment.AnalyzeRequest + 1, // 1: sentiment.Sentiment.Analyze:output_type -> sentiment.AnalyzeResponse 1, // [1:2] is the sub-list for method output_type 0, // [0:1] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name @@ -179,7 +181,7 @@ func file_proto_sentiment_proto_init() { } if !protoimpl.UnsafeEnabled { file_proto_sentiment_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Request); i { + switch v := v.(*AnalyzeRequest); i { case 0: return &v.state case 1: @@ -191,7 +193,7 @@ func file_proto_sentiment_proto_init() { } } file_proto_sentiment_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Response); i { + switch v := v.(*AnalyzeResponse); i { case 0: return &v.state case 1: diff --git a/sentiment/proto/sentiment.pb.micro.go b/sentiment/proto/sentiment.pb.micro.go index 2e256a9..35d068d 100644 --- a/sentiment/proto/sentiment.pb.micro.go +++ b/sentiment/proto/sentiment.pb.micro.go @@ -42,7 +42,7 @@ func NewSentimentEndpoints() []*api.Endpoint { // Client API for Sentiment service type SentimentService interface { - Analyze(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) + Analyze(ctx context.Context, in *AnalyzeRequest, opts ...client.CallOption) (*AnalyzeResponse, error) } type sentimentService struct { @@ -57,9 +57,9 @@ func NewSentimentService(name string, c client.Client) SentimentService { } } -func (c *sentimentService) Analyze(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) { +func (c *sentimentService) Analyze(ctx context.Context, in *AnalyzeRequest, opts ...client.CallOption) (*AnalyzeResponse, error) { req := c.c.NewRequest(c.name, "Sentiment.Analyze", in) - out := new(Response) + out := new(AnalyzeResponse) err := c.c.Call(ctx, req, out, opts...) if err != nil { return nil, err @@ -70,12 +70,12 @@ func (c *sentimentService) Analyze(ctx context.Context, in *Request, opts ...cli // Server API for Sentiment service type SentimentHandler interface { - Analyze(context.Context, *Request, *Response) error + Analyze(context.Context, *AnalyzeRequest, *AnalyzeResponse) error } func RegisterSentimentHandler(s server.Server, hdlr SentimentHandler, opts ...server.HandlerOption) error { type sentiment interface { - Analyze(ctx context.Context, in *Request, out *Response) error + Analyze(ctx context.Context, in *AnalyzeRequest, out *AnalyzeResponse) error } type Sentiment struct { sentiment @@ -88,6 +88,6 @@ type sentimentHandler struct { SentimentHandler } -func (h *sentimentHandler) Analyze(ctx context.Context, in *Request, out *Response) error { +func (h *sentimentHandler) Analyze(ctx context.Context, in *AnalyzeRequest, out *AnalyzeResponse) error { return h.SentimentHandler.Analyze(ctx, in, out) } diff --git a/sentiment/proto/sentiment.proto b/sentiment/proto/sentiment.proto index e6bfcea..8dea1be 100644 --- a/sentiment/proto/sentiment.proto +++ b/sentiment/proto/sentiment.proto @@ -5,18 +5,18 @@ package sentiment; option go_package = "./proto;sentiment"; service Sentiment { - rpc Analyze(Request) returns (Response) {}; + rpc Analyze(AnalyzeRequest) returns (AnalyzeResponse) {}; } // Analyze and score a piece of text -message Request { +message AnalyzeRequest { // The text to analyze string text = 1; // The language. Defaults to english. string lang = 2; } -message Response { +message AnalyzeResponse { // The score of the text {positive is 1, negative is 0} double score = 1; }