Skip to content

Commit ab246d7

Browse files
committed
Generate root client that uses implementation of subrouter clients
1 parent 7ac4f7f commit ab246d7

File tree

8 files changed

+218
-40
lines changed

8 files changed

+218
-40
lines changed

clients/go/gengo.go

Lines changed: 147 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import (
1515
)
1616

1717
// Generate generates a client
18-
func Generate(packageName, basePath, outputPath string, s spec.Swagger, isSubrouter bool) error {
19-
if err := generateClient(packageName, basePath, outputPath, s, isSubrouter); err != nil {
18+
func Generate(packageName, basePath, outputPath string, s spec.Swagger) error {
19+
if err := generateClient(packageName, basePath, outputPath, s); err != nil {
2020
return err
2121
}
2222
return generateInterface(packageName, basePath, outputPath, &s, s.Info.InfoProps.Title, s.Paths)
@@ -31,29 +31,34 @@ type clientCodeTemplate struct {
3131
Operations []string
3232
Version string
3333
VersionSuffix string
34+
Subrouters []swagger.Subrouter
3435
}
3536

3637
var clientCodeTemplateStr = `
3738
package client
3839
3940
import (
40-
"context"
41-
"strings"
42-
"bytes"
43-
"net/http"
44-
"strconv"
45-
"encoding/json"
46-
"strconv"
47-
"time"
48-
"fmt"
49-
"io/ioutil"
50-
"crypto/md5"
51-
52-
"{{.ModuleName}}{{.OutputPath}}/models{{.VersionSuffix}}"
53-
54-
discovery "github.com/Clever/discovery-go"
55-
wcl "github.com/Clever/wag/logging/wagclientlogger"
56-
41+
"context"
42+
"strings"
43+
"bytes"
44+
"net/http"
45+
"strconv"
46+
"encoding/json"
47+
"strconv"
48+
"time"
49+
"fmt"
50+
"io/ioutil"
51+
"crypto/md5"
52+
53+
"{{.ModuleName}}{{.OutputPath}}/models{{.VersionSuffix}}"
54+
{{- if .Subrouters }}
55+
{{ range $i, $val := .Subrouters -}}
56+
{{$val.Key}}client "{{$.ModuleName}}/routers/{{$val.Key}}/gen-go/client{{$.VersionSuffix}}"
57+
{{$val.Key}}models "{{$.ModuleName}}/routers/{{$val.Key}}/gen-go/models{{$.VersionSuffix}}"
58+
{{ end }}
59+
{{ end }}
60+
discovery "github.com/Clever/discovery-go"
61+
wcl "github.com/Clever/wag/logging/wagclientlogger"
5762
)
5863
5964
var _ = json.Marshal
@@ -76,6 +81,13 @@ type WagClient struct {
7681
retryDoer *retryDoer
7782
defaultTimeout time.Duration
7883
logger wcl.WagClientLogger
84+
{{- if .Subrouters }}
85+
86+
// Subrouters
87+
{{ range $i, $val := .Subrouters -}}
88+
{{camelcase $val.Key}}Client {{$val.Key}}client.Client
89+
{{ end }}
90+
{{ end -}}
7991
}
8092
8193
var _ Client = (*WagClient)(nil)
@@ -85,7 +97,6 @@ var _ Client = (*WagClient)(nil)
8597
// provide an instrumented transport using the wag clientconfig module. If no tracing is required, pass nil to use
8698
// the default transport.
8799
func New(basePath string, logger wcl.WagClientLogger, transport *http.RoundTripper) *WagClient {
88-
89100
t := http.DefaultTransport
90101
if transport != nil {
91102
t = *transport
@@ -106,6 +117,9 @@ func New(basePath string, logger wcl.WagClientLogger, transport *http.RoundTripp
106117
retryDoer: &retry,
107118
defaultTimeout: 5 * time.Second,
108119
logger: logger,
120+
{{ range $i, $val := .Subrouters -}}
121+
{{camelcase $val.Key}}Client: {{$val.Key}}client.New(basePath, logger, transport),
122+
{{ end }}
109123
}
110124
return client
111125
}
@@ -151,9 +165,14 @@ func shortHash(s string) string {
151165
}
152166
`
153167

154-
func generateClient(packageName, basePath, outputPath string, s spec.Swagger, isSubrouter bool) error {
168+
func generateClient(packageName, basePath, outputPath string, s spec.Swagger) error {
155169
outputPath = strings.TrimPrefix(outputPath, ".")
156170
moduleName, versionSuffix := utils.ExtractModuleNameAndVersionSuffix(packageName, outputPath)
171+
subrouters, err := swagger.ParseSubrouters(s)
172+
if err != nil {
173+
return err
174+
}
175+
157176
codeTemplate := clientCodeTemplate{
158177
PackageName: packageName,
159178
OutputPath: outputPath,
@@ -162,6 +181,7 @@ func generateClient(packageName, basePath, outputPath string, s spec.Swagger, is
162181
FormattedServiceName: strings.ToUpper(strings.Replace(s.Info.InfoProps.Title, "-", "_", -1)),
163182
Version: s.Info.InfoProps.Version,
164183
VersionSuffix: versionSuffix,
184+
Subrouters: subrouters,
165185
}
166186

167187
for _, path := range swagger.SortedPathItemKeys(s.Paths.Paths) {
@@ -180,6 +200,29 @@ func generateClient(packageName, basePath, outputPath string, s spec.Swagger, is
180200
}
181201
}
182202

203+
for _, router := range subrouters {
204+
routerSpec, err := swagger.LoadSubrouterSpec(router)
205+
if err != nil {
206+
return err
207+
}
208+
209+
for _, path := range swagger.SortedPathItemKeys(routerSpec.Paths.Paths) {
210+
pathItem := routerSpec.Paths.Paths[path]
211+
pathItemOps := swagger.PathItemOperations(pathItem)
212+
for _, method := range swagger.SortedOperationsKeys(pathItemOps) {
213+
op := pathItemOps[method]
214+
if op.Deprecated {
215+
continue
216+
}
217+
code, err := subrouterOperationCode(routerSpec, op, router)
218+
if err != nil {
219+
return err
220+
}
221+
codeTemplate.Operations = append(codeTemplate.Operations, code)
222+
}
223+
}
224+
}
225+
183226
clientCode, err := templates.WriteTemplate(clientCodeTemplateStr, codeTemplate)
184227
if err != nil {
185228
return err
@@ -192,11 +235,20 @@ func generateClient(packageName, basePath, outputPath string, s spec.Swagger, is
192235
return err
193236
}
194237

195-
return CreateModFile("client/go.mod", basePath, codeTemplate)
238+
return CreateModFile("client/go.mod", basePath, codeTemplate, s)
196239
}
197240

198241
// CreateModFile creates a go.mod file for the client module.
199-
func CreateModFile(path string, basePath string, codeTemplate clientCodeTemplate) error {
242+
func CreateModFile(
243+
path, basePath string,
244+
codeTemplate clientCodeTemplate,
245+
s spec.Swagger,
246+
) error {
247+
subrouters, err := swagger.ParseSubrouters(s)
248+
if err != nil {
249+
return err
250+
}
251+
200252
absPath := basePath + "/" + path
201253
f, err := os.Create(absPath)
202254
if err != nil {
@@ -214,8 +266,35 @@ require (
214266
github.com/Clever/wag/logging/wagclientlogger v0.0.0-20221024182247-2bf828ef51be
215267
github.com/donovanhide/eventsource v0.0.0-20171031113327-3ed64d21fb0b
216268
)
269+
217270
//Replace directives will work locally but mess up imports.
218-
replace ` + codeTemplate.ModuleName + codeTemplate.OutputPath + `/models` + codeTemplate.VersionSuffix + ` => ../models `
271+
`
272+
273+
if subrouters != nil {
274+
replaceString := fmt.Sprintf(
275+
`replace (
276+
%s%s/models%s => ../models
277+
`,
278+
codeTemplate.ModuleName,
279+
codeTemplate.OutputPath,
280+
codeTemplate.VersionSuffix,
281+
)
282+
283+
for _, router := range subrouters {
284+
replaceString += fmt.Sprintf(
285+
"\t%s/routers/%s/gen-go/client => ../../routers/%s/gen-go/client\n",
286+
codeTemplate.ModuleName,
287+
router.Key,
288+
router.Key,
289+
)
290+
}
291+
292+
replaceString += ")\n"
293+
modFileString += replaceString
294+
} else {
295+
modFileString += `replace ` + codeTemplate.ModuleName + codeTemplate.OutputPath + `/models` + codeTemplate.VersionSuffix + ` => ../models
296+
`
297+
}
219298

220299
_, err = f.WriteString(modFileString)
221300
if err != nil {
@@ -241,12 +320,36 @@ func IsBinaryParam(param spec.Parameter, definitions map[string]spec.Schema) boo
241320
return definitions[definitionName].Format == "binary"
242321
}
243322

244-
func generateInterface(packageName, basePath, outputPath string, s *spec.Swagger, serviceName string, paths *spec.Paths) error {
323+
func generateInterface(
324+
packageName, basePath, outputPath string,
325+
s *spec.Swagger,
326+
serviceName string,
327+
paths *spec.Paths,
328+
) error {
245329
outputPath = strings.TrimPrefix(outputPath, ".")
246330
g := swagger.Generator{BasePath: basePath}
247-
g.Print("package client\n\n")
331+
subrouters, err := swagger.ParseSubrouters(*s)
332+
if err != nil {
333+
return err
334+
}
335+
248336
moduleName, versionSuffix := utils.ExtractModuleNameAndVersionSuffix(packageName, outputPath)
249-
g.Print(swagger.ImportStatements([]string{"context", moduleName + outputPath + "/models" + versionSuffix}))
337+
imports := []string{"context", moduleName + outputPath + "/models" + versionSuffix}
338+
for _, router := range subrouters {
339+
imports = append(
340+
imports,
341+
fmt.Sprintf(
342+
"%sclient \"%s/routers/%s/gen-go/client%s\"",
343+
router.Key,
344+
moduleName,
345+
router.Key,
346+
versionSuffix,
347+
),
348+
)
349+
}
350+
351+
g.Print("package client\n\n")
352+
g.Print(swagger.ImportStatements(imports))
250353
g.Print("//go:generate mockgen -source=$GOFILE -destination=mock_client.go -package client --build_flags=--mod=mod -imports=models=" + moduleName + outputPath + "/models" + versionSuffix + "\n\n")
251354

252355
if err := generateClientInterface(s, &g, serviceName, paths); err != nil {
@@ -259,10 +362,24 @@ func generateInterface(packageName, basePath, outputPath string, s *spec.Swagger
259362
return g.WriteFile("client/interface.go")
260363
}
261364

262-
func generateClientInterface(s *spec.Swagger, g *swagger.Generator, serviceName string, paths *spec.Paths) error {
365+
func generateClientInterface(
366+
s *spec.Swagger,
367+
g *swagger.Generator,
368+
serviceName string,
369+
paths *spec.Paths,
370+
) error {
263371
g.Printf("// Client defines the methods available to clients of the %s service.\n", serviceName)
264372
g.Print("type Client interface {\n\n")
265373

374+
subrouters, err := swagger.ParseSubrouters(*s)
375+
if err != nil {
376+
return err
377+
}
378+
379+
for _, router := range subrouters {
380+
g.Printf("\t%sclient.Client\n", router.Key)
381+
}
382+
266383
for _, pathKey := range swagger.SortedPathItemKeys(paths.Paths) {
267384
path := paths.Paths[pathKey]
268385
pathItemOps := swagger.PathItemOperations(path)
@@ -736,12 +853,13 @@ func iterCode(s *spec.Swagger, op *spec.Operation, basePath, methodPath, method
736853
resourceAccessString = resourceAccessString + "." + utils.CamelCase(pathComponent, true)
737854
}
738855

856+
operationInput, _ := swagger.OperationInput(op)
739857
return templates.WriteTemplate(
740858
iterTmplStr,
741859
iterTmpl{
742860
OpID: op.ID,
743861
CapOpID: capOpID,
744-
Input: swagger.OperationInput(op),
862+
Input: operationInput,
745863
BuildPathCode: buildPathCode(s, op, basePath, methodPath),
746864
BuildHeadersCode: buildHeadersCode(s, op),
747865
BuildBodyCode: buildBodyCode(s, op, method),

clients/go/subrouters.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package goclient
2+
3+
import (
4+
"strings"
5+
6+
"github.com/Clever/wag/v9/swagger"
7+
"github.com/Clever/wag/v9/templates"
8+
"github.com/go-openapi/spec"
9+
"github.com/iancoleman/strcase"
10+
)
11+
12+
func subrouterOperationCode(
13+
s *spec.Swagger,
14+
op *spec.Operation,
15+
subrouter swagger.Subrouter,
16+
) (string, error) {
17+
_, param := swagger.OperationInput(op)
18+
templateArgs := struct {
19+
ClientOperation string
20+
InputParamName string
21+
OperationID string
22+
SubrouterClient string
23+
}{
24+
ClientOperation: strings.ReplaceAll(
25+
swagger.ClientInterface(s, op),
26+
"models",
27+
subrouter.Key+"models",
28+
),
29+
InputParamName: param,
30+
OperationID: op.ID,
31+
SubrouterClient: strcase.ToLowerCamel(subrouter.Key) + "Client",
32+
}
33+
34+
templateStr := `func (c *WagClient) {{.ClientOperation}} {
35+
return c.{{.SubrouterClient}}.{{pascalcase .OperationID}}(ctx, {{.InputParamName}})
36+
}`
37+
38+
return templates.WriteTemplate(templateStr, templateArgs)
39+
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ require (
1313
github.com/go-openapi/swag v0.22.3
1414
github.com/go-openapi/validate v0.19.15
1515
github.com/go-swagger/go-swagger v0.23.0
16+
github.com/iancoleman/strcase v0.3.0
1617
github.com/stretchr/testify v1.8.2
1718
)
1819

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf
144144
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
145145
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
146146
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
147+
github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI=
148+
github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
147149
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
148150
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
149151
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=

main.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,6 @@ func main() {
145145
conf.goAbsolutePackagePath,
146146
*conf.outputPath,
147147
swaggerSpec,
148-
*conf.subrouter,
149148
); err != nil {
150149
log.Fatal(err.Error())
151150
}
@@ -214,12 +213,11 @@ func generateDynamo(dynamoPath, goPackageName, basePath, relativeDynamoPath, Out
214213
func generateGoClient(
215214
goPackageName, basePath, outputPath string,
216215
swaggerSpec spec.Swagger,
217-
subrouter bool,
218216
) error {
219217
if err := prepareDir(filepath.Join(basePath, "client")); err != nil {
220218
return err
221219
}
222-
if err := goclient.Generate(goPackageName, basePath, outputPath, swaggerSpec, subrouter); err != nil {
220+
if err := goclient.Generate(goPackageName, basePath, outputPath, swaggerSpec); err != nil {
223221
return fmt.Errorf("Failed generating go client %s", err)
224222
}
225223
doerGenerator := swagger.Generator{BasePath: basePath}

swagger/ext_subrouters.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ package swagger
33
import (
44
"encoding/json"
55
"log"
6+
"path/filepath"
67

8+
"github.com/go-openapi/loads"
79
"github.com/go-openapi/spec"
810
)
911

@@ -34,3 +36,12 @@ func ParseSubrouters(s spec.Swagger) ([]Subrouter, error) {
3436

3537
return subrouterConfig, nil
3638
}
39+
40+
func LoadSubrouterSpec(router Subrouter) (*spec.Swagger, error) {
41+
doc, err := loads.Spec(filepath.Join("routers", router.Key, "swagger.yml"))
42+
if err != nil {
43+
return nil, err
44+
}
45+
46+
return doc.Spec(), nil
47+
}

0 commit comments

Comments
 (0)