From 9fcec8ec902a3c4a83d132400e7ad33ea19234b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 16 Dec 2022 16:52:53 -0800 Subject: [PATCH 01/82] Bump golang.org/x/tools from 0.3.0 to 0.4.0 (#893) Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.3.0 to 0.4.0. - [Release notes](https://github.com/golang/tools/releases) - [Commits](https://github.com/golang/tools/compare/v0.3.0...v0.4.0) --- updated-dependencies: - dependency-name: golang.org/x/tools dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index ff48607022..9d8dc882cb 100644 --- a/go.mod +++ b/go.mod @@ -12,8 +12,8 @@ require ( github.com/lestrrat-go/jwx v1.2.25 github.com/matryer/moq v0.2.7 github.com/stretchr/testify v1.8.1 - golang.org/x/text v0.4.0 - golang.org/x/tools v0.3.0 + golang.org/x/text v0.5.0 + golang.org/x/tools v0.4.0 gopkg.in/yaml.v2 v2.4.0 ) @@ -53,8 +53,8 @@ require ( github.com/valyala/fasttemplate v1.2.2 // indirect golang.org/x/crypto v0.1.0 // indirect golang.org/x/mod v0.7.0 // indirect - golang.org/x/net v0.2.0 // indirect - golang.org/x/sys v0.2.0 // indirect + golang.org/x/net v0.3.0 // indirect + golang.org/x/sys v0.3.0 // indirect golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect google.golang.org/protobuf v1.28.1 // indirect diff --git a/go.sum b/go.sum index 86f056337d..f1d6f58115 100644 --- a/go.sum +++ b/go.sum @@ -145,8 +145,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.3.0 h1:VWL6FNY2bEEmsGVKabSlHu5Irp34xmMRoqb/9lF9lxk= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= @@ -160,22 +160,22 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w= golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= -golang.org/x/tools v0.3.0 h1:SrNbZl6ECOS1qFzgTdQfWXZM9XBkiA6tkFrH9YSTPHM= -golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.4.0 h1:7mTAgkunk3fr4GAloyyCasadO6h9zSsQZbwvcaIciV4= +golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From be3354eb68979c5f222bae0cc9ffa6cba23d7c0a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 16 Dec 2022 16:53:07 -0800 Subject: [PATCH 02/82] Bump github.com/go-chi/chi/v5 from 5.0.7 to 5.0.8 (#894) Bumps [github.com/go-chi/chi/v5](https://github.com/go-chi/chi) from 5.0.7 to 5.0.8. - [Release notes](https://github.com/go-chi/chi/releases) - [Changelog](https://github.com/go-chi/chi/blob/master/CHANGELOG.md) - [Commits](https://github.com/go-chi/chi/compare/v5.0.7...v5.0.8) --- updated-dependencies: - dependency-name: github.com/go-chi/chi/v5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 9d8dc882cb..228e0e5960 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ require ( github.com/apapsch/go-jsonmerge/v2 v2.0.0 github.com/getkin/kin-openapi v0.107.0 github.com/gin-gonic/gin v1.8.1 - github.com/go-chi/chi/v5 v5.0.7 + github.com/go-chi/chi/v5 v5.0.8 github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219 github.com/google/uuid v1.3.0 github.com/gorilla/mux v1.8.0 diff --git a/go.sum b/go.sum index f1d6f58115..678f9656e5 100644 --- a/go.sum +++ b/go.sum @@ -16,8 +16,8 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= -github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8= -github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0= +github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= From 597fa8dc03b3a8e2d74d7875069c41fa4d393d82 Mon Sep 17 00:00:00 2001 From: Cosmos Nicolaou Date: Fri, 16 Dec 2022 16:54:17 -0800 Subject: [PATCH 03/82] . (#895) --- pkg/codegen/merge_schemas.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/codegen/merge_schemas.go b/pkg/codegen/merge_schemas.go index 610f0d2dec..466e55c549 100644 --- a/pkg/codegen/merge_schemas.go +++ b/pkg/codegen/merge_schemas.go @@ -37,7 +37,7 @@ func mergeSchemas(allOf []*openapi3.SchemaRef, path []string) (Schema, error) { if err != nil { return Schema{}, err } - schema, err = mergeOpenapiSchemas(schema, oneOfSchema) + schema, err = mergeOpenapiSchemas(schema, oneOfSchema, true) if err != nil { return Schema{}, fmt.Errorf("error merging schemas for AllOf: %w", err) } @@ -74,7 +74,7 @@ func mergeAllOf(allOf []*openapi3.SchemaRef) (openapi3.Schema, error) { var schema openapi3.Schema for _, schemaRef := range allOf { var err error - schema, err = mergeOpenapiSchemas(schema, *schemaRef.Value) + schema, err = mergeOpenapiSchemas(schema, *schemaRef.Value, true) if err != nil { return openapi3.Schema{}, fmt.Errorf("error merging schemas for AllOf: %w", err) } @@ -84,7 +84,7 @@ func mergeAllOf(allOf []*openapi3.SchemaRef) (openapi3.Schema, error) { // mergeOpenapiSchemas merges two openAPI schemas and returns the schema // all of whose fields are composed. -func mergeOpenapiSchemas(s1, s2 openapi3.Schema) (openapi3.Schema, error) { +func mergeOpenapiSchemas(s1, s2 openapi3.Schema, allOf bool) (openapi3.Schema, error) { var result openapi3.Schema if s1.Extensions != nil || s2.Extensions != nil { result.Extensions = make(map[string]interface{}) @@ -219,8 +219,8 @@ func mergeOpenapiSchemas(s1, s2 openapi3.Schema) (openapi3.Schema, error) { result.AdditionalProperties = s2.AdditionalProperties } - // Unhandled for now - if s1.Discriminator != nil || s2.Discriminator != nil { + // Allow discriminators for allOf merges, but disallow for one/anyOfs. + if !allOf && (s1.Discriminator != nil || s2.Discriminator != nil) { return openapi3.Schema{}, errors.New("merging two schemas with discriminators is not supported") } From e96550865fbb515792fa912819d2fa7d2ae14f73 Mon Sep 17 00:00:00 2001 From: Sergey Kostyuchenko Date: Sat, 17 Dec 2022 03:56:31 +0300 Subject: [PATCH 04/82] Gin's Cookie returns string, not *http.Cookie (#878) --- pkg/codegen/templates/gin/gin-wrappers.tmpl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pkg/codegen/templates/gin/gin-wrappers.tmpl b/pkg/codegen/templates/gin/gin-wrappers.tmpl index a0beee4855..b16776b815 100644 --- a/pkg/codegen/templates/gin/gin-wrappers.tmpl +++ b/pkg/codegen/templates/gin/gin-wrappers.tmpl @@ -126,18 +126,19 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { {{end}} {{range .CookieParams}} - var cookie *http.Cookie + { + var cookie string if cookie, err = c.Cookie("{{.ParamName}}"); err == nil { {{- if .IsPassThrough}} - params.{{.GoName}} = {{if not .Required}}&{{end}}cookie.Value + params.{{.GoName}} = {{if not .Required}}&{{end}}cookie {{end}} {{- if .IsJson}} var value {{.TypeDef}} var decoded string - decoded, err := url.QueryUnescape(cookie.Value) + decoded, err := url.QueryUnescape(cookie) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Error unescaping cookie parameter '{{.ParamName}}'"), http.StatusBadRequest) return @@ -154,7 +155,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { {{- if .IsStyled}} var value {{.TypeDef}} - err = runtime.BindStyledParameter("simple",{{.Explode}}, "{{.ParamName}}", cookie.Value, &value) + err = runtime.BindStyledParameter("simple",{{.Explode}}, "{{.ParamName}}", cookie, &value) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %s", err), http.StatusBadRequest) return @@ -169,6 +170,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { return } {{- end}} + } {{end}} {{end}} From d516da72dfb76924131812bc33905e1385fe384a Mon Sep 17 00:00:00 2001 From: Alejandro Mery Date: Sat, 17 Dec 2022 00:58:03 +0000 Subject: [PATCH 05/82] x-enum-varnames revival (#880) * feat: support x-enum-varnames for numeric enums x-enum-varnames can be used to have an other enum name for the corresponding value. This is used to define names of the enum items. * test: add test for x-enum-varnames * docs: describe x-enum-varnames in README.md * feat: also support `x-enumNames`, alias for `x-enum-varnames` Co-authored-by: HANAI tohru --- README.md | 29 ++++++++++++++++++++++++++ pkg/codegen/codegen_test.go | 5 +++++ pkg/codegen/extension.go | 14 +++++++++++++ pkg/codegen/schema.go | 12 ++++++++++- pkg/codegen/test_spec.yaml | 41 +++++++++++++++++++++++++++++++++++++ pkg/codegen/utils.go | 23 +++++++++++++-------- 6 files changed, 114 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 295edf35a1..c916753cdb 100644 --- a/README.md +++ b/README.md @@ -632,6 +632,35 @@ which help you to use the various OpenAPI 3 Authentication mechanism. } ``` +- `x-enum-varnames`: supplies other enum names for the corresponding values. (alias: `x-enumNames`) + + ```yaml + components: + schemas: + Object: + properties: + category: + type: integer + enum: [0, 1, 2] + x-enum-varnames: + - notice + - warning + - urgent + ``` + + After code generation you will get this result: + + ```go + // Defines values for ObjectCategory. + const ( + Notice ObjectCategory = 0 + Urgent ObjectCategory = 2 + Warning ObjectCategory = 1 + ) + + // ObjectCategory defines model for Object.Category. + type ObjectCategory int + ``` ## Using `oapi-codegen` diff --git a/pkg/codegen/codegen_test.go b/pkg/codegen/codegen_test.go index 4a85eb1e92..e3878f58dd 100644 --- a/pkg/codegen/codegen_test.go +++ b/pkg/codegen/codegen_test.go @@ -188,6 +188,11 @@ type GetTestByNameResponse struct { assert.Contains(t, code, "func (c *Client) GetTestByName(ctx context.Context, name string, params *GetTestByNameParams, reqEditors ...RequestEditorFn) (*http.Response, error) {") assert.Contains(t, code, "func (c *ClientWithResponses) GetTestByNameWithResponse(ctx context.Context, name string, params *GetTestByNameParams, reqEditors ...RequestEditorFn) (*GetTestByNameResponse, error) {") assert.Contains(t, code, "DeadSince *time.Time `json:\"dead_since,omitempty\" tag1:\"value1\" tag2:\"value2\"`") + assert.Contains(t, code, "type EnumTestNumerics int") + assert.Contains(t, code, "N2 EnumTestNumerics = 2") + assert.Contains(t, code, "type EnumTestEnumNames int") + assert.Contains(t, code, "Two EnumTestEnumNames = 2") + assert.Contains(t, code, "Double EnumTestEnumVarnames = 2") // Make sure the generated code is valid: checkLint(t, "test.gen.go", []byte(code)) diff --git a/pkg/codegen/extension.go b/pkg/codegen/extension.go index 69c462142d..ad91ad06b1 100644 --- a/pkg/codegen/extension.go +++ b/pkg/codegen/extension.go @@ -17,6 +17,8 @@ const ( extPropGoJsonIgnore = "x-go-json-ignore" extPropOmitEmpty = "x-omitempty" extPropExtraTags = "x-oapi-codegen-extra-tags" + extEnumVarNames = "x-enum-varnames" + extEnumNames = "x-enumNames" ) func extString(extPropValue interface{}) (string, error) { @@ -78,3 +80,15 @@ func extParseGoJsonIgnore(extPropValue interface{}) (bool, error) { return goJsonIgnore, nil } + +func extParseEnumVarNames(extPropValue interface{}) ([]string, error) { + raw, ok := extPropValue.(json.RawMessage) + if !ok { + return nil, fmt.Errorf("failed to convert type: %T", extPropValue) + } + var names []string + if err := json.Unmarshal(raw, &names); err != nil { + return nil, fmt.Errorf("failed to unmarshal json: %w", err) + } + return names, nil +} diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index d8001f1998..18430240db 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -420,7 +420,17 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { enumValues[i] = fmt.Sprintf("%v", enumValue) } - sanitizedValues := SanitizeEnumNames(enumValues) + enumNames := enumValues + for _, key := range []string{extEnumVarNames, extEnumNames} { + if _, ok := schema.ExtensionProps.Extensions[key]; ok { + if extEnumNames, err := extParseEnumVarNames(schema.ExtensionProps.Extensions[key]); err == nil { + enumNames = extEnumNames + break + } + } + } + + sanitizedValues := SanitizeEnumNames(enumNames, enumValues) outSchema.EnumValues = make(map[string]string, len(sanitizedValues)) for k, v := range sanitizedValues { diff --git a/pkg/codegen/test_spec.yaml b/pkg/codegen/test_spec.yaml index 62a987123a..7491c69c31 100644 --- a/pkg/codegen/test_spec.yaml +++ b/pkg/codegen/test_spec.yaml @@ -87,6 +87,27 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' + /enum: + get: + tags: + - enum + summary: References enum + operationId: getEnum + responses: + 200: + description: Success + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/EnumTest' + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' components: schemas: @@ -136,3 +157,23 @@ components: cause: type: string enum: [ car, dog, oldage ] + + EnumTest: + properties: + numerics: + type: integer + enum: [0, 1, 2] + enumNames: + type: integer + enum: [0, 1, 2] + x-enumNames: + - zero + - one + - two + enumVarnames: + type: integer + enum: [0, 1, 2] + x-enum-varnames: + - na + - single + - double diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index 52274c0a67..7526ee3bf1 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -554,13 +554,17 @@ func SanitizeGoIdentity(str string) string { // SanitizeEnumNames fixes illegal chars in the enum names // and removes duplicates -func SanitizeEnumNames(enumNames []string) map[string]string { - dupCheck := make(map[string]int, len(enumNames)) - deDup := make([]string, 0, len(enumNames)) - - for _, n := range enumNames { +func SanitizeEnumNames(enumNames, enumValues []string) map[string]string { + dupCheck := make(map[string]int, len(enumValues)) + deDup := make([][]string, 0, len(enumValues)) + + for i, v := range enumValues { + n := v + if i < len(enumNames) { + n = enumNames[i] + } if _, dup := dupCheck[n]; !dup { - deDup = append(deDup, n) + deDup = append(deDup, []string{n, v}) } dupCheck[n] = 0 } @@ -568,13 +572,14 @@ func SanitizeEnumNames(enumNames []string) map[string]string { dupCheck = make(map[string]int, len(deDup)) sanitizedDeDup := make(map[string]string, len(deDup)) - for _, n := range deDup { + for _, p := range deDup { + n, v := p[0], p[1] sanitized := SanitizeGoIdentity(SchemaNameToTypeName(n)) if _, dup := dupCheck[sanitized]; !dup { - sanitizedDeDup[sanitized] = n + sanitizedDeDup[sanitized] = v } else { - sanitizedDeDup[sanitized+strconv.Itoa(dupCheck[sanitized])] = n + sanitizedDeDup[sanitized+strconv.Itoa(dupCheck[sanitized])] = v } dupCheck[sanitized]++ } From c7be8fd42a62d9542d779df3d7a24b33601fa93d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 16 Dec 2022 16:58:23 -0800 Subject: [PATCH 06/82] Bump github.com/matryer/moq from 0.2.7 to 0.3.0 (#875) Bumps [github.com/matryer/moq](https://github.com/matryer/moq) from 0.2.7 to 0.3.0. - [Release notes](https://github.com/matryer/moq/releases) - [Changelog](https://github.com/matryer/moq/blob/main/.goreleaser.yml) - [Commits](https://github.com/matryer/moq/compare/v0.2.7...v0.3.0) --- updated-dependencies: - dependency-name: github.com/matryer/moq dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 22 ++-------------------- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/go.mod b/go.mod index 228e0e5960..528232e59f 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/gorilla/mux v1.8.0 github.com/labstack/echo/v4 v4.9.1 github.com/lestrrat-go/jwx v1.2.25 - github.com/matryer/moq v0.2.7 + github.com/matryer/moq v0.3.0 github.com/stretchr/testify v1.8.1 golang.org/x/text v0.5.0 golang.org/x/tools v0.4.0 diff --git a/go.sum b/go.sum index 678f9656e5..0f88eb052f 100644 --- a/go.sum +++ b/go.sum @@ -84,8 +84,8 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/matryer/moq v0.2.7 h1:RtpiPUM8L7ZSCbSwK+QcZH/E9tgqAkFjKQxsRs25b4w= -github.com/matryer/moq v0.2.7/go.mod h1:kITsx543GOENm48TUAQyJ9+SAvFSr7iGQXPoth/VUBk= +github.com/matryer/moq v0.3.0 h1:4j0goF/XK3pMTc7fJB3fveuTJoQNdavRX/78vlK3Xb4= +github.com/matryer/moq v0.3.0/go.mod h1:RJ75ZZZD71hejp39j4crZLsEDszGk6iH4v4YsWFKH4s= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= @@ -131,40 +131,27 @@ github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyC github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.3.0 h1:VWL6FNY2bEEmsGVKabSlHu5Irp34xmMRoqb/9lF9lxk= golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= @@ -172,14 +159,9 @@ golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w= golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.4.0 h1:7mTAgkunk3fr4GAloyyCasadO6h9zSsQZbwvcaIciV4= golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= From 6c80420b8d5134b72f14e97711475a3b577f6f97 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sat, 17 Dec 2022 01:01:12 +0000 Subject: [PATCH 07/82] Warn when using a non-empty `spec.Servers` (#883) It's a fairly common mistake when using the OpenAPI request validation filter from kin-openapi to receive `no matching operation was found` errors if using the `servers` directive in your OpenAPI specification. This is a valid usescase, but you may not always want to be enforcing the validation that the `Host` header matches one of the `servers` mentioned in your specification. This makes it clearer to operators that there may be a configuration issue here, as a way to avoid as many folks falling into the same trap that many have before. This also provides an option to silence the warning, as logging out can be annoying and costly. Closes #882. --- pkg/chi-middleware/oapi_validate.go | 7 +++++++ pkg/gin-middleware/oapi_validate.go | 7 +++++++ pkg/middleware/oapi_validate.go | 7 +++++++ 3 files changed, 21 insertions(+) diff --git a/pkg/chi-middleware/oapi_validate.go b/pkg/chi-middleware/oapi_validate.go index 8c37a79e13..c09c2f1e28 100644 --- a/pkg/chi-middleware/oapi_validate.go +++ b/pkg/chi-middleware/oapi_validate.go @@ -7,6 +7,7 @@ import ( "context" "errors" "fmt" + "log" "net/http" "strings" @@ -27,6 +28,8 @@ type Options struct { Options openapi3filter.Options ErrorHandler ErrorHandler MultiErrorHandler MultiErrorHandler + // SilenceServersWarning allows silencing a warning for https://github.com/deepmap/oapi-codegen/issues/882 that reports when an OpenAPI spec has `spec.Servers != nil` + SilenceServersWarning bool } // OapiRequestValidator Creates middleware to validate request by swagger spec. @@ -38,6 +41,10 @@ func OapiRequestValidator(swagger *openapi3.T) func(next http.Handler) http.Hand // OapiRequestValidatorWithOptions Creates middleware to validate request by swagger spec. // This middleware is good for net/http either since go-chi is 100% compatible with net/http. func OapiRequestValidatorWithOptions(swagger *openapi3.T, options *Options) func(next http.Handler) http.Handler { + if swagger.Servers != nil && (options == nil || options.SilenceServersWarning) { + log.Println("WARN: OapiRequestValidatorWithOptions called with an OpenAPI spec that has `Servers` set. This may lead to an HTTP 400 with `no matching operation was found` when sending a valid request, as the validator performs `Host` header validation. If you're expecting `Host` header validation, you can silence this warning by setting `Options.SilenceServersWarning = true`. See https://github.com/deepmap/oapi-codegen/issues/882 for more information.") + } + router, err := gorillamux.NewRouter(swagger) if err != nil { panic(err) diff --git a/pkg/gin-middleware/oapi_validate.go b/pkg/gin-middleware/oapi_validate.go index 82c1f52cb6..3406134a68 100644 --- a/pkg/gin-middleware/oapi_validate.go +++ b/pkg/gin-middleware/oapi_validate.go @@ -18,6 +18,7 @@ import ( "context" "errors" "fmt" + "log" "net/http" "os" "strings" @@ -70,10 +71,16 @@ type Options struct { ParamDecoder openapi3filter.ContentParameterDecoder UserData interface{} MultiErrorHandler MultiErrorHandler + // SilenceServersWarning allows silencing a warning for https://github.com/deepmap/oapi-codegen/issues/882 that reports when an OpenAPI spec has `spec.Servers != nil` + SilenceServersWarning bool } // OapiRequestValidatorWithOptions creates a validator from a swagger object, with validation options func OapiRequestValidatorWithOptions(swagger *openapi3.T, options *Options) gin.HandlerFunc { + if swagger.Servers != nil && (options == nil || options.SilenceServersWarning) { + log.Println("WARN: OapiRequestValidatorWithOptions called with an OpenAPI spec that has `Servers` set. This may lead to an HTTP 400 with `no matching operation was found` when sending a valid request, as the validator performs `Host` header validation. If you're expecting `Host` header validation, you can silence this warning by setting `Options.SilenceServersWarning = true`. See https://github.com/deepmap/oapi-codegen/issues/882 for more information.") + } + router, err := gorillamux.NewRouter(swagger) if err != nil { panic(err) diff --git a/pkg/middleware/oapi_validate.go b/pkg/middleware/oapi_validate.go index a665b3dfcb..0318d29610 100644 --- a/pkg/middleware/oapi_validate.go +++ b/pkg/middleware/oapi_validate.go @@ -18,6 +18,7 @@ import ( "context" "errors" "fmt" + "log" "net/http" "os" "strings" @@ -73,10 +74,16 @@ type Options struct { UserData interface{} Skipper echomiddleware.Skipper MultiErrorHandler MultiErrorHandler + // SilenceServersWarning allows silencing a warning for https://github.com/deepmap/oapi-codegen/issues/882 that reports when an OpenAPI spec has `spec.Servers != nil` + SilenceServersWarning bool } // OapiRequestValidatorWithOptions creates a validator from a swagger object, with validation options func OapiRequestValidatorWithOptions(swagger *openapi3.T, options *Options) echo.MiddlewareFunc { + if swagger.Servers != nil && (options == nil || options.SilenceServersWarning) { + log.Println("WARN: OapiRequestValidatorWithOptions called with an OpenAPI spec that has `Servers` set. This may lead to an HTTP 400 with `no matching operation was found` when sending a valid request, as the validator performs `Host` header validation. If you're expecting `Host` header validation, you can silence this warning by setting `Options.SilenceServersWarning = true`. See https://github.com/deepmap/oapi-codegen/issues/882 for more information.") + } + router, err := gorillamux.NewRouter(swagger) if err != nil { panic(err) From 0fe10df5fda73d5e1b7fa1cca1ab58a08ed98c3a Mon Sep 17 00:00:00 2001 From: Cosmos Nicolaou Date: Fri, 16 Dec 2022 17:01:25 -0800 Subject: [PATCH 08/82] . (#897) From e8dc342de823cad04ffd4eb0892e2f1eaca5156f Mon Sep 17 00:00:00 2001 From: Sergey Kostyuchenko Date: Sat, 17 Dec 2022 04:01:51 +0300 Subject: [PATCH 09/82] Use gin.IRouter instead of *gin.Engine (#879) * Use gin.IRouter instead of *gin.Engine * Regenerate, fix tests --- .../gin/api/petstore-server.gen.go | 13 +++---------- examples/petstore-expanded/gin/petstore.go | 5 +++-- internal/test/strict-server/gin/server.gen.go | 18 +++--------------- internal/test/strict-server/strict_test.go | 13 +++++++------ pkg/codegen/templates/gin/gin-register.tmpl | 15 +++++++-------- 5 files changed, 23 insertions(+), 41 deletions(-) diff --git a/examples/petstore-expanded/gin/api/petstore-server.gen.go b/examples/petstore-expanded/gin/api/petstore-server.gen.go index 8dabdd9e76..abe997f618 100644 --- a/examples/petstore-expanded/gin/api/petstore-server.gen.go +++ b/examples/petstore-expanded/gin/api/petstore-server.gen.go @@ -134,15 +134,13 @@ type GinServerOptions struct { } // RegisterHandlers creates http.Handler with routing matching OpenAPI spec. -func RegisterHandlers(router *gin.Engine, si ServerInterface) *gin.Engine { - return RegisterHandlersWithOptions(router, si, GinServerOptions{}) +func RegisterHandlers(router gin.IRouter, si ServerInterface) { + RegisterHandlersWithOptions(router, si, GinServerOptions{}) } // RegisterHandlersWithOptions creates http.Handler with additional options -func RegisterHandlersWithOptions(router *gin.Engine, si ServerInterface, options GinServerOptions) *gin.Engine { - +func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options GinServerOptions) { errorHandler := options.ErrorHandler - if errorHandler == nil { errorHandler = func(c *gin.Context, err error, statusCode int) { c.JSON(statusCode, gin.H{"msg": err.Error()}) @@ -156,14 +154,9 @@ func RegisterHandlersWithOptions(router *gin.Engine, si ServerInterface, options } router.GET(options.BaseURL+"/pets", wrapper.FindPets) - router.POST(options.BaseURL+"/pets", wrapper.AddPet) - router.DELETE(options.BaseURL+"/pets/:id", wrapper.DeletePet) - router.GET(options.BaseURL+"/pets/:id", wrapper.FindPetByID) - - return router } // Base64 encoded, gzipped, json marshaled Swagger object diff --git a/examples/petstore-expanded/gin/petstore.go b/examples/petstore-expanded/gin/petstore.go index 2eae15bfca..a5b40a2f4c 100644 --- a/examples/petstore-expanded/gin/petstore.go +++ b/examples/petstore-expanded/gin/petstore.go @@ -11,9 +11,10 @@ import ( "net/http" "os" + "github.com/gin-gonic/gin" + "github.com/deepmap/oapi-codegen/examples/petstore-expanded/gin/api" middleware "github.com/deepmap/oapi-codegen/pkg/gin-middleware" - "github.com/gin-gonic/gin" ) func NewGinPetServer(petStore *api.PetStore, port int) *http.Server { @@ -35,7 +36,7 @@ func NewGinPetServer(petStore *api.PetStore, port int) *http.Server { r.Use(middleware.OapiRequestValidator(swagger)) // We now register our petStore above as the handler for the interface - r = api.RegisterHandlers(r, petStore) + api.RegisterHandlers(r, petStore) s := &http.Server{ Handler: r, diff --git a/internal/test/strict-server/gin/server.gen.go b/internal/test/strict-server/gin/server.gen.go index 52c729007a..a00437d709 100644 --- a/internal/test/strict-server/gin/server.gen.go +++ b/internal/test/strict-server/gin/server.gen.go @@ -208,15 +208,13 @@ type GinServerOptions struct { } // RegisterHandlers creates http.Handler with routing matching OpenAPI spec. -func RegisterHandlers(router *gin.Engine, si ServerInterface) *gin.Engine { - return RegisterHandlersWithOptions(router, si, GinServerOptions{}) +func RegisterHandlers(router gin.IRouter, si ServerInterface) { + RegisterHandlersWithOptions(router, si, GinServerOptions{}) } // RegisterHandlersWithOptions creates http.Handler with additional options -func RegisterHandlersWithOptions(router *gin.Engine, si ServerInterface, options GinServerOptions) *gin.Engine { - +func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options GinServerOptions) { errorHandler := options.ErrorHandler - if errorHandler == nil { errorHandler = func(c *gin.Context, err error, statusCode int) { c.JSON(statusCode, gin.H{"msg": err.Error()}) @@ -230,24 +228,14 @@ func RegisterHandlersWithOptions(router *gin.Engine, si ServerInterface, options } router.POST(options.BaseURL+"/json", wrapper.JSONExample) - router.POST(options.BaseURL+"/multipart", wrapper.MultipartExample) - router.POST(options.BaseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes) - router.POST(options.BaseURL+"/reusable-responses", wrapper.ReusableResponses) - router.POST(options.BaseURL+"/text", wrapper.TextExample) - router.POST(options.BaseURL+"/unknown", wrapper.UnknownExample) - router.POST(options.BaseURL+"/unspecified-content-type", wrapper.UnspecifiedContentType) - router.POST(options.BaseURL+"/urlencoded", wrapper.URLEncodedExample) - router.POST(options.BaseURL+"/with-headers", wrapper.HeadersExample) - - return router } type BadrequestResponse struct { diff --git a/internal/test/strict-server/strict_test.go b/internal/test/strict-server/strict_test.go index 76f236730d..860cc4cb8d 100644 --- a/internal/test/strict-server/strict_test.go +++ b/internal/test/strict-server/strict_test.go @@ -11,16 +11,17 @@ import ( "strings" "testing" + "github.com/gin-gonic/gin" + "github.com/go-chi/chi/v5" + "github.com/labstack/echo/v4" + "github.com/stretchr/testify/assert" + "github.com/deepmap/oapi-codegen/internal/test/strict-server/chi" api3 "github.com/deepmap/oapi-codegen/internal/test/strict-server/client" api4 "github.com/deepmap/oapi-codegen/internal/test/strict-server/echo" api2 "github.com/deepmap/oapi-codegen/internal/test/strict-server/gin" "github.com/deepmap/oapi-codegen/pkg/runtime" "github.com/deepmap/oapi-codegen/pkg/testutil" - "github.com/gin-gonic/gin" - "github.com/go-chi/chi/v5" - "github.com/labstack/echo/v4" - "github.com/stretchr/testify/assert" ) func TestChiServer(t *testing.T) { @@ -44,8 +45,8 @@ func TestGinServer(t *testing.T) { strictHandler := api2.NewStrictHandler(server, nil) gin.SetMode(gin.ReleaseMode) r := gin.New() - handler := api2.RegisterHandlers(r, strictHandler) - testImpl(t, handler) + api2.RegisterHandlers(r, strictHandler) + testImpl(t, r) } func testImpl(t *testing.T, handler http.Handler) { diff --git a/pkg/codegen/templates/gin/gin-register.tmpl b/pkg/codegen/templates/gin/gin-register.tmpl index 188cbb83ea..8f03722ab1 100644 --- a/pkg/codegen/templates/gin/gin-register.tmpl +++ b/pkg/codegen/templates/gin/gin-register.tmpl @@ -6,15 +6,14 @@ type GinServerOptions struct { } // RegisterHandlers creates http.Handler with routing matching OpenAPI spec. -func RegisterHandlers(router *gin.Engine, si ServerInterface) *gin.Engine { - return RegisterHandlersWithOptions(router, si, GinServerOptions{}) +func RegisterHandlers(router gin.IRouter, si ServerInterface) { + RegisterHandlersWithOptions(router, si, GinServerOptions{}) } // RegisterHandlersWithOptions creates http.Handler with additional options -func RegisterHandlersWithOptions(router *gin.Engine, si ServerInterface, options GinServerOptions) *gin.Engine { - {{if .}} +func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options GinServerOptions) { + {{- if . -}} errorHandler := options.ErrorHandler - if errorHandler == nil { errorHandler = func(c *gin.Context, err error, statusCode int) { c.JSON(statusCode, gin.H{"msg": err.Error()}) @@ -27,8 +26,8 @@ func RegisterHandlersWithOptions(router *gin.Engine, si ServerInterface, options ErrorHandler: errorHandler, } {{end}} - {{range .}} + + {{range . -}} router.{{.Method }}(options.BaseURL+"{{.Path | swaggerUriToGinUri }}", wrapper.{{.OperationId}}) - {{end}} - return router + {{end -}} } From 1b639823c72cc25fced33bfcf672096ba91b2dad Mon Sep 17 00:00:00 2001 From: Steven Hartland Date: Sat, 17 Dec 2022 01:02:42 +0000 Subject: [PATCH 10/82] fix(oapi-codegen): package name detection (#873) Re-add package name detection which was removed removed in the configuration rework. This also improves it by using go list to detect current package names. --- cmd/oapi-codegen/oapi-codegen.go | 42 ++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/cmd/oapi-codegen/oapi-codegen.go b/cmd/oapi-codegen/oapi-codegen.go index 957b90fef6..aa33a76ea7 100644 --- a/cmd/oapi-codegen/oapi-codegen.go +++ b/cmd/oapi-codegen/oapi-codegen.go @@ -17,7 +17,9 @@ import ( "flag" "fmt" "os" + "os/exec" "path" + "path/filepath" "runtime/debug" "strings" @@ -238,6 +240,10 @@ func main() { // fields. opts.Configuration = opts.UpdateDefaults() + if err := detectPackageName(&opts); err != nil { + errExit("%s\n", err) + } + // Now, ensure that the config options are valid. if err := opts.Validate(); err != nil { errExit("configuration error: %v\n", err) @@ -309,6 +315,42 @@ func loadTemplateOverrides(templatesDir string) (map[string]string, error) { return templates, nil } +// detectPackageName detects and sets PackageName if not already set. +func detectPackageName(cfg *configuration) error { + if cfg.PackageName != "" { + return nil + } + + if cfg.OutputFile != "" { + // Determine from the package name of the output file. + dir := filepath.Dir(cfg.PackageName) + cmd := exec.Command("go", "list", "-f", "{{.Name}}", dir) + out, err := cmd.CombinedOutput() + if err != nil { + outStr := string(out) + switch { + case strings.Contains(outStr, "expected 'package', found 'EOF'"): + // Redirecting the output to current directory which hasn't + // written anything yet, ignore. + case strings.HasPrefix(outStr, "no Go files in"): + // No go files yet, ignore. + default: + // Unexpected failure report. + return fmt.Errorf("detect package name for %q output: %q: %w", dir, string(out), err) + } + } else { + cfg.PackageName = string(out) + return nil + } + } + + // Fallback to determining from the spec file name. + parts := strings.Split(filepath.Base(flag.Arg(0)), ".") + cfg.PackageName = codegen.LowercaseFirstCharacter(codegen.ToCamelCase(parts[0])) + + return nil +} + // updateConfigFromFlags updates a loaded configuration from flags. Flags // override anything in the file. We generate errors for command line options // associated with the old style configuration From e1b4ade53fd75c6317f52fcc3ee57ef21b76b4be Mon Sep 17 00:00:00 2001 From: B-Lorentz <44694582+B-Lorentz@users.noreply.github.com> Date: Sat, 17 Dec 2022 02:04:18 +0100 Subject: [PATCH 11/82] AdditionalProperties and oneOf in one Schema (#765) * demonstrate error * updated templates * fix template * test --- internal/test/components/components.gen.go | 170 ++++++++++++++++++ internal/test/components/components.yaml | 17 ++ internal/test/components/components_test.go | 29 +++ pkg/codegen/codegen.go | 27 ++- .../templates/additional-properties.tmpl | 2 + .../union-and-additional-properties.tmpl | 72 ++++++++ pkg/codegen/templates/union.tmpl | 3 + 7 files changed, 319 insertions(+), 1 deletion(-) create mode 100644 pkg/codegen/templates/union-and-additional-properties.tmpl diff --git a/internal/test/components/components.gen.go b/internal/test/components/components.gen.go index d7e23d31c9..4ed8b65a1e 100644 --- a/internal/test/components/components.gen.go +++ b/internal/test/components/components.gen.go @@ -217,6 +217,13 @@ type OneOfObject120 = string // OneOfObject121 defines model for . type OneOfObject121 = float32 +// OneOfObject13 oneOf with fixed discriminator and other fields allowed +type OneOfObject13 struct { + Type string `json:"type"` + AdditionalProperties map[string]interface{} `json:"-"` + union json.RawMessage +} + // OneOfObject2 oneOf with inline elements type OneOfObject2 struct { union json.RawMessage @@ -772,6 +779,23 @@ func (a AdditionalPropertiesObject4_Inner) MarshalJSON() ([]byte, error) { return json.Marshal(object) } +// Getter for additional properties for OneOfObject13. Returns the specified +// element and whether it was found +func (a OneOfObject13) Get(fieldName string) (value interface{}, found bool) { + if a.AdditionalProperties != nil { + value, found = a.AdditionalProperties[fieldName] + } + return +} + +// Setter for additional properties for OneOfObject13 +func (a *OneOfObject13) Set(fieldName string, value interface{}) { + if a.AdditionalProperties == nil { + a.AdditionalProperties = make(map[string]interface{}) + } + a.AdditionalProperties[fieldName] = value +} + // AsOneOfVariant4 returns the union data inside the AnyOfObject1 as a OneOfVariant4 func (t AnyOfObject1) AsOneOfVariant4() (OneOfVariant4, error) { var body OneOfVariant4 @@ -1248,6 +1272,89 @@ func (t *OneOfObject12) UnmarshalJSON(b []byte) error { return err } +// AsOneOfVariant1 returns the union data inside the OneOfObject13 as a OneOfVariant1 +func (t OneOfObject13) AsOneOfVariant1() (OneOfVariant1, error) { + var body OneOfVariant1 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromOneOfVariant1 overwrites any union data inside the OneOfObject13 as the provided OneOfVariant1 +func (t *OneOfObject13) FromOneOfVariant1(v OneOfVariant1) error { + t.Type = "v1" + + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeOneOfVariant1 performs a merge with any union data inside the OneOfObject13, using the provided OneOfVariant1 +func (t *OneOfObject13) MergeOneOfVariant1(v OneOfVariant1) error { + t.Type = "v1" + + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JsonMerge(b, t.union) + t.union = merged + return err +} + +// AsOneOfVariant6 returns the union data inside the OneOfObject13 as a OneOfVariant6 +func (t OneOfObject13) AsOneOfVariant6() (OneOfVariant6, error) { + var body OneOfVariant6 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromOneOfVariant6 overwrites any union data inside the OneOfObject13 as the provided OneOfVariant6 +func (t *OneOfObject13) FromOneOfVariant6(v OneOfVariant6) error { + t.Type = "v6" + + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeOneOfVariant6 performs a merge with any union data inside the OneOfObject13, using the provided OneOfVariant6 +func (t *OneOfObject13) MergeOneOfVariant6(v OneOfVariant6) error { + t.Type = "v6" + + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JsonMerge(b, t.union) + t.union = merged + return err +} + +func (t OneOfObject13) Discriminator() (string, error) { + var discriminator struct { + Discriminator string `json:"type"` + } + err := json.Unmarshal(t.union, &discriminator) + return discriminator.Discriminator, err +} + +func (t OneOfObject13) ValueByDiscriminator() (interface{}, error) { + discriminator, err := t.Discriminator() + if err != nil { + return nil, err + } + switch discriminator { + case "v1": + return t.AsOneOfVariant1() + case "v6": + return t.AsOneOfVariant6() + default: + return nil, errors.New("unknown discriminator value: " + discriminator) + } +} + // AsOneOfObject20 returns the union data inside the OneOfObject2 as a OneOfObject20 func (t OneOfObject2) AsOneOfObject20() (OneOfObject20, error) { var body OneOfObject20 @@ -1988,3 +2095,66 @@ func (t *OneOfObject9) UnmarshalJSON(b []byte) error { return err } + +// Override default JSON handling for OneOfObject13 to handle AdditionalProperties and union +func (a *OneOfObject13) UnmarshalJSON(b []byte) error { + err := a.union.UnmarshalJSON(b) + if err != nil { + return err + } + object := make(map[string]json.RawMessage) + err = json.Unmarshal(b, &object) + if err != nil { + return err + } + + if raw, found := object["type"]; found { + err = json.Unmarshal(raw, &a.Type) + if err != nil { + return fmt.Errorf("error reading 'type': %w", err) + } + delete(object, "type") + } + + if len(object) != 0 { + a.AdditionalProperties = make(map[string]interface{}) + for fieldName, fieldBuf := range object { + var fieldVal interface{} + err := json.Unmarshal(fieldBuf, &fieldVal) + if err != nil { + return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err) + } + a.AdditionalProperties[fieldName] = fieldVal + } + } + return nil +} + +// Override default JSON handling for OneOfObject13 to handle AdditionalProperties and union +func (a OneOfObject13) MarshalJSON() ([]byte, error) { + var err error + b, err := a.union.MarshalJSON() + if err != nil { + return nil, err + } + object := make(map[string]json.RawMessage) + if a.union != nil { + err = json.Unmarshal(b, &object) + if err != nil { + return nil, err + } + } + + object["type"], err = json.Marshal(a.Type) + if err != nil { + return nil, fmt.Errorf("error marshaling 'type': %w", err) + } + + for fieldName, field := range a.AdditionalProperties { + object[fieldName], err = json.Marshal(field) + if err != nil { + return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err) + } + } + return json.Marshal(object) +} diff --git a/internal/test/components/components.yaml b/internal/test/components/components.yaml index 79e3857361..98224ed5f6 100644 --- a/internal/test/components/components.yaml +++ b/internal/test/components/components.yaml @@ -325,6 +325,23 @@ components: - oneOf: - $ref: '#/components/schemas/OneOfVariant3' - $ref: '#/components/schemas/OneOfVariant4' + OneOfObject13: + description: oneOf with fixed discriminator and other fields allowed + type: object + properties: + type: + type: string + oneOf: + - $ref: '#/components/schemas/OneOfVariant1' + - $ref: '#/components/schemas/OneOfVariant6' + discriminator: + propertyName: type + mapping: + v1: '#/components/schemas/OneOfVariant1' + v6: '#/components/schemas/OneOfVariant6' + required: + - type + additionalProperties: true AnyOfObject1: description: simple anyOf case anyOf: diff --git a/internal/test/components/components_test.go b/internal/test/components/components_test.go index e2eabfb09b..e25ede26bc 100644 --- a/internal/test/components/components_test.go +++ b/internal/test/components/components_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func assertJsonEqual(t *testing.T, j1 []byte, j2 []byte) { @@ -203,6 +204,34 @@ func TestAnyOf(t *testing.T) { assert.Equal(t, OneOfVariant5{Discriminator: "all", Id: 456}, v5) } +func TestOneOfWithAdditional(t *testing.T) { + x := OneOfObject13{ + AdditionalProperties: map[string]interface{}{"x": "y"}, + } + err := x.MergeOneOfVariant1(OneOfVariant1{Name: "test-name"}) + require.NoError(t, err) + b, err := json.Marshal(x) + require.NoError(t, err) + assert.JSONEq(t, `{"x":"y", "name":"test-name", "type":"v1"}`, string(b)) + var y OneOfObject13 + err = json.Unmarshal(b, &y) + require.NoError(t, err) + assert.Equal(t, x.Type, y.Type) + xVariant, err := x.AsOneOfVariant1() + require.NoError(t, err) + yVariant, err := y.AsOneOfVariant1() + require.NoError(t, err) + assert.Equal(t, xVariant, yVariant) + xAdditional, ok := x.Get("x") + assert.True(t, ok) + yAdditional, ok := y.Get("x") + assert.True(t, ok) + assert.Equal(t, xAdditional, yAdditional) + b, err = json.Marshal(y) + require.NoError(t, err) + assert.JSONEq(t, `{"x":"y", "name":"test-name", "type":"v1"}`, string(b)) +} + func TestMarshalWhenNoUnionValueSet(t *testing.T) { const expected = `{}` diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 50866917e8..062dc953d7 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -396,7 +396,12 @@ func GenerateTypeDefinitions(t *template.Template, swagger *openapi3.T, ops []Op return "", fmt.Errorf("error generating union boilerplate: %w", err) } - typeDefinitions := strings.Join([]string{enumsOut, typesOut, operationsOut, allOfBoilerplate, unionBoilerplate}, "") + unionAndAdditionalBoilerplate, err := GenerateUnionAndAdditionalProopertiesBoilerplate(t, allTypes) + if err != nil { + return "", fmt.Errorf("error generating boilerplate for union types with additionalProperties: %w", err) + } + + typeDefinitions := strings.Join([]string{enumsOut, typesOut, operationsOut, allOfBoilerplate, unionBoilerplate, unionAndAdditionalBoilerplate}, "") return typeDefinitions, nil } @@ -778,6 +783,26 @@ func GenerateUnionBoilerplate(t *template.Template, typeDefs []TypeDefinition) ( return GenerateTemplates([]string{"union.tmpl"}, t, context) } +func GenerateUnionAndAdditionalProopertiesBoilerplate(t *template.Template, typeDefs []TypeDefinition) (string, error) { + var filteredTypes []TypeDefinition + for _, t := range typeDefs { + if len(t.Schema.UnionElements) != 0 && t.Schema.HasAdditionalProperties { + filteredTypes = append(filteredTypes, t) + } + } + + if len(filteredTypes) == 0 { + return "", nil + } + context := struct { + Types []TypeDefinition + }{ + Types: filteredTypes, + } + + return GenerateTemplates([]string{"union-and-additional-properties.tmpl"}, t, context) +} + // SanitizeCode runs sanitizers across the generated Go code to ensure the // generated code will be able to compile. func SanitizeCode(goCode string) string { diff --git a/pkg/codegen/templates/additional-properties.tmpl b/pkg/codegen/templates/additional-properties.tmpl index 8a37647bf4..c83cc107ed 100644 --- a/pkg/codegen/templates/additional-properties.tmpl +++ b/pkg/codegen/templates/additional-properties.tmpl @@ -17,6 +17,7 @@ func (a *{{.TypeName}}) Set(fieldName string, value {{$addType}}) { a.AdditionalProperties[fieldName] = value } +{{if eq 0 (len .Schema.UnionElements) -}} // Override default JSON handling for {{.TypeName}} to handle AdditionalProperties func (a *{{.TypeName}}) UnmarshalJSON(b []byte) error { object := make(map[string]json.RawMessage) @@ -68,3 +69,4 @@ func (a {{.TypeName}}) MarshalJSON() ([]byte, error) { return json.Marshal(object) } {{end}} +{{end}} \ No newline at end of file diff --git a/pkg/codegen/templates/union-and-additional-properties.tmpl b/pkg/codegen/templates/union-and-additional-properties.tmpl new file mode 100644 index 0000000000..79b4c67b2e --- /dev/null +++ b/pkg/codegen/templates/union-and-additional-properties.tmpl @@ -0,0 +1,72 @@ +{{range .Types}} + +{{$addType := .Schema.AdditionalPropertiesType.TypeDecl}} +{{$typeName := .TypeName -}} +{{$discriminator := .Schema.Discriminator}} +{{$properties := .Schema.Properties -}} + +// Override default JSON handling for {{.TypeName}} to handle AdditionalProperties and union +func (a *{{.TypeName}}) UnmarshalJSON(b []byte) error { + err := a.union.UnmarshalJSON(b) + if err != nil { + return err + } + object := make(map[string]json.RawMessage) + err = json.Unmarshal(b, &object) + if err != nil { + return err + } +{{range .Schema.Properties}} + if raw, found := object["{{.JsonFieldName}}"]; found { + err = json.Unmarshal(raw, &a.{{.GoFieldName}}) + if err != nil { + return fmt.Errorf("error reading '{{.JsonFieldName}}': %w", err) + } + delete(object, "{{.JsonFieldName}}") + } +{{end}} + if len(object) != 0 { + a.AdditionalProperties = make(map[string]{{$addType}}) + for fieldName, fieldBuf := range object { + var fieldVal {{$addType}} + err := json.Unmarshal(fieldBuf, &fieldVal) + if err != nil { + return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err) + } + a.AdditionalProperties[fieldName] = fieldVal + } + } + return nil +} + +// Override default JSON handling for {{.TypeName}} to handle AdditionalProperties and union +func (a {{.TypeName}}) MarshalJSON() ([]byte, error) { + var err error + b, err := a.union.MarshalJSON() + if err != nil { + return nil, err + } + object := make(map[string]json.RawMessage) + if a.union != nil { + err = json.Unmarshal(b, &object) + if err != nil { + return nil, err + } + } +{{range .Schema.Properties}} +{{if not .Required}}if a.{{.GoFieldName}} != nil { {{end}} + object["{{.JsonFieldName}}"], err = json.Marshal(a.{{.GoFieldName}}) + if err != nil { + return nil, fmt.Errorf("error marshaling '{{.JsonFieldName}}': %w", err) + } +{{if not .Required}} }{{end}} +{{end}} + for fieldName, field := range a.AdditionalProperties { + object[fieldName], err = json.Marshal(field) + if err != nil { + return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err) + } + } + return json.Marshal(object) +} +{{end}} diff --git a/pkg/codegen/templates/union.tmpl b/pkg/codegen/templates/union.tmpl index b758a82c64..06c91f4f13 100644 --- a/pkg/codegen/templates/union.tmpl +++ b/pkg/codegen/templates/union.tmpl @@ -86,6 +86,8 @@ {{end}} {{end}} + {{if not .Schema.HasAdditionalProperties}} + func (t {{.TypeName}}) MarshalJSON() ([]byte, error) { b, err := t.union.MarshalJSON() {{if ne 0 (len .Schema.Properties) -}} @@ -134,4 +136,5 @@ {{end -}} return err } + {{end}} {{end}} From ab90f1927bc5ec3e29af216d4298fbb4780ae36d Mon Sep 17 00:00:00 2001 From: Ryota Kusano <31480737+mpls104@users.noreply.github.com> Date: Sat, 17 Dec 2022 10:08:59 +0900 Subject: [PATCH 12/82] Reverse the order of the middleware when they applied in gorilla/mux implementation (#842) * Reverse the order of the middleware when they apopted in gorilla/mux implementation * Add config to keep compatibility * Rename option by omitting --- examples/petstore-expanded/gorilla/api/cfg.yaml | 2 ++ .../gorilla/api/petstore.gen.go | 16 ++++++++-------- pkg/codegen/configuration.go | 5 +++++ .../templates/gorilla/gorilla-middleware.tmpl | 6 ++++++ 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/examples/petstore-expanded/gorilla/api/cfg.yaml b/examples/petstore-expanded/gorilla/api/cfg.yaml index 7f1a2d759c..8ead7a60de 100644 --- a/examples/petstore-expanded/gorilla/api/cfg.yaml +++ b/examples/petstore-expanded/gorilla/api/cfg.yaml @@ -4,3 +4,5 @@ generate: models: true embedded-spec: true output: petstore.gen.go +compatibility: + apply-gorilla-middleware-first-to-last: true diff --git a/examples/petstore-expanded/gorilla/api/petstore.gen.go b/examples/petstore-expanded/gorilla/api/petstore.gen.go index deac9824ad..b55ecd0142 100644 --- a/examples/petstore-expanded/gorilla/api/petstore.gen.go +++ b/examples/petstore-expanded/gorilla/api/petstore.gen.go @@ -114,8 +114,8 @@ func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Reque siw.Handler.FindPets(w, r, params) } - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + handler = siw.HandlerMiddlewares[i](handler) } handler(w, r.WithContext(ctx)) @@ -129,8 +129,8 @@ func (siw *ServerInterfaceWrapper) AddPet(w http.ResponseWriter, r *http.Request siw.Handler.AddPet(w, r) } - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + handler = siw.HandlerMiddlewares[i](handler) } handler(w, r.WithContext(ctx)) @@ -155,8 +155,8 @@ func (siw *ServerInterfaceWrapper) DeletePet(w http.ResponseWriter, r *http.Requ siw.Handler.DeletePet(w, r, id) } - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + handler = siw.HandlerMiddlewares[i](handler) } handler(w, r.WithContext(ctx)) @@ -181,8 +181,8 @@ func (siw *ServerInterfaceWrapper) FindPetByID(w http.ResponseWriter, r *http.Re siw.Handler.FindPetByID(w, r, id) } - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + handler = siw.HandlerMiddlewares[i](handler) } handler(w, r.WithContext(ctx)) diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index 1400c3c740..afa4fc5020 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -69,6 +69,11 @@ type CompatibilityOptions struct { // This resolves the behavior such that middlewares are chained in the order they are invoked. // Please see https://github.com/deepmap/oapi-codegen/issues/786 ApplyChiMiddlewareFirstToLast bool `yaml:"apply-chi-middleware-first-to-last,omitempty"` + // Our generated code for gorilla/mux has historically inverted the order in which gorilla/mux middleware is + // applied such that the last invoked middleware ends up executing first in the middlewares chain + // This resolves the behavior such that middlewares are chained in the order they are invoked. + // Please see https://github.com/deepmap/oapi-codegen/issues/841 + ApplyGorillaMiddlewareFirstToLast bool `yaml:"apply-gorilla-middleware-first-to-last,omitempty"` } // OutputOptions are used to modify the output code in some way. diff --git a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl index 5150186b04..1360891137 100644 --- a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl +++ b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl @@ -177,9 +177,15 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ siw.Handler.{{.OperationId}}(w, r{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}}) } + {{if opts.Compatibility.ApplyGorillaMiddlewareFirstToLast}} + for i := len(siw.HandlerMiddlewares) -1; i >= 0; i-- { + handler = siw.HandlerMiddlewares[i](handler) + } + {{else}} for _, middleware := range siw.HandlerMiddlewares { handler = middleware(handler) } + {{end}} handler(w, r.WithContext(ctx)) } From 087e1bf0d1b9ba5e0fa753463e5567330a0c704a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Jan 2023 16:45:17 -0800 Subject: [PATCH 13/82] Bump golang.org/x/text from 0.5.0 to 0.6.0 (#921) Bumps [golang.org/x/text](https://github.com/golang/text) from 0.5.0 to 0.6.0. - [Release notes](https://github.com/golang/text/releases) - [Commits](https://github.com/golang/text/compare/v0.5.0...v0.6.0) --- updated-dependencies: - dependency-name: golang.org/x/text dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 528232e59f..5af7bf8f18 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/lestrrat-go/jwx v1.2.25 github.com/matryer/moq v0.3.0 github.com/stretchr/testify v1.8.1 - golang.org/x/text v0.5.0 + golang.org/x/text v0.6.0 golang.org/x/tools v0.4.0 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index 0f88eb052f..d0b1483428 100644 --- a/go.sum +++ b/go.sum @@ -154,8 +154,8 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w= golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= From 28269339d607cbca4f48ec7e2e97503ce861f470 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Jan 2023 16:51:25 -0800 Subject: [PATCH 14/82] Bump github.com/getkin/kin-openapi from 0.107.0 to 0.112.0 (#907) Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.107.0 to 0.112.0. - [Release notes](https://github.com/getkin/kin-openapi/releases) - [Commits](https://github.com/getkin/kin-openapi/compare/v0.107.0...v0.112.0) --- updated-dependencies: - dependency-name: github.com/getkin/kin-openapi dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 5af7bf8f18..f4b9e456a4 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module github.com/deepmap/oapi-codegen require ( github.com/apapsch/go-jsonmerge/v2 v2.0.0 - github.com/getkin/kin-openapi v0.107.0 + github.com/getkin/kin-openapi v0.112.0 github.com/gin-gonic/gin v1.8.1 github.com/go-chi/chi/v5 v5.0.8 github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219 diff --git a/go.sum b/go.sum index d0b1483428..a23d00c666 100644 --- a/go.sum +++ b/go.sum @@ -10,8 +10,8 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= -github.com/getkin/kin-openapi v0.107.0 h1:bxhL6QArW7BXQj8NjXfIJQy680NsMKd25nwhvpCXchg= -github.com/getkin/kin-openapi v0.107.0/go.mod h1:9Dhr+FasATJZjS4iOLvB0hkaxgYdulrNYm2e9epLWOo= +github.com/getkin/kin-openapi v0.112.0 h1:lnLXx3bAG53EJVI4E/w0N8i1Y/vUZUEsnrXkgnfn7/Y= +github.com/getkin/kin-openapi v0.112.0/go.mod h1:QtwUNt0PAAgIIBEvFWYfB7dfngxtAaqCX1zYHMZDeK8= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= From 40d10760c4b2793ce062fa460e29d2c3ef2633e8 Mon Sep 17 00:00:00 2001 From: Alex <1353716+alexstojda@users.noreply.github.com> Date: Tue, 17 Jan 2023 19:52:05 -0500 Subject: [PATCH 15/82] fix(gin-template): Respect ctx.Abort() (#914) Respect when c.Abort() is called in a middleware func. --- pkg/codegen/templates/gin/gin-wrappers.tmpl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/codegen/templates/gin/gin-wrappers.tmpl b/pkg/codegen/templates/gin/gin-wrappers.tmpl index b16776b815..ccd7271998 100644 --- a/pkg/codegen/templates/gin/gin-wrappers.tmpl +++ b/pkg/codegen/templates/gin/gin-wrappers.tmpl @@ -176,6 +176,9 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { for _, middleware := range siw.HandlerMiddlewares { middleware(c) + if c.isAborted() { + return + } } siw.Handler.{{.OperationId}}(c{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}}) From cc8881a9fa03f8c9e3b638bcc265a0825b562902 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Jan 2023 16:55:34 -0800 Subject: [PATCH 16/82] Bump github.com/labstack/echo/v4 from 4.9.1 to 4.10.0 (#912) Bumps [github.com/labstack/echo/v4](https://github.com/labstack/echo) from 4.9.1 to 4.10.0. - [Release notes](https://github.com/labstack/echo/releases) - [Changelog](https://github.com/labstack/echo/blob/master/CHANGELOG.md) - [Commits](https://github.com/labstack/echo/compare/v4.9.1...v4.10.0) --- updated-dependencies: - dependency-name: github.com/labstack/echo/v4 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index f4b9e456a4..1101c7a3c0 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219 github.com/google/uuid v1.3.0 github.com/gorilla/mux v1.8.0 - github.com/labstack/echo/v4 v4.9.1 + github.com/labstack/echo/v4 v4.10.0 github.com/lestrrat-go/jwx v1.2.25 github.com/matryer/moq v0.3.0 github.com/stretchr/testify v1.8.1 @@ -51,11 +51,11 @@ require ( github.com/ugorji/go/codec v1.2.7 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect - golang.org/x/crypto v0.1.0 // indirect + golang.org/x/crypto v0.2.0 // indirect golang.org/x/mod v0.7.0 // indirect - golang.org/x/net v0.3.0 // indirect + golang.org/x/net v0.4.0 // indirect golang.org/x/sys v0.3.0 // indirect - golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect + golang.org/x/time v0.2.0 // indirect golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index a23d00c666..dd1ec908ba 100644 --- a/go.sum +++ b/go.sum @@ -61,8 +61,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/labstack/echo/v4 v4.9.1 h1:GliPYSpzGKlyOhqIbG8nmHBo3i1saKWFOgh41AN3b+Y= -github.com/labstack/echo/v4 v4.9.1/go.mod h1:Pop5HLc+xoc4qhTZ1ip6C0RtP7Z+4VzRLWZZFKqbbjo= +github.com/labstack/echo/v4 v4.10.0 h1:5CiyngihEO4HXsz3vVsJn7f8xAlWwRr3aY6Ih280ZKA= +github.com/labstack/echo/v4 v4.10.0/go.mod h1:S/T/5fy/GigaXnHTkh0ZGe4LpkkQysvRjFMSUTkDRNQ= github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= @@ -133,13 +133,13 @@ github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQ github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.2.0 h1:BRXPfhNivWL5Yq0BGQ39a2sW6t44aODpfxkWjYdzewE= +golang.org/x/crypto v0.2.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.3.0 h1:VWL6FNY2bEEmsGVKabSlHu5Irp34xmMRoqb/9lF9lxk= -golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -156,8 +156,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w= -golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.2.0 h1:52I/1L54xyEQAYdtcSuxtiT84KGYTBGXwayxmIpNJhE= +golang.org/x/time v0.2.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.4.0 h1:7mTAgkunk3fr4GAloyyCasadO6h9zSsQZbwvcaIciV4= golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= From 1ea9510857688fdb4c12a97feb74b351de4bd0be Mon Sep 17 00:00:00 2001 From: marcinromaszewicz Date: Tue, 17 Jan 2023 17:09:56 -0800 Subject: [PATCH 17/82] Regenerate dirty files --- .../gin/api/petstore-server.gen.go | 12 +++++++++ internal/test/strict-server/gin/server.gen.go | 27 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/examples/petstore-expanded/gin/api/petstore-server.gen.go b/examples/petstore-expanded/gin/api/petstore-server.gen.go index abe997f618..ccd51984fd 100644 --- a/examples/petstore-expanded/gin/api/petstore-server.gen.go +++ b/examples/petstore-expanded/gin/api/petstore-server.gen.go @@ -69,6 +69,9 @@ func (siw *ServerInterfaceWrapper) FindPets(c *gin.Context) { for _, middleware := range siw.HandlerMiddlewares { middleware(c) + if c.isAborted() { + return + } } siw.Handler.FindPets(c, params) @@ -79,6 +82,9 @@ func (siw *ServerInterfaceWrapper) AddPet(c *gin.Context) { for _, middleware := range siw.HandlerMiddlewares { middleware(c) + if c.isAborted() { + return + } } siw.Handler.AddPet(c) @@ -100,6 +106,9 @@ func (siw *ServerInterfaceWrapper) DeletePet(c *gin.Context) { for _, middleware := range siw.HandlerMiddlewares { middleware(c) + if c.isAborted() { + return + } } siw.Handler.DeletePet(c, id) @@ -121,6 +130,9 @@ func (siw *ServerInterfaceWrapper) FindPetByID(c *gin.Context) { for _, middleware := range siw.HandlerMiddlewares { middleware(c) + if c.isAborted() { + return + } } siw.Handler.FindPetByID(c, id) diff --git a/internal/test/strict-server/gin/server.gen.go b/internal/test/strict-server/gin/server.gen.go index a00437d709..3ecd6bac79 100644 --- a/internal/test/strict-server/gin/server.gen.go +++ b/internal/test/strict-server/gin/server.gen.go @@ -67,6 +67,9 @@ func (siw *ServerInterfaceWrapper) JSONExample(c *gin.Context) { for _, middleware := range siw.HandlerMiddlewares { middleware(c) + if c.isAborted() { + return + } } siw.Handler.JSONExample(c) @@ -77,6 +80,9 @@ func (siw *ServerInterfaceWrapper) MultipartExample(c *gin.Context) { for _, middleware := range siw.HandlerMiddlewares { middleware(c) + if c.isAborted() { + return + } } siw.Handler.MultipartExample(c) @@ -87,6 +93,9 @@ func (siw *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(c *gin.Contex for _, middleware := range siw.HandlerMiddlewares { middleware(c) + if c.isAborted() { + return + } } siw.Handler.MultipleRequestAndResponseTypes(c) @@ -97,6 +106,9 @@ func (siw *ServerInterfaceWrapper) ReusableResponses(c *gin.Context) { for _, middleware := range siw.HandlerMiddlewares { middleware(c) + if c.isAborted() { + return + } } siw.Handler.ReusableResponses(c) @@ -107,6 +119,9 @@ func (siw *ServerInterfaceWrapper) TextExample(c *gin.Context) { for _, middleware := range siw.HandlerMiddlewares { middleware(c) + if c.isAborted() { + return + } } siw.Handler.TextExample(c) @@ -117,6 +132,9 @@ func (siw *ServerInterfaceWrapper) UnknownExample(c *gin.Context) { for _, middleware := range siw.HandlerMiddlewares { middleware(c) + if c.isAborted() { + return + } } siw.Handler.UnknownExample(c) @@ -127,6 +145,9 @@ func (siw *ServerInterfaceWrapper) UnspecifiedContentType(c *gin.Context) { for _, middleware := range siw.HandlerMiddlewares { middleware(c) + if c.isAborted() { + return + } } siw.Handler.UnspecifiedContentType(c) @@ -137,6 +158,9 @@ func (siw *ServerInterfaceWrapper) URLEncodedExample(c *gin.Context) { for _, middleware := range siw.HandlerMiddlewares { middleware(c) + if c.isAborted() { + return + } } siw.Handler.URLEncodedExample(c) @@ -195,6 +219,9 @@ func (siw *ServerInterfaceWrapper) HeadersExample(c *gin.Context) { for _, middleware := range siw.HandlerMiddlewares { middleware(c) + if c.isAborted() { + return + } } siw.Handler.HeadersExample(c, params) From 4bf4c366c0e20e3b00f9618350f1962164af3358 Mon Sep 17 00:00:00 2001 From: marcinromaszewicz Date: Tue, 17 Jan 2023 17:15:42 -0800 Subject: [PATCH 18/82] fix gin capitalization error A recent PR generated code calling ctx.isAborted(), but that should have been ctx.IsAborted() --- .../gin/api/petstore-server.gen.go | 8 ++++---- internal/test/strict-server/gin/server.gen.go | 18 +++++++++--------- pkg/codegen/templates/gin/gin-wrappers.tmpl | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/examples/petstore-expanded/gin/api/petstore-server.gen.go b/examples/petstore-expanded/gin/api/petstore-server.gen.go index ccd51984fd..3b0368db57 100644 --- a/examples/petstore-expanded/gin/api/petstore-server.gen.go +++ b/examples/petstore-expanded/gin/api/petstore-server.gen.go @@ -69,7 +69,7 @@ func (siw *ServerInterfaceWrapper) FindPets(c *gin.Context) { for _, middleware := range siw.HandlerMiddlewares { middleware(c) - if c.isAborted() { + if c.IsAborted() { return } } @@ -82,7 +82,7 @@ func (siw *ServerInterfaceWrapper) AddPet(c *gin.Context) { for _, middleware := range siw.HandlerMiddlewares { middleware(c) - if c.isAborted() { + if c.IsAborted() { return } } @@ -106,7 +106,7 @@ func (siw *ServerInterfaceWrapper) DeletePet(c *gin.Context) { for _, middleware := range siw.HandlerMiddlewares { middleware(c) - if c.isAborted() { + if c.IsAborted() { return } } @@ -130,7 +130,7 @@ func (siw *ServerInterfaceWrapper) FindPetByID(c *gin.Context) { for _, middleware := range siw.HandlerMiddlewares { middleware(c) - if c.isAborted() { + if c.IsAborted() { return } } diff --git a/internal/test/strict-server/gin/server.gen.go b/internal/test/strict-server/gin/server.gen.go index 3ecd6bac79..81b9aef138 100644 --- a/internal/test/strict-server/gin/server.gen.go +++ b/internal/test/strict-server/gin/server.gen.go @@ -67,7 +67,7 @@ func (siw *ServerInterfaceWrapper) JSONExample(c *gin.Context) { for _, middleware := range siw.HandlerMiddlewares { middleware(c) - if c.isAborted() { + if c.IsAborted() { return } } @@ -80,7 +80,7 @@ func (siw *ServerInterfaceWrapper) MultipartExample(c *gin.Context) { for _, middleware := range siw.HandlerMiddlewares { middleware(c) - if c.isAborted() { + if c.IsAborted() { return } } @@ -93,7 +93,7 @@ func (siw *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(c *gin.Contex for _, middleware := range siw.HandlerMiddlewares { middleware(c) - if c.isAborted() { + if c.IsAborted() { return } } @@ -106,7 +106,7 @@ func (siw *ServerInterfaceWrapper) ReusableResponses(c *gin.Context) { for _, middleware := range siw.HandlerMiddlewares { middleware(c) - if c.isAborted() { + if c.IsAborted() { return } } @@ -119,7 +119,7 @@ func (siw *ServerInterfaceWrapper) TextExample(c *gin.Context) { for _, middleware := range siw.HandlerMiddlewares { middleware(c) - if c.isAborted() { + if c.IsAborted() { return } } @@ -132,7 +132,7 @@ func (siw *ServerInterfaceWrapper) UnknownExample(c *gin.Context) { for _, middleware := range siw.HandlerMiddlewares { middleware(c) - if c.isAborted() { + if c.IsAborted() { return } } @@ -145,7 +145,7 @@ func (siw *ServerInterfaceWrapper) UnspecifiedContentType(c *gin.Context) { for _, middleware := range siw.HandlerMiddlewares { middleware(c) - if c.isAborted() { + if c.IsAborted() { return } } @@ -158,7 +158,7 @@ func (siw *ServerInterfaceWrapper) URLEncodedExample(c *gin.Context) { for _, middleware := range siw.HandlerMiddlewares { middleware(c) - if c.isAborted() { + if c.IsAborted() { return } } @@ -219,7 +219,7 @@ func (siw *ServerInterfaceWrapper) HeadersExample(c *gin.Context) { for _, middleware := range siw.HandlerMiddlewares { middleware(c) - if c.isAborted() { + if c.IsAborted() { return } } diff --git a/pkg/codegen/templates/gin/gin-wrappers.tmpl b/pkg/codegen/templates/gin/gin-wrappers.tmpl index ccd7271998..c34a522873 100644 --- a/pkg/codegen/templates/gin/gin-wrappers.tmpl +++ b/pkg/codegen/templates/gin/gin-wrappers.tmpl @@ -176,7 +176,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { for _, middleware := range siw.HandlerMiddlewares { middleware(c) - if c.isAborted() { + if c.IsAborted() { return } } From 4109cb5b624416f1ef18ce64c19efa08ccaa80e5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Jan 2023 17:19:11 -0800 Subject: [PATCH 19/82] Bump github.com/gin-gonic/gin from 1.8.1 to 1.8.2 (#908) Bumps [github.com/gin-gonic/gin](https://github.com/gin-gonic/gin) from 1.8.1 to 1.8.2. - [Release notes](https://github.com/gin-gonic/gin/releases) - [Changelog](https://github.com/gin-gonic/gin/blob/master/CHANGELOG.md) - [Commits](https://github.com/gin-gonic/gin/compare/v1.8.1...v1.8.2) --- updated-dependencies: - dependency-name: github.com/gin-gonic/gin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 1101c7a3c0..565c820cd4 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/deepmap/oapi-codegen require ( github.com/apapsch/go-jsonmerge/v2 v2.0.0 github.com/getkin/kin-openapi v0.112.0 - github.com/gin-gonic/gin v1.8.1 + github.com/gin-gonic/gin v1.8.2 github.com/go-chi/chi/v5 v5.0.8 github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219 github.com/google/uuid v1.3.0 @@ -44,7 +44,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/pelletier/go-toml/v2 v2.0.5 // indirect + github.com/pelletier/go-toml/v2 v2.0.6 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/objx v0.5.0 // indirect diff --git a/go.sum b/go.sum index dd1ec908ba..5988465ce8 100644 --- a/go.sum +++ b/go.sum @@ -14,8 +14,8 @@ github.com/getkin/kin-openapi v0.112.0 h1:lnLXx3bAG53EJVI4E/w0N8i1Y/vUZUEsnrXkgn github.com/getkin/kin-openapi v0.112.0/go.mod h1:QtwUNt0PAAgIIBEvFWYfB7dfngxtAaqCX1zYHMZDeK8= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= -github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= +github.com/gin-gonic/gin v1.8.2 h1:UzKToD9/PoFj/V4rvlKqTRKnQYyz8Sc1MJlv4JHPtvY= +github.com/gin-gonic/gin v1.8.2/go.mod h1:qw5AYuDrzRTnhvusDsrov+fDIxp9Dleuu12h8nfB398= github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0= github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= @@ -100,8 +100,8 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= -github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= +github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= +github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= From 2b6b326aed5d25d62efd20829241a927bd1eedfd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Jan 2023 17:21:14 -0800 Subject: [PATCH 20/82] Bump golang.org/x/tools from 0.4.0 to 0.5.0 (#920) Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.4.0 to 0.5.0. - [Release notes](https://github.com/golang/tools/releases) - [Commits](https://github.com/golang/tools/compare/v0.4.0...v0.5.0) --- updated-dependencies: - dependency-name: golang.org/x/tools dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 565c820cd4..cd07c4f427 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/matryer/moq v0.3.0 github.com/stretchr/testify v1.8.1 golang.org/x/text v0.6.0 - golang.org/x/tools v0.4.0 + golang.org/x/tools v0.5.0 gopkg.in/yaml.v2 v2.4.0 ) @@ -53,8 +53,8 @@ require ( github.com/valyala/fasttemplate v1.2.2 // indirect golang.org/x/crypto v0.2.0 // indirect golang.org/x/mod v0.7.0 // indirect - golang.org/x/net v0.4.0 // indirect - golang.org/x/sys v0.3.0 // indirect + golang.org/x/net v0.5.0 // indirect + golang.org/x/sys v0.4.0 // indirect golang.org/x/time v0.2.0 // indirect golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect google.golang.org/protobuf v1.28.1 // indirect diff --git a/go.sum b/go.sum index 5988465ce8..5fee8d8037 100644 --- a/go.sum +++ b/go.sum @@ -138,8 +138,8 @@ golang.org/x/crypto v0.2.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4 golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= -golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -149,8 +149,8 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -159,8 +159,8 @@ golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.2.0 h1:52I/1L54xyEQAYdtcSuxtiT84KGYTBGXwayxmIpNJhE= golang.org/x/time v0.2.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.4.0 h1:7mTAgkunk3fr4GAloyyCasadO6h9zSsQZbwvcaIciV4= -golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= +golang.org/x/tools v0.5.0 h1:+bSpV5HIeWkuvgaMfI3UmKRThoTA5ODJTUd8T17NO+4= +golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From f4cf8f9a570380c24c6ba03ae04b9393cf120692 Mon Sep 17 00:00:00 2001 From: ikorihn <16367098+ikorihn@users.noreply.github.com> Date: Wed, 18 Jan 2023 10:23:57 +0900 Subject: [PATCH 21/82] change error message when failed parsing date-time in deepObject (#919) --- pkg/runtime/deepobject.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/runtime/deepobject.go b/pkg/runtime/deepobject.go index f18ace374e..87e9dd9a24 100644 --- a/pkg/runtime/deepobject.go +++ b/pkg/runtime/deepobject.go @@ -245,7 +245,7 @@ func assignPathValues(dst interface{}, pathValues fieldOrValue) error { // TODO: why is this marked as an ineffassign? tm, err = time.Parse(types.DateFormat, pathValues.value) //nolint:ineffassign,staticcheck if err != nil { - return fmt.Errorf("error parsing tim as RFC3339 or 2006-01-02 time: %s", err) + return fmt.Errorf("error parsing '%s' as RFC3339 or 2006-01-02 time: %s", pathValues.value, err) } return fmt.Errorf("invalid date format: %w", err) } From 2b52cd58cf5bca58b25d8925df4b75829eb7b6fd Mon Sep 17 00:00:00 2001 From: Matthew Gabeler-Lee Date: Tue, 21 Feb 2023 13:02:06 -0500 Subject: [PATCH 22/82] fix(deps): update kin-openapi to v0.104.0 (#953) Adapt to breaking changes from v0.103.0 --- go.mod | 3 +- go.sum | 8 ++- internal/test/components/components.gen.go | 4 +- internal/test/components/components.yaml | 4 +- .../issue-grab_import_names/issue.gen.go | 12 ++-- pkg/codegen/codegen.go | 52 ++++++++++------- pkg/codegen/extension.go | 48 +++++++--------- pkg/codegen/extension_test.go | 16 ++++-- pkg/codegen/merge_schemas.go | 8 +-- pkg/codegen/operations.go | 16 +++--- pkg/codegen/prune.go | 8 ++- pkg/codegen/schema.go | 56 +++++++++---------- pkg/codegen/utils.go | 32 ++++++++--- 13 files changed, 148 insertions(+), 119 deletions(-) diff --git a/go.mod b/go.mod index cd07c4f427..5881dc76bf 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module github.com/deepmap/oapi-codegen require ( github.com/apapsch/go-jsonmerge/v2 v2.0.0 - github.com/getkin/kin-openapi v0.112.0 + github.com/getkin/kin-openapi v0.114.0 github.com/gin-gonic/gin v1.8.2 github.com/go-chi/chi/v5 v5.0.8 github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219 @@ -45,6 +45,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/pelletier/go-toml/v2 v2.0.6 // indirect + github.com/perimeterx/marshmallow v1.1.4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/objx v0.5.0 // indirect diff --git a/go.sum b/go.sum index 5fee8d8037..c3aca06740 100644 --- a/go.sum +++ b/go.sum @@ -10,8 +10,8 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= -github.com/getkin/kin-openapi v0.112.0 h1:lnLXx3bAG53EJVI4E/w0N8i1Y/vUZUEsnrXkgnfn7/Y= -github.com/getkin/kin-openapi v0.112.0/go.mod h1:QtwUNt0PAAgIIBEvFWYfB7dfngxtAaqCX1zYHMZDeK8= +github.com/getkin/kin-openapi v0.114.0 h1:ar7QiJpDdlR+zSyPjrLf8mNnpoFP/lI90XcywMCFNe8= +github.com/getkin/kin-openapi v0.114.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.8.2 h1:UzKToD9/PoFj/V4rvlKqTRKnQYyz8Sc1MJlv4JHPtvY= @@ -31,6 +31,8 @@ github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/j github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= +github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= +github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= @@ -102,6 +104,8 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwd github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= +github.com/perimeterx/marshmallow v1.1.4 h1:pZLDH9RjlLGGorbXhcaQLhfuV0pFMNfPO55FuFkxqLw= +github.com/perimeterx/marshmallow v1.1.4/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/internal/test/components/components.gen.go b/internal/test/components/components.gen.go index 4ed8b65a1e..da630a8053 100644 --- a/internal/test/components/components.gen.go +++ b/internal/test/components/components.gen.go @@ -170,7 +170,7 @@ type ObjectWithJsonField struct { Value2 json.RawMessage `json:"value2,omitempty"` } -// OneOfObject1 oneOf with references and no disciminator +// OneOfObject1 oneOf with references and no discriminator type OneOfObject1 struct { union json.RawMessage } @@ -256,7 +256,7 @@ type OneOfObject4 struct { union json.RawMessage } -// OneOfObject5 oneOf with disciminator but no mapping +// OneOfObject5 oneOf with discriminator but no mapping type OneOfObject5 struct { union json.RawMessage } diff --git a/internal/test/components/components.yaml b/internal/test/components/components.yaml index 98224ed5f6..d60c810795 100644 --- a/internal/test/components/components.yaml +++ b/internal/test/components/components.yaml @@ -208,7 +208,7 @@ components: additionalProperties: $ref: '#/components/schemas/SchemaObject' OneOfObject1: - description: oneOf with references and no disciminator + description: oneOf with references and no discriminator oneOf: - $ref: '#/components/schemas/OneOfVariant1' - $ref: '#/components/schemas/OneOfVariant2' @@ -244,7 +244,7 @@ components: - $ref: '#/components/schemas/OneOfVariant2' - $ref: '#/components/schemas/OneOfVariant3' OneOfObject5: - description: oneOf with disciminator but no mapping + description: oneOf with discriminator but no mapping oneOf: - $ref: '#/components/schemas/OneOfVariant4' - $ref: '#/components/schemas/OneOfVariant5' diff --git a/internal/test/issues/issue-grab_import_names/issue.gen.go b/internal/test/issues/issue-grab_import_names/issue.gen.go index 6378e57dfb..b9904fcde1 100644 --- a/internal/test/issues/issue-grab_import_names/issue.gen.go +++ b/internal/test/issues/issue-grab_import_names/issue.gen.go @@ -363,12 +363,12 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/3yRQWv7MAzFv4rQ2aih/fM/5DjGxu67jTHcVG08YstY6mhX8t2HnZ7KulyERPTz03sX", - "HCRmSZxMsb/MDkPaC/YXtGATY49EhA6/uGiQhD121FGHs0PJnHwO2OOGOlqjw+xtrBRc7aUxDmy17FiH", - "ErItgAUomYuvk5cd9vjM9iTSEMVHNi6K/dvt5tYr//9HsD0bK8EwBoJBkvHJCHgYhYBLkaIE+2gEh++Q", - "CUazTBCE4FMlEVx1b6qKULEj+x0XdJh8rBcvSnQYOfrmxDnXsVoJ6YDz7G51XYkf9UclqDYQlGOyEJlg", - "2VOC1j4el7OX7jVEhmOZCE5xIjj7ON2V9eDLn7LeHRbWLEm5hbDuulqaQanl4HOewtCeX1Uv6uw+b3a/", - "BDe37ycAAP//wjdd4jYCAAA=", + "H4sIAAAAAAAC/3yRzWrrQAyFX0VoPSgmudyFl6W0dN9dKWXiKPEUzw+SUpIGv3uZcVahqTdCwvrm6JwL", + "hrTP2F/Qgk2MPRIROvxi0ZAT9thRRx3ODnPh5EvAHjfU0RodFm+j1t3VPjfGga2WHesgodgCWIC5sPg6", + "edlhj89sTzk3hPjIxqLYv91ubr3y/38E27OxEgxjIBhyMj4ZAQ9jJmCRLEqwj0Zw+A6FYDQrBCETfGpO", + "BFfdm6oiVOzIfseCDpOP9eJFiQ4jR9+cOJc6VpOQDjjP7lbXlfhRf1SCagOBHJOFyATLnhK09vG4nL10", + "ryEyHGUiOMWJ4OzjdFfWg5c/Zb07FNaSk3ILYd11tTSDUsvBlzKFoT2/ql7U2X3e7H4Jbm7fTwAAAP//", + "VfuleiYCAAA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 062dc953d7..956d589329 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -201,9 +201,12 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) { var strictServerOut string if opts.Generate.Strict { - responses, err := GenerateResponseDefinitions("", spec.Components.Responses) - if err != nil { - return "", fmt.Errorf("error generation response definitions for schema: %w", err) + var responses []ResponseDefinition + if spec.Components != nil { + responses, err = GenerateResponseDefinitions("", spec.Components.Responses) + if err != nil { + return "", fmt.Errorf("error generation response definitions for schema: %w", err) + } } strictServerResponses, err := GenerateStrictResponses(t, responses) if err != nil { @@ -339,28 +342,31 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) { } func GenerateTypeDefinitions(t *template.Template, swagger *openapi3.T, ops []OperationDefinition, excludeSchemas []string) (string, error) { - schemaTypes, err := GenerateTypesForSchemas(t, swagger.Components.Schemas, excludeSchemas) - if err != nil { - return "", fmt.Errorf("error generating Go types for component schemas: %w", err) - } + var allTypes []TypeDefinition + if swagger.Components != nil { + schemaTypes, err := GenerateTypesForSchemas(t, swagger.Components.Schemas, excludeSchemas) + if err != nil { + return "", fmt.Errorf("error generating Go types for component schemas: %w", err) + } - paramTypes, err := GenerateTypesForParameters(t, swagger.Components.Parameters) - if err != nil { - return "", fmt.Errorf("error generating Go types for component parameters: %w", err) - } - allTypes := append(schemaTypes, paramTypes...) + paramTypes, err := GenerateTypesForParameters(t, swagger.Components.Parameters) + if err != nil { + return "", fmt.Errorf("error generating Go types for component parameters: %w", err) + } + allTypes = append(schemaTypes, paramTypes...) - responseTypes, err := GenerateTypesForResponses(t, swagger.Components.Responses) - if err != nil { - return "", fmt.Errorf("error generating Go types for component responses: %w", err) - } - allTypes = append(allTypes, responseTypes...) + responseTypes, err := GenerateTypesForResponses(t, swagger.Components.Responses) + if err != nil { + return "", fmt.Errorf("error generating Go types for component responses: %w", err) + } + allTypes = append(allTypes, responseTypes...) - bodyTypes, err := GenerateTypesForRequestBodies(t, swagger.Components.RequestBodies) - if err != nil { - return "", fmt.Errorf("error generating Go types for component request bodies: %w", err) + bodyTypes, err := GenerateTypesForRequestBodies(t, swagger.Components.RequestBodies) + if err != nil { + return "", fmt.Errorf("error generating Go types for component request bodies: %w", err) + } + allTypes = append(allTypes, bodyTypes...) } - allTypes = append(allTypes, bodyTypes...) // Go through all operations, and add their types to allTypes, so that we can // scan all of them for enums. Operation definitions are handled differently @@ -893,6 +899,10 @@ func OperationImports(ops []OperationDefinition) (map[string]goImport, error) { func GetTypeDefinitionsImports(swagger *openapi3.T, excludeSchemas []string) (map[string]goImport, error) { res := map[string]goImport{} + if swagger.Components == nil { + return res, nil + } + schemaImports, err := GetSchemaImports(swagger.Components.Schemas, excludeSchemas) if err != nil { return nil, err diff --git a/pkg/codegen/extension.go b/pkg/codegen/extension.go index ad91ad06b1..483d6d8142 100644 --- a/pkg/codegen/extension.go +++ b/pkg/codegen/extension.go @@ -1,7 +1,6 @@ package codegen import ( - "encoding/json" "fmt" ) @@ -22,15 +21,10 @@ const ( ) func extString(extPropValue interface{}) (string, error) { - raw, ok := extPropValue.(json.RawMessage) + str, ok := extPropValue.(string) if !ok { return "", fmt.Errorf("failed to convert type: %T", extPropValue) } - var str string - if err := json.Unmarshal(raw, &str); err != nil { - return "", fmt.Errorf("failed to unmarshal json: %w", err) - } - return str, nil } func extTypeName(extPropValue interface{}) (string, error) { @@ -42,53 +36,49 @@ func extParseGoFieldName(extPropValue interface{}) (string, error) { } func extParseOmitEmpty(extPropValue interface{}) (bool, error) { - raw, ok := extPropValue.(json.RawMessage) + omitEmpty, ok := extPropValue.(bool) if !ok { return false, fmt.Errorf("failed to convert type: %T", extPropValue) } - - var omitEmpty bool - if err := json.Unmarshal(raw, &omitEmpty); err != nil { - return false, fmt.Errorf("failed to unmarshal json: %w", err) - } - return omitEmpty, nil } func extExtraTags(extPropValue interface{}) (map[string]string, error) { - raw, ok := extPropValue.(json.RawMessage) + tagsI, ok := extPropValue.(map[string]interface{}) if !ok { return nil, fmt.Errorf("failed to convert type: %T", extPropValue) } - var tags map[string]string - if err := json.Unmarshal(raw, &tags); err != nil { - return nil, fmt.Errorf("failed to unmarshal json: %w", err) + tags := make(map[string]string, len(tagsI)) + for k, v := range tagsI { + vs, ok := v.(string) + if !ok { + return nil, fmt.Errorf("failed to convert type: %T", v) + } + tags[k] = vs } return tags, nil } func extParseGoJsonIgnore(extPropValue interface{}) (bool, error) { - raw, ok := extPropValue.(json.RawMessage) + goJsonIgnore, ok := extPropValue.(bool) if !ok { return false, fmt.Errorf("failed to convert type: %T", extPropValue) } - - var goJsonIgnore bool - if err := json.Unmarshal(raw, &goJsonIgnore); err != nil { - return false, fmt.Errorf("failed to unmarshal json: %w", err) - } - return goJsonIgnore, nil } func extParseEnumVarNames(extPropValue interface{}) ([]string, error) { - raw, ok := extPropValue.(json.RawMessage) + namesI, ok := extPropValue.([]interface{}) if !ok { return nil, fmt.Errorf("failed to convert type: %T", extPropValue) } - var names []string - if err := json.Unmarshal(raw, &names); err != nil { - return nil, fmt.Errorf("failed to unmarshal json: %w", err) + names := make([]string, len(namesI)) + for i, v := range namesI { + vs, ok := v.(string) + if !ok { + return nil, fmt.Errorf("failed to convert type: %T", v) + } + names[i] = vs } return names, nil } diff --git a/pkg/codegen/extension_test.go b/pkg/codegen/extension_test.go index 64681a604b..1d5a215639 100644 --- a/pkg/codegen/extension_test.go +++ b/pkg/codegen/extension_test.go @@ -9,7 +9,7 @@ import ( func Test_extTypeName(t *testing.T) { type args struct { - extPropValue interface{} + extPropValue json.RawMessage } tests := []struct { name string @@ -24,21 +24,27 @@ func Test_extTypeName(t *testing.T) { wantErr: false, }, { - name: "type conversion error", + name: "nil conversion error", args: args{nil}, want: "", wantErr: true, }, { - name: "json unmarshal error", - args: args{json.RawMessage("invalid json format")}, + name: "type conversion error", + args: args{json.RawMessage(`12`)}, want: "", wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := extTypeName(tt.args.extPropValue) + // kin-openapi no longer returns these as RawMessage + var extPropValue interface{} + if tt.args.extPropValue != nil { + err := json.Unmarshal(tt.args.extPropValue, &extPropValue) + assert.NoError(t, err) + } + got, err := extTypeName(extPropValue) if tt.wantErr { assert.Error(t, err) return diff --git a/pkg/codegen/merge_schemas.go b/pkg/codegen/merge_schemas.go index 466e55c549..ba5b86db51 100644 --- a/pkg/codegen/merge_schemas.go +++ b/pkg/codegen/merge_schemas.go @@ -212,11 +212,11 @@ func mergeOpenapiSchemas(s1, s2 openapi3.Schema, allOf bool) (openapi3.Schema, e if SchemaHasAdditionalProperties(&s1) && SchemaHasAdditionalProperties(&s2) { return openapi3.Schema{}, errors.New("merging two schemas with additional properties, this is unhandled") } - if s1.AdditionalProperties != nil { - result.AdditionalProperties = s1.AdditionalProperties + if s1.AdditionalProperties.Schema != nil { + result.AdditionalProperties.Schema = s1.AdditionalProperties.Schema } - if s2.AdditionalProperties != nil { - result.AdditionalProperties = s2.AdditionalProperties + if s2.AdditionalProperties.Schema != nil { + result.AdditionalProperties.Schema = s2.AdditionalProperties.Schema } // Allow discriminators for allOf merges, but disallow for one/anyOfs. diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index 314e89462d..7de40d61cc 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -126,8 +126,8 @@ func (pd ParameterDefinition) GoVariableName() string { func (pd ParameterDefinition) GoName() string { goName := pd.ParamName - if _, ok := pd.Spec.ExtensionProps.Extensions[extGoName]; ok { - if extGoFieldName, err := extParseGoFieldName(pd.Spec.ExtensionProps.Extensions[extGoName]); err == nil { + if _, ok := pd.Spec.Extensions[extGoName]; ok { + if extGoFieldName, err := extParseGoFieldName(pd.Spec.Extensions[extGoName]); err == nil { goName = extGoFieldName } } @@ -825,12 +825,12 @@ func GenerateParamsTypes(op OperationDefinition) []TypeDefinition { }) } prop := Property{ - Description: param.Spec.Description, - JsonFieldName: param.ParamName, - Required: param.Required, - Schema: pSchema, - NeedsFormTag: param.Style() == "form", - ExtensionProps: ¶m.Spec.ExtensionProps, + Description: param.Spec.Description, + JsonFieldName: param.ParamName, + Required: param.Required, + Schema: pSchema, + NeedsFormTag: param.Style() == "form", + Extensions: param.Spec.Extensions, } s.Properties = append(s.Properties, prop) } diff --git a/pkg/codegen/prune.go b/pkg/codegen/prune.go index 03df80fecd..9dc4fd8719 100644 --- a/pkg/codegen/prune.go +++ b/pkg/codegen/prune.go @@ -35,7 +35,7 @@ func walkSwagger(swagger *openapi3.T, doFn func(RefWrapper) (bool, error)) error } } - _ = walkComponents(&swagger.Components, doFn) + _ = walkComponents(swagger.Components, doFn) return nil } @@ -144,7 +144,7 @@ func walkSchemaRef(ref *openapi3.SchemaRef, doFn func(RefWrapper) (bool, error)) _ = walkSchemaRef(ref, doFn) } - _ = walkSchemaRef(ref.Value.AdditionalProperties, doFn) + _ = walkSchemaRef(ref.Value.AdditionalProperties.Schema, doFn) return nil } @@ -392,6 +392,10 @@ func findComponentRefs(swagger *openapi3.T) []string { } func removeOrphanedComponents(swagger *openapi3.T, refs []string) int { + if swagger.Components == nil { + return 0 + } + countRemoved := 0 for key := range swagger.Components.Schemas { diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 18430240db..1f10d4823e 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -75,15 +75,15 @@ func (s Schema) GetAdditionalTypeDefs() []TypeDefinition { } type Property struct { - Description string - JsonFieldName string - Schema Schema - Required bool - Nullable bool - ReadOnly bool - WriteOnly bool - NeedsFormTag bool - ExtensionProps *openapi3.ExtensionProps + Description string + JsonFieldName string + Schema Schema + Required bool + Nullable bool + ReadOnly bool + WriteOnly bool + NeedsFormTag bool + Extensions map[string]interface{} } func (p Property) GoFieldName() string { @@ -308,8 +308,8 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { // If additional properties are defined, we will override the default // above with the specific definition. - if schema.AdditionalProperties != nil { - additionalSchema, err := GenerateGoSchema(schema.AdditionalProperties, path) + if schema.AdditionalProperties.Schema != nil { + additionalSchema, err := GenerateGoSchema(schema.AdditionalProperties.Schema, path) if err != nil { return Schema{}, fmt.Errorf("error generating type for additional properties: %w", err) } @@ -379,14 +379,14 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { description = p.Value.Description } prop := Property{ - JsonFieldName: pName, - Schema: pSchema, - Required: required, - Description: description, - Nullable: p.Value.Nullable, - ReadOnly: p.Value.ReadOnly, - WriteOnly: p.Value.WriteOnly, - ExtensionProps: &p.Value.ExtensionProps, + JsonFieldName: pName, + Schema: pSchema, + Required: required, + Description: description, + Nullable: p.Value.Nullable, + ReadOnly: p.Value.ReadOnly, + WriteOnly: p.Value.WriteOnly, + Extensions: p.Value.Extensions, } outSchema.Properties = append(outSchema.Properties, prop) } @@ -422,8 +422,8 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { enumNames := enumValues for _, key := range []string{extEnumVarNames, extEnumNames} { - if _, ok := schema.ExtensionProps.Extensions[key]; ok { - if extEnumNames, err := extParseEnumVarNames(schema.ExtensionProps.Extensions[key]); err == nil { + if _, ok := schema.Extensions[key]; ok { + if extEnumNames, err := extParseEnumVarNames(schema.Extensions[key]); err == nil { enumNames = extEnumNames break } @@ -605,8 +605,8 @@ func GenFieldsFromProperties(props []Property) []string { field := "" goFieldName := p.GoFieldName() - if _, ok := p.ExtensionProps.Extensions[extGoName]; ok { - if extGoFieldName, err := extParseGoFieldName(p.ExtensionProps.Extensions[extGoName]); err == nil { + if _, ok := p.Extensions[extGoName]; ok { + if extGoFieldName, err := extParseGoFieldName(p.Extensions[extGoName]); err == nil { goFieldName = extGoFieldName } } @@ -625,8 +625,8 @@ func GenFieldsFromProperties(props []Property) []string { // Support x-omitempty overrideOmitEmpty := true - if _, ok := p.ExtensionProps.Extensions[extPropOmitEmpty]; ok { - if extOmitEmpty, err := extParseOmitEmpty(p.ExtensionProps.Extensions[extPropOmitEmpty]); err == nil { + if _, ok := p.Extensions[extPropOmitEmpty]; ok { + if extOmitEmpty, err := extParseOmitEmpty(p.Extensions[extPropOmitEmpty]); err == nil { overrideOmitEmpty = extOmitEmpty } } @@ -646,14 +646,14 @@ func GenFieldsFromProperties(props []Property) []string { } // Support x-go-json-ignore - if _, ok := p.ExtensionProps.Extensions[extPropGoJsonIgnore]; ok { - if goJsonIgnore, err := extParseGoJsonIgnore(p.ExtensionProps.Extensions[extPropGoJsonIgnore]); err == nil && goJsonIgnore { + if _, ok := p.Extensions[extPropGoJsonIgnore]; ok { + if goJsonIgnore, err := extParseGoJsonIgnore(p.Extensions[extPropGoJsonIgnore]); err == nil && goJsonIgnore { fieldTags["json"] = "-" } } // Support x-oapi-codegen-extra-tags - if extension, ok := p.ExtensionProps.Extensions[extPropExtraTags]; ok { + if extension, ok := p.Extensions[extPropExtraTags]; ok { if tags, err := extExtraTags(extension); err == nil { keys := SortedStringKeys(tags) for _, k := range keys { diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index 7526ee3bf1..c5b0e60deb 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -14,7 +14,6 @@ package codegen import ( - "encoding/json" "fmt" "go/token" "net/url" @@ -646,11 +645,11 @@ func SchemaNameToTypeName(name string) string { // you must specify an additionalProperties type // If additionalProperties it true/false, this field will be non-nil. func SchemaHasAdditionalProperties(schema *openapi3.Schema) bool { - if schema.AdditionalPropertiesAllowed != nil && *schema.AdditionalPropertiesAllowed { + if schema.AdditionalProperties.Has != nil && *schema.AdditionalProperties.Has { return true } - if schema.AdditionalProperties != nil { + if schema.AdditionalProperties.Schema != nil { return true } return false @@ -840,15 +839,30 @@ func ParseGoImportExtension(v *openapi3.SchemaRef) (*goImport, error) { goTypeImportExt := v.Value.Extensions[extPropGoImport] - if raw, ok := goTypeImportExt.(json.RawMessage); ok { - gi := goImport{} - if err := json.Unmarshal(raw, &gi); err != nil { - return nil, err + importI, ok := goTypeImportExt.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("failed to convert type: %T", goTypeImportExt) + } + + gi := goImport{} + // replicate the case-insensitive field mapping json.Unmarshal would do + for k, v := range importI { + if strings.EqualFold(k, "name") { + if vs, ok := v.(string); ok { + gi.Name = vs + } else { + return nil, fmt.Errorf("failed to convert type: %T", v) + } + } else if strings.EqualFold(k, "path") { + if vs, ok := v.(string); ok { + gi.Path = vs + } else { + return nil, fmt.Errorf("failed to convert type: %T", v) + } } - return &gi, nil } - return nil, nil + return &gi, nil } func MergeImports(dst, src map[string]goImport) { From 2d839e122ba7687a9109e005e9984b82011c203c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Mar 2023 09:17:57 -0800 Subject: [PATCH 23/82] Bump golang.org/x/tools from 0.5.0 to 0.6.0 (#964) Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.5.0 to 0.6.0. - [Release notes](https://github.com/golang/tools/releases) - [Commits](https://github.com/golang/tools/compare/v0.5.0...v0.6.0) --- updated-dependencies: - dependency-name: golang.org/x/tools dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 10 +++++----- go.sum | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 5881dc76bf..1ea0add5ba 100644 --- a/go.mod +++ b/go.mod @@ -12,8 +12,8 @@ require ( github.com/lestrrat-go/jwx v1.2.25 github.com/matryer/moq v0.3.0 github.com/stretchr/testify v1.8.1 - golang.org/x/text v0.6.0 - golang.org/x/tools v0.5.0 + golang.org/x/text v0.7.0 + golang.org/x/tools v0.6.0 gopkg.in/yaml.v2 v2.4.0 ) @@ -53,9 +53,9 @@ require ( github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect golang.org/x/crypto v0.2.0 // indirect - golang.org/x/mod v0.7.0 // indirect - golang.org/x/net v0.5.0 // indirect - golang.org/x/sys v0.4.0 // indirect + golang.org/x/mod v0.8.0 // indirect + golang.org/x/net v0.6.0 // indirect + golang.org/x/sys v0.5.0 // indirect golang.org/x/time v0.2.0 // indirect golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect google.golang.org/protobuf v1.28.1 // indirect diff --git a/go.sum b/go.sum index c3aca06740..38f267b5d2 100644 --- a/go.sum +++ b/go.sum @@ -139,11 +139,11 @@ golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.2.0 h1:BRXPfhNivWL5Yq0BGQ39a2sW6t44aODpfxkWjYdzewE= golang.org/x/crypto v0.2.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw= -golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -153,18 +153,18 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= -golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.2.0 h1:52I/1L54xyEQAYdtcSuxtiT84KGYTBGXwayxmIpNJhE= golang.org/x/time v0.2.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.5.0 h1:+bSpV5HIeWkuvgaMfI3UmKRThoTA5ODJTUd8T17NO+4= -golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 6bcd56c62bfd568eacb30a7e9254bbcc05039770 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Mar 2023 09:48:18 -0800 Subject: [PATCH 24/82] Bump golang.org/x/net from 0.5.0 to 0.7.0 (#973) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.5.0 to 0.7.0. - [Release notes](https://github.com/golang/net/releases) - [Commits](https://github.com/golang/net/compare/v0.5.0...v0.7.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 1ea0add5ba..8ac0857f3c 100644 --- a/go.mod +++ b/go.mod @@ -54,7 +54,7 @@ require ( github.com/valyala/fasttemplate v1.2.2 // indirect golang.org/x/crypto v0.2.0 // indirect golang.org/x/mod v0.8.0 // indirect - golang.org/x/net v0.6.0 // indirect + golang.org/x/net v0.7.0 // indirect golang.org/x/sys v0.5.0 // indirect golang.org/x/time v0.2.0 // indirect golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect diff --git a/go.sum b/go.sum index 38f267b5d2..72ab62e8ec 100644 --- a/go.sum +++ b/go.sum @@ -142,8 +142,8 @@ golang.org/x/crypto v0.2.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4 golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= From a5a9b6cda708224515ffa918db653eeef43692b6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Mar 2023 09:48:33 -0800 Subject: [PATCH 25/82] Bump github.com/labstack/echo/v4 from 4.10.0 to 4.10.2 (#980) Bumps [github.com/labstack/echo/v4](https://github.com/labstack/echo) from 4.10.0 to 4.10.2. - [Release notes](https://github.com/labstack/echo/releases) - [Changelog](https://github.com/labstack/echo/blob/master/CHANGELOG.md) - [Commits](https://github.com/labstack/echo/compare/v4.10.0...v4.10.2) --- updated-dependencies: - dependency-name: github.com/labstack/echo/v4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 8 ++++---- go.sum | 15 ++++++++------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index 8ac0857f3c..4aa1b1ab82 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219 github.com/google/uuid v1.3.0 github.com/gorilla/mux v1.8.0 - github.com/labstack/echo/v4 v4.10.0 + github.com/labstack/echo/v4 v4.10.2 github.com/lestrrat-go/jwx v1.2.25 github.com/matryer/moq v0.3.0 github.com/stretchr/testify v1.8.1 @@ -40,7 +40,7 @@ require ( github.com/lestrrat-go/option v1.0.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.16 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect @@ -52,11 +52,11 @@ require ( github.com/ugorji/go/codec v1.2.7 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect - golang.org/x/crypto v0.2.0 // indirect + golang.org/x/crypto v0.6.0 // indirect golang.org/x/mod v0.8.0 // indirect golang.org/x/net v0.7.0 // indirect golang.org/x/sys v0.5.0 // indirect - golang.org/x/time v0.2.0 // indirect + golang.org/x/time v0.3.0 // indirect golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 72ab62e8ec..5eda37f240 100644 --- a/go.sum +++ b/go.sum @@ -63,8 +63,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/labstack/echo/v4 v4.10.0 h1:5CiyngihEO4HXsz3vVsJn7f8xAlWwRr3aY6Ih280ZKA= -github.com/labstack/echo/v4 v4.10.0/go.mod h1:S/T/5fy/GigaXnHTkh0ZGe4LpkkQysvRjFMSUTkDRNQ= +github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M= +github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k= github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= @@ -92,8 +92,9 @@ github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -137,8 +138,8 @@ github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQ github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.2.0 h1:BRXPfhNivWL5Yq0BGQ39a2sW6t44aODpfxkWjYdzewE= -golang.org/x/crypto v0.2.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -160,8 +161,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/time v0.2.0 h1:52I/1L54xyEQAYdtcSuxtiT84KGYTBGXwayxmIpNJhE= -golang.org/x/time v0.2.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= From 3dff1e920b42845becd895fc01be6d4fe4d30fcb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Mar 2023 09:48:45 -0800 Subject: [PATCH 26/82] Bump github.com/stretchr/testify from 1.8.1 to 1.8.2 (#981) Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.8.1 to 1.8.2. - [Release notes](https://github.com/stretchr/testify/releases) - [Commits](https://github.com/stretchr/testify/compare/v1.8.1...v1.8.2) --- updated-dependencies: - dependency-name: github.com/stretchr/testify dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 4aa1b1ab82..2963a53f0a 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/labstack/echo/v4 v4.10.2 github.com/lestrrat-go/jwx v1.2.25 github.com/matryer/moq v0.3.0 - github.com/stretchr/testify v1.8.1 + github.com/stretchr/testify v1.8.2 golang.org/x/text v0.7.0 golang.org/x/tools v0.6.0 gopkg.in/yaml.v2 v2.4.0 diff --git a/go.sum b/go.sum index 5eda37f240..9b6e1035d2 100644 --- a/go.sum +++ b/go.sum @@ -126,8 +126,9 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= From 3a8047e50fbf591b7f991a3d517abbb3bac8884d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Mar 2023 09:52:25 -0800 Subject: [PATCH 27/82] Bump golang.org/x/text from 0.6.0 to 0.8.0 (#989) Bumps [golang.org/x/text](https://github.com/golang/text) from 0.6.0 to 0.8.0. - [Release notes](https://github.com/golang/text/releases) - [Commits](https://github.com/golang/text/compare/v0.6.0...v0.8.0) --- updated-dependencies: - dependency-name: golang.org/x/text dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 2963a53f0a..afa69bc3bf 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/lestrrat-go/jwx v1.2.25 github.com/matryer/moq v0.3.0 github.com/stretchr/testify v1.8.2 - golang.org/x/text v0.7.0 + golang.org/x/text v0.8.0 golang.org/x/tools v0.6.0 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index 9b6e1035d2..81809fbd8b 100644 --- a/go.sum +++ b/go.sum @@ -160,8 +160,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= From f965b623ed97b61b2f7099b421a5316649d9c053 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Mar 2023 08:53:57 -0700 Subject: [PATCH 28/82] Bump github.com/gin-gonic/gin from 1.8.2 to 1.9.0 (#1001) Bumps [github.com/gin-gonic/gin](https://github.com/gin-gonic/gin) from 1.8.2 to 1.9.0. - [Release notes](https://github.com/gin-gonic/gin/releases) - [Changelog](https://github.com/gin-gonic/gin/blob/master/CHANGELOG.md) - [Commits](https://github.com/gin-gonic/gin/compare/v1.8.2...v1.9.0) --- updated-dependencies: - dependency-name: github.com/gin-gonic/gin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 17 +++++++++++------ go.sum | 49 ++++++++++++++++++++++++++----------------------- 2 files changed, 37 insertions(+), 29 deletions(-) diff --git a/go.mod b/go.mod index afa69bc3bf..ff8f10d88f 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/deepmap/oapi-codegen require ( github.com/apapsch/go-jsonmerge/v2 v2.0.0 github.com/getkin/kin-openapi v0.114.0 - github.com/gin-gonic/gin v1.8.2 + github.com/gin-gonic/gin v1.9.0 github.com/go-chi/chi/v5 v5.0.8 github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219 github.com/google/uuid v1.3.0 @@ -18,19 +18,22 @@ require ( ) require ( + github.com/bytedance/sonic v1.8.0 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/swag v0.21.1 // indirect - github.com/go-playground/locales v0.14.0 // indirect - github.com/go-playground/universal-translator v0.18.0 // indirect - github.com/go-playground/validator/v10 v10.11.1 // indirect - github.com/goccy/go-json v0.9.11 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.11.2 // indirect + github.com/goccy/go-json v0.10.0 // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/invopop/yaml v0.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.0.9 // indirect github.com/labstack/gommon v0.4.0 // indirect github.com/leodido/go-urn v1.2.1 // indirect github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect @@ -49,9 +52,11 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/objx v0.5.0 // indirect - github.com/ugorji/go/codec v1.2.7 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.9 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect + golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect golang.org/x/crypto v0.6.0 // indirect golang.org/x/mod v0.8.0 // indirect golang.org/x/net v0.7.0 // indirect diff --git a/go.sum b/go.sum index 81809fbd8b..1cdedbff6e 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,12 @@ github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMz github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA= +github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 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= @@ -14,8 +20,8 @@ github.com/getkin/kin-openapi v0.114.0 h1:ar7QiJpDdlR+zSyPjrLf8mNnpoFP/lI90XcywM github.com/getkin/kin-openapi v0.114.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.8.2 h1:UzKToD9/PoFj/V4rvlKqTRKnQYyz8Sc1MJlv4JHPtvY= -github.com/gin-gonic/gin v1.8.2/go.mod h1:qw5AYuDrzRTnhvusDsrov+fDIxp9Dleuu12h8nfB398= +github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8= +github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k= github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0= github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= @@ -23,19 +29,18 @@ github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34 github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU= github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= -github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= -github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= -github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= -github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= -github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= +github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= -github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= +github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= 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/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= @@ -55,10 +60,10 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= +github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -107,14 +112,11 @@ github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvI github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/perimeterx/marshmallow v1.1.4 h1:pZLDH9RjlLGGorbXhcaQLhfuV0pFMNfPO55FuFkxqLw= github.com/perimeterx/marshmallow v1.1.4/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= -github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -129,15 +131,19 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= -github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU= +github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= @@ -151,7 +157,6 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -159,7 +164,6 @@ golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= @@ -177,8 +181,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= @@ -188,3 +190,4 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= From 7fd8f391cbdfa09f1a2d1d5982000ce1733e6010 Mon Sep 17 00:00:00 2001 From: Anton Telyshev Date: Tue, 14 Mar 2023 17:54:51 +0200 Subject: [PATCH 29/82] OneOf: Implicit mapping (#932) --- internal/test/components/components.gen.go | 213 ++++++++++++++++++++ internal/test/components/components.yaml | 28 +++ internal/test/components/components_test.go | 122 ++++++++++- pkg/codegen/schema.go | 16 ++ pkg/codegen/utils.go | 17 ++ pkg/codegen/utils_test.go | 14 ++ 6 files changed, 401 insertions(+), 9 deletions(-) diff --git a/internal/test/components/components.gen.go b/internal/test/components/components.gen.go index da630a8053..8dec2e5cd3 100644 --- a/internal/test/components/components.gen.go +++ b/internal/test/components/components.gen.go @@ -266,6 +266,16 @@ type OneOfObject6 struct { union json.RawMessage } +// OneOfObject61 oneOf with discriminator and partial mapping +type OneOfObject61 struct { + union json.RawMessage +} + +// OneOfObject62 oneOf with snake_case discriminator and partial snake_case mapping +type OneOfObject62 struct { + union json.RawMessage +} + // OneOfObject7 array of oneOf type OneOfObject7 = []OneOfObject7_Item @@ -337,6 +347,12 @@ type SchemaObject struct { WriteOnlyRequiredProp *int `json:"writeOnlyRequiredProp,omitempty"` } +// OneOfVariant51 defines model for one_of_variant51. +type OneOfVariant51 struct { + Discriminator string `json:"discriminator"` + Id int `json:"id"` +} + // EnumParam1 defines model for EnumParam1. type EnumParam1 string @@ -1662,6 +1678,7 @@ func (t OneOfObject5) AsOneOfVariant4() (OneOfVariant4, error) { // FromOneOfVariant4 overwrites any union data inside the OneOfObject5 as the provided OneOfVariant4 func (t *OneOfObject5) FromOneOfVariant4(v OneOfVariant4) error { + v.Discriminator = "OneOfVariant4" b, err := json.Marshal(v) t.union = b return err @@ -1669,6 +1686,7 @@ func (t *OneOfObject5) FromOneOfVariant4(v OneOfVariant4) error { // MergeOneOfVariant4 performs a merge with any union data inside the OneOfObject5, using the provided OneOfVariant4 func (t *OneOfObject5) MergeOneOfVariant4(v OneOfVariant4) error { + v.Discriminator = "OneOfVariant4" b, err := json.Marshal(v) if err != nil { return err @@ -1688,6 +1706,7 @@ func (t OneOfObject5) AsOneOfVariant5() (OneOfVariant5, error) { // FromOneOfVariant5 overwrites any union data inside the OneOfObject5 as the provided OneOfVariant5 func (t *OneOfObject5) FromOneOfVariant5(v OneOfVariant5) error { + v.Discriminator = "OneOfVariant5" b, err := json.Marshal(v) t.union = b return err @@ -1695,6 +1714,7 @@ func (t *OneOfObject5) FromOneOfVariant5(v OneOfVariant5) error { // MergeOneOfVariant5 performs a merge with any union data inside the OneOfObject5, using the provided OneOfVariant5 func (t *OneOfObject5) MergeOneOfVariant5(v OneOfVariant5) error { + v.Discriminator = "OneOfVariant5" b, err := json.Marshal(v) if err != nil { return err @@ -1713,6 +1733,21 @@ func (t OneOfObject5) Discriminator() (string, error) { return discriminator.Discriminator, err } +func (t OneOfObject5) ValueByDiscriminator() (interface{}, error) { + discriminator, err := t.Discriminator() + if err != nil { + return nil, err + } + switch discriminator { + case "OneOfVariant4": + return t.AsOneOfVariant4() + case "OneOfVariant5": + return t.AsOneOfVariant5() + default: + return nil, errors.New("unknown discriminator value: " + discriminator) + } +} + func (t OneOfObject5) MarshalJSON() ([]byte, error) { b, err := t.union.MarshalJSON() return b, err @@ -1812,6 +1847,184 @@ func (t *OneOfObject6) UnmarshalJSON(b []byte) error { return err } +// AsOneOfVariant4 returns the union data inside the OneOfObject61 as a OneOfVariant4 +func (t OneOfObject61) AsOneOfVariant4() (OneOfVariant4, error) { + var body OneOfVariant4 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromOneOfVariant4 overwrites any union data inside the OneOfObject61 as the provided OneOfVariant4 +func (t *OneOfObject61) FromOneOfVariant4(v OneOfVariant4) error { + v.Discriminator = "v4" + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeOneOfVariant4 performs a merge with any union data inside the OneOfObject61, using the provided OneOfVariant4 +func (t *OneOfObject61) MergeOneOfVariant4(v OneOfVariant4) error { + v.Discriminator = "v4" + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JsonMerge(b, t.union) + t.union = merged + return err +} + +// AsOneOfVariant5 returns the union data inside the OneOfObject61 as a OneOfVariant5 +func (t OneOfObject61) AsOneOfVariant5() (OneOfVariant5, error) { + var body OneOfVariant5 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromOneOfVariant5 overwrites any union data inside the OneOfObject61 as the provided OneOfVariant5 +func (t *OneOfObject61) FromOneOfVariant5(v OneOfVariant5) error { + v.Discriminator = "OneOfVariant5" + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeOneOfVariant5 performs a merge with any union data inside the OneOfObject61, using the provided OneOfVariant5 +func (t *OneOfObject61) MergeOneOfVariant5(v OneOfVariant5) error { + v.Discriminator = "OneOfVariant5" + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JsonMerge(b, t.union) + t.union = merged + return err +} + +func (t OneOfObject61) Discriminator() (string, error) { + var discriminator struct { + Discriminator string `json:"discriminator"` + } + err := json.Unmarshal(t.union, &discriminator) + return discriminator.Discriminator, err +} + +func (t OneOfObject61) ValueByDiscriminator() (interface{}, error) { + discriminator, err := t.Discriminator() + if err != nil { + return nil, err + } + switch discriminator { + case "OneOfVariant5": + return t.AsOneOfVariant5() + case "v4": + return t.AsOneOfVariant4() + default: + return nil, errors.New("unknown discriminator value: " + discriminator) + } +} + +func (t OneOfObject61) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *OneOfObject61) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} + +// AsOneOfVariant4 returns the union data inside the OneOfObject62 as a OneOfVariant4 +func (t OneOfObject62) AsOneOfVariant4() (OneOfVariant4, error) { + var body OneOfVariant4 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromOneOfVariant4 overwrites any union data inside the OneOfObject62 as the provided OneOfVariant4 +func (t *OneOfObject62) FromOneOfVariant4(v OneOfVariant4) error { + v.Discriminator = "variant_four" + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeOneOfVariant4 performs a merge with any union data inside the OneOfObject62, using the provided OneOfVariant4 +func (t *OneOfObject62) MergeOneOfVariant4(v OneOfVariant4) error { + v.Discriminator = "variant_four" + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JsonMerge(b, t.union) + t.union = merged + return err +} + +// AsOneOfVariant51 returns the union data inside the OneOfObject62 as a OneOfVariant51 +func (t OneOfObject62) AsOneOfVariant51() (OneOfVariant51, error) { + var body OneOfVariant51 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromOneOfVariant51 overwrites any union data inside the OneOfObject62 as the provided OneOfVariant51 +func (t *OneOfObject62) FromOneOfVariant51(v OneOfVariant51) error { + v.Discriminator = "one_of_variant51" + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeOneOfVariant51 performs a merge with any union data inside the OneOfObject62, using the provided OneOfVariant51 +func (t *OneOfObject62) MergeOneOfVariant51(v OneOfVariant51) error { + v.Discriminator = "one_of_variant51" + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JsonMerge(b, t.union) + t.union = merged + return err +} + +func (t OneOfObject62) Discriminator() (string, error) { + var discriminator struct { + Discriminator string `json:"discriminator"` + } + err := json.Unmarshal(t.union, &discriminator) + return discriminator.Discriminator, err +} + +func (t OneOfObject62) ValueByDiscriminator() (interface{}, error) { + discriminator, err := t.Discriminator() + if err != nil { + return nil, err + } + switch discriminator { + case "one_of_variant51": + return t.AsOneOfVariant51() + case "variant_four": + return t.AsOneOfVariant4() + default: + return nil, errors.New("unknown discriminator value: " + discriminator) + } +} + +func (t OneOfObject62) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *OneOfObject62) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} + // AsOneOfVariant1 returns the union data inside the OneOfObject7_Item as a OneOfVariant1 func (t OneOfObject7_Item) AsOneOfVariant1() (OneOfVariant1, error) { var body OneOfVariant1 diff --git a/internal/test/components/components.yaml b/internal/test/components/components.yaml index d60c810795..24fdf77b7e 100644 --- a/internal/test/components/components.yaml +++ b/internal/test/components/components.yaml @@ -260,6 +260,24 @@ components: mapping: v4: '#/components/schemas/OneOfVariant4' v5: '#/components/schemas/OneOfVariant5' + OneOfObject61: + description: oneOf with discriminator and partial mapping + oneOf: + - $ref: '#/components/schemas/OneOfVariant4' + - $ref: '#/components/schemas/OneOfVariant5' + discriminator: + propertyName: discriminator + mapping: + v4: '#/components/schemas/OneOfVariant4' + OneOfObject62: + description: oneOf with snake_case discriminator and partial snake_case mapping + oneOf: + - $ref: '#/components/schemas/OneOfVariant4' + - $ref: '#/components/schemas/one_of_variant51' + discriminator: + propertyName: discriminator + mapping: + variant_four: '#/components/schemas/OneOfVariant4' OneOfObject7: description: array of oneOf type: array @@ -380,6 +398,16 @@ components: required: - discriminator - id + one_of_variant51: + type: object + properties: + discriminator: + type: string + id: + type: integer + required: + - discriminator + - id OneOfVariant6: type: object properties: diff --git a/internal/test/components/components_test.go b/internal/test/components/components_test.go index e25ede26bc..7810ea20d6 100644 --- a/internal/test/components/components_test.go +++ b/internal/test/components/components_test.go @@ -9,15 +9,8 @@ import ( ) func assertJsonEqual(t *testing.T, j1 []byte, j2 []byte) { - var v1, v2 interface{} - - err := json.Unmarshal(j1, &v1) - assert.NoError(t, err) - - err = json.Unmarshal(j2, &v2) - assert.NoError(t, err) - - assert.EqualValues(t, v1, v2) + t.Helper() + assert.JSONEq(t, string(j1), string(j2)) } func TestRawJSON(t *testing.T) { @@ -152,6 +145,117 @@ func TestOneOfWithDiscriminator(t *testing.T) { assertJsonEqual(t, []byte(variant5), marshaled) } +func TestOneOfWithDiscriminator_PartialMapping(t *testing.T) { + const variant4 = `{"discriminator": "v4", "name": "123"}` + const variant5 = `{"discriminator": "OneOfVariant5", "id": 321}` + var dst OneOfObject61 + + err := json.Unmarshal([]byte(variant4), &dst) + assert.NoError(t, err) + discriminator, err := dst.Discriminator() + require.NoError(t, err) + assert.Equal(t, "v4", discriminator) + v4, err := dst.ValueByDiscriminator() + require.NoError(t, err) + assert.Equal(t, OneOfVariant4{Discriminator: "v4", Name: "123"}, v4) + + err = json.Unmarshal([]byte(variant5), &dst) + require.NoError(t, err) + discriminator, err = dst.Discriminator() + require.NoError(t, err) + assert.Equal(t, "OneOfVariant5", discriminator) + v5, err := dst.ValueByDiscriminator() + require.NoError(t, err) + assert.Equal(t, OneOfVariant5{Discriminator: "OneOfVariant5", Id: 321}, v5) + + // discriminator value will be filled by the generated code + err = dst.FromOneOfVariant4(OneOfVariant4{Name: "123"}) + require.NoError(t, err) + marshaled, err := json.Marshal(dst) + require.NoError(t, err) + assertJsonEqual(t, []byte(variant4), marshaled) + + err = dst.FromOneOfVariant5(OneOfVariant5{Id: 321}) + require.NoError(t, err) + marshaled, err = json.Marshal(dst) + require.NoError(t, err) + assertJsonEqual(t, []byte(variant5), marshaled) +} + +func TestOneOfWithDiscriminator_SchemaNameUsed(t *testing.T) { + const variant4 = `{"discriminator": "variant_four", "name": "789"}` + const variant51 = `{"discriminator": "one_of_variant51", "id": 987}` + var dst OneOfObject62 + + err := json.Unmarshal([]byte(variant4), &dst) + assert.NoError(t, err) + discriminator, err := dst.Discriminator() + require.NoError(t, err) + assert.Equal(t, "variant_four", discriminator) + v4, err := dst.ValueByDiscriminator() + require.NoError(t, err) + assert.Equal(t, OneOfVariant4{Discriminator: "variant_four", Name: "789"}, v4) + + err = json.Unmarshal([]byte(variant51), &dst) + require.NoError(t, err) + discriminator, err = dst.Discriminator() + require.NoError(t, err) + assert.Equal(t, "one_of_variant51", discriminator) + v5, err := dst.ValueByDiscriminator() + require.NoError(t, err) + assert.Equal(t, OneOfVariant51{Discriminator: "one_of_variant51", Id: 987}, v5) + + // discriminator value will be filled by the generated code + err = dst.FromOneOfVariant4(OneOfVariant4{Name: "789"}) + require.NoError(t, err) + marshaled, err := json.Marshal(dst) + require.NoError(t, err) + assertJsonEqual(t, []byte(variant4), marshaled) + + err = dst.FromOneOfVariant51(OneOfVariant51{Id: 987}) + require.NoError(t, err) + marshaled, err = json.Marshal(dst) + require.NoError(t, err) + assertJsonEqual(t, []byte(variant51), marshaled) +} + +func TestOneOfWithDiscriminator_FullImplicitMapping(t *testing.T) { + const variant4 = `{"discriminator": "OneOfVariant4", "name": "456"}` + const variant5 = `{"discriminator": "OneOfVariant5", "id": 654}` + var dst OneOfObject5 + + err := json.Unmarshal([]byte(variant4), &dst) + assert.NoError(t, err) + discriminator, err := dst.Discriminator() + require.NoError(t, err) + assert.Equal(t, "OneOfVariant4", discriminator) + v4, err := dst.ValueByDiscriminator() + require.NoError(t, err) + assert.Equal(t, OneOfVariant4{Discriminator: "OneOfVariant4", Name: "456"}, v4) + + err = json.Unmarshal([]byte(variant5), &dst) + require.NoError(t, err) + discriminator, err = dst.Discriminator() + require.NoError(t, err) + assert.Equal(t, "OneOfVariant5", discriminator) + v5, err := dst.ValueByDiscriminator() + require.NoError(t, err) + assert.Equal(t, OneOfVariant5{Discriminator: "OneOfVariant5", Id: 654}, v5) + + // discriminator value will be filled by the generated code + err = dst.FromOneOfVariant4(OneOfVariant4{Name: "456"}) + require.NoError(t, err) + marshaled, err := json.Marshal(dst) + require.NoError(t, err) + assertJsonEqual(t, []byte(variant4), marshaled) + + err = dst.FromOneOfVariant5(OneOfVariant5{Id: 654}) + require.NoError(t, err) + marshaled, err = json.Marshal(dst) + require.NoError(t, err) + assertJsonEqual(t, []byte(variant5), marshaled) +} + func TestOneOfWithFixedProperties(t *testing.T) { const variant1 = "{\"type\": \"v1\", \"name\": \"123\"}" const variant6 = "{\"type\": \"v6\", \"values\": [1, 2, 3]}" diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 1f10d4823e..252914a4b3 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -1,6 +1,7 @@ package codegen import ( + "errors" "fmt" "strings" @@ -759,15 +760,30 @@ func generateUnion(outSchema *Schema, elements openapi3.SchemaRefs, discriminato } if discriminator != nil { + if len(discriminator.Mapping) != 0 && element.Ref == "" { + return errors.New("ambiguous discriminator.mapping: please replace inlined object with $ref") + } + + // Explicit mapping. + var mapped bool for k, v := range discriminator.Mapping { if v == element.Ref { outSchema.Discriminator.Mapping[k] = elementSchema.GoType + mapped = true break } } + // Implicit mapping. + if !mapped { + outSchema.Discriminator.Mapping[RefPathToObjName(element.Ref)] = elementSchema.GoType + } } outSchema.UnionElements = append(outSchema.UnionElements, UnionElement(elementSchema.GoType)) } + if (outSchema.Discriminator != nil) && len(outSchema.Discriminator.Mapping) != len(elements) { + return errors.New("discriminator: not all schemas were mapped") + } + return nil } diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index c5b0e60deb..53ee299606 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -290,6 +290,23 @@ func StringInArray(str string, array []string) bool { return false } +// RefPathToObjName returns the name of referenced object without changes. +// +// #/components/schemas/Foo -> Foo +// #/components/parameters/Bar -> Bar +// #/components/responses/baz_baz -> baz_baz +// document.json#/Foo -> Foo +// http://deepmap.com/schemas/document.json#/objObj -> objObj +// +// Does not check refPath correctness. +func RefPathToObjName(refPath string) string { + parts := strings.Split(refPath, "/") + if len(parts) > 0 { + return parts[len(parts)-1] + } + return "" +} + // RefPathToGoType takes a $ref value and converts it to a Go typename. // #/components/schemas/Foo -> Foo // #/components/parameters/Bar -> Bar diff --git a/pkg/codegen/utils_test.go b/pkg/codegen/utils_test.go index 518e287f5e..32708f0692 100644 --- a/pkg/codegen/utils_test.go +++ b/pkg/codegen/utils_test.go @@ -432,3 +432,17 @@ func TestSchemaNameToTypeName(t *testing.T) { assert.Equal(t, want, SchemaNameToTypeName(in)) } } + +func TestRefPathToObjName(t *testing.T) { + t.Parallel() + + for in, want := range map[string]string{ + "#/components/schemas/Foo": "Foo", + "#/components/parameters/Bar": "Bar", + "#/components/responses/baz_baz": "baz_baz", + "document.json#/Foo": "Foo", + "http://deepmap.com/schemas/document.json#/objObj": "objObj", + } { + assert.Equal(t, want, RefPathToObjName(in)) + } +} From 357b712075e29198d22d0fa0603fe471e8678717 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Mar 2023 08:55:55 -0700 Subject: [PATCH 30/82] Bump golang.org/x/tools from 0.6.0 to 0.7.0 (#1002) Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.6.0 to 0.7.0. - [Release notes](https://github.com/golang/tools/releases) - [Commits](https://github.com/golang/tools/compare/v0.6.0...v0.7.0) --- updated-dependencies: - dependency-name: golang.org/x/tools dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index ff8f10d88f..12b9c9c3de 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/matryer/moq v0.3.0 github.com/stretchr/testify v1.8.2 golang.org/x/text v0.8.0 - golang.org/x/tools v0.6.0 + golang.org/x/tools v0.7.0 gopkg.in/yaml.v2 v2.4.0 ) @@ -58,9 +58,9 @@ require ( github.com/valyala/fasttemplate v1.2.2 // indirect golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect golang.org/x/crypto v0.6.0 // indirect - golang.org/x/mod v0.8.0 // indirect - golang.org/x/net v0.7.0 // indirect - golang.org/x/sys v0.5.0 // indirect + golang.org/x/mod v0.9.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect google.golang.org/protobuf v1.28.1 // indirect diff --git a/go.sum b/go.sum index 1cdedbff6e..4b24b0bb16 100644 --- a/go.sum +++ b/go.sum @@ -147,11 +147,11 @@ golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUu golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -160,8 +160,8 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= @@ -169,8 +169,8 @@ golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From f0729a4a90aba39fba89a497ebacf2504d1e912e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Mar 2023 08:56:08 -0700 Subject: [PATCH 31/82] Bump github.com/matryer/moq from 0.3.0 to 0.3.1 (#1003) Bumps [github.com/matryer/moq](https://github.com/matryer/moq) from 0.3.0 to 0.3.1. - [Release notes](https://github.com/matryer/moq/releases) - [Changelog](https://github.com/matryer/moq/blob/main/.goreleaser.yml) - [Commits](https://github.com/matryer/moq/compare/v0.3.0...v0.3.1) --- updated-dependencies: - dependency-name: github.com/matryer/moq dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 12b9c9c3de..e3364ea8f0 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/gorilla/mux v1.8.0 github.com/labstack/echo/v4 v4.10.2 github.com/lestrrat-go/jwx v1.2.25 - github.com/matryer/moq v0.3.0 + github.com/matryer/moq v0.3.1 github.com/stretchr/testify v1.8.2 golang.org/x/text v0.8.0 golang.org/x/tools v0.7.0 diff --git a/go.sum b/go.sum index 4b24b0bb16..5e5310b857 100644 --- a/go.sum +++ b/go.sum @@ -91,8 +91,8 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/matryer/moq v0.3.0 h1:4j0goF/XK3pMTc7fJB3fveuTJoQNdavRX/78vlK3Xb4= -github.com/matryer/moq v0.3.0/go.mod h1:RJ75ZZZD71hejp39j4crZLsEDszGk6iH4v4YsWFKH4s= +github.com/matryer/moq v0.3.1 h1:kLDiBJoGcusWS2BixGyTkF224aSCD8nLY24tj/NcTCs= +github.com/matryer/moq v0.3.1/go.mod h1:RJ75ZZZD71hejp39j4crZLsEDszGk6iH4v4YsWFKH4s= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= From 0d7287ef68a453f1196609001c5e27464384cbf3 Mon Sep 17 00:00:00 2001 From: reinkrul Date: Tue, 14 Mar 2023 16:57:31 +0100 Subject: [PATCH 32/82] Fix incorrect fieldname reserved keywords in path parameters (#999) --- internal/test/strict-server/chi/server.gen.go | 111 +++++++++++++++--- internal/test/strict-server/chi/server.go | 4 + .../test/strict-server/client/client.gen.go | 98 ++++++++++++++++ .../test/strict-server/echo/server.gen.go | 98 +++++++++++++--- internal/test/strict-server/echo/server.go | 4 + internal/test/strict-server/gin/server.gen.go | 107 ++++++++++++++--- internal/test/strict-server/gin/server.go | 4 + .../test/strict-server/strict-schema.yaml | 17 +++ pkg/codegen/templates/strict/strict-echo.tmpl | 3 +- pkg/codegen/templates/strict/strict-gin.tmpl | 3 +- pkg/codegen/templates/strict/strict-http.tmpl | 3 +- 11 files changed, 401 insertions(+), 51 deletions(-) diff --git a/internal/test/strict-server/chi/server.gen.go b/internal/test/strict-server/chi/server.gen.go index 124c057d2f..236277cfa6 100644 --- a/internal/test/strict-server/chi/server.gen.go +++ b/internal/test/strict-server/chi/server.gen.go @@ -34,6 +34,9 @@ type ServerInterface interface { // (POST /multiple) MultipleRequestAndResponseTypes(w http.ResponseWriter, r *http.Request) + // (GET /reserved-go-keyword-parameters/{type}) + ReservedGoKeywordParameters(w http.ResponseWriter, r *http.Request, pType string) + // (POST /reusable-responses) ReusableResponses(w http.ResponseWriter, r *http.Request) @@ -107,6 +110,32 @@ func (siw *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(w http.Respon handler.ServeHTTP(w, r.WithContext(ctx)) } +// ReservedGoKeywordParameters operation middleware +func (siw *ServerInterfaceWrapper) ReservedGoKeywordParameters(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + var err error + + // ------------- Path parameter "type" ------------- + var pType string + + err = runtime.BindStyledParameterWithLocation("simple", false, "type", runtime.ParamLocationPath, chi.URLParam(r, "type"), &pType) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "type", Err: err}) + return + } + + var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.ReservedGoKeywordParameters(w, r, pType) + }) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r.WithContext(ctx)) +} + // ReusableResponses operation middleware func (siw *ServerInterfaceWrapper) ReusableResponses(w http.ResponseWriter, r *http.Request) { ctx := r.Context() @@ -368,6 +397,9 @@ func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handl r.Group(func(r chi.Router) { r.Post(options.BaseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes) }) + r.Group(func(r chi.Router) { + r.Get(options.BaseURL+"/reserved-go-keyword-parameters/{type}", wrapper.ReservedGoKeywordParameters) + }) r.Group(func(r chi.Router) { r.Post(options.BaseURL+"/reusable-responses", wrapper.ReusableResponses) }) @@ -553,6 +585,24 @@ func (response MultipleRequestAndResponseTypes400Response) VisitMultipleRequestA return nil } +type ReservedGoKeywordParametersRequestObject struct { + Type string `json:"type"` +} + +type ReservedGoKeywordParametersResponseObject interface { + VisitReservedGoKeywordParametersResponse(w http.ResponseWriter) error +} + +type ReservedGoKeywordParameters200TextResponse string + +func (response ReservedGoKeywordParameters200TextResponse) VisitReservedGoKeywordParametersResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "text/plain") + w.WriteHeader(200) + + _, err := w.Write([]byte(response)) + return err +} + type ReusableResponsesRequestObject struct { Body *ReusableResponsesJSONRequestBody } @@ -820,6 +870,9 @@ type StrictServerInterface interface { // (POST /multiple) MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, error) + // (GET /reserved-go-keyword-parameters/{type}) + ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) + // (POST /reusable-responses) ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error) @@ -996,6 +1049,32 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(w http.ResponseWriter, } } +// ReservedGoKeywordParameters operation middleware +func (sh *strictHandler) ReservedGoKeywordParameters(w http.ResponseWriter, r *http.Request, pType string) { + var request ReservedGoKeywordParametersRequestObject + + request.Type = pType + + handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { + return sh.ssi.ReservedGoKeywordParameters(ctx, request.(ReservedGoKeywordParametersRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "ReservedGoKeywordParameters") + } + + response, err := handler(r.Context(), w, r, request) + + if err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } else if validResponse, ok := response.(ReservedGoKeywordParametersResponseObject); ok { + if err := validResponse.VisitReservedGoKeywordParametersResponse(w); err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } + } else if response != nil { + sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("Unexpected response type: %T", response)) + } +} + // ReusableResponses operation middleware func (sh *strictHandler) ReusableResponses(w http.ResponseWriter, r *http.Request) { var request ReusableResponsesRequestObject @@ -1184,21 +1263,23 @@ func (sh *strictHandler) HeadersExample(w http.ResponseWriter, r *http.Request, // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", + "AP//O0NNuucUAAA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/chi/server.go b/internal/test/strict-server/chi/server.go index 5b7026809e..b0724db19f 100644 --- a/internal/test/strict-server/chi/server.go +++ b/internal/test/strict-server/chi/server.go @@ -100,3 +100,7 @@ func (s StrictServer) HeadersExample(ctx context.Context, request HeadersExample func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error) { return ReusableResponses200JSONResponse{ReusableresponseJSONResponse: ReusableresponseJSONResponse{Body: *request.Body}}, nil } + +func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) { + return ReservedGoKeywordParameters200TextResponse(""), nil +} diff --git a/internal/test/strict-server/client/client.gen.go b/internal/test/strict-server/client/client.gen.go index 68105f2f24..5ec0210b50 100644 --- a/internal/test/strict-server/client/client.gen.go +++ b/internal/test/strict-server/client/client.gen.go @@ -156,6 +156,9 @@ type ClientInterface interface { MultipleRequestAndResponseTypesWithTextBody(ctx context.Context, body MultipleRequestAndResponseTypesTextRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + // ReservedGoKeywordParameters request + ReservedGoKeywordParameters(ctx context.Context, pType string, reqEditors ...RequestEditorFn) (*http.Response, error) + // ReusableResponses request with any body ReusableResponsesWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -267,6 +270,18 @@ func (c *Client) MultipleRequestAndResponseTypesWithTextBody(ctx context.Context return c.Client.Do(req) } +func (c *Client) ReservedGoKeywordParameters(ctx context.Context, pType string, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewReservedGoKeywordParametersRequest(c.Server, pType) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + func (c *Client) ReusableResponsesWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { req, err := NewReusableResponsesRequestWithBody(c.Server, contentType, body) if err != nil { @@ -514,6 +529,40 @@ func NewMultipleRequestAndResponseTypesRequestWithBody(server string, contentTyp return req, nil } +// NewReservedGoKeywordParametersRequest generates requests for ReservedGoKeywordParameters +func NewReservedGoKeywordParametersRequest(server string, pType string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "type", runtime.ParamLocationPath, pType) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/reserved-go-keyword-parameters/%s", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + // NewReusableResponsesRequest calls the generic ReusableResponses builder with application/json body func NewReusableResponsesRequest(server string, body ReusableResponsesJSONRequestBody) (*http.Request, error) { var bodyReader io.Reader @@ -808,6 +857,9 @@ type ClientWithResponsesInterface interface { MultipleRequestAndResponseTypesWithTextBodyWithResponse(ctx context.Context, body MultipleRequestAndResponseTypesTextRequestBody, reqEditors ...RequestEditorFn) (*MultipleRequestAndResponseTypesResponse, error) + // ReservedGoKeywordParameters request + ReservedGoKeywordParametersWithResponse(ctx context.Context, pType string, reqEditors ...RequestEditorFn) (*ReservedGoKeywordParametersResponse, error) + // ReusableResponses request with any body ReusableResponsesWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*ReusableResponsesResponse, error) @@ -900,6 +952,27 @@ func (r MultipleRequestAndResponseTypesResponse) StatusCode() int { return 0 } +type ReservedGoKeywordParametersResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r ReservedGoKeywordParametersResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r ReservedGoKeywordParametersResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + type ReusableResponsesResponse struct { Body []byte HTTPResponse *http.Response @@ -1087,6 +1160,15 @@ func (c *ClientWithResponses) MultipleRequestAndResponseTypesWithTextBodyWithRes return ParseMultipleRequestAndResponseTypesResponse(rsp) } +// ReservedGoKeywordParametersWithResponse request returning *ReservedGoKeywordParametersResponse +func (c *ClientWithResponses) ReservedGoKeywordParametersWithResponse(ctx context.Context, pType string, reqEditors ...RequestEditorFn) (*ReservedGoKeywordParametersResponse, error) { + rsp, err := c.ReservedGoKeywordParameters(ctx, pType, reqEditors...) + if err != nil { + return nil, err + } + return ParseReservedGoKeywordParametersResponse(rsp) +} + // ReusableResponsesWithBodyWithResponse request with arbitrary body returning *ReusableResponsesResponse func (c *ClientWithResponses) ReusableResponsesWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*ReusableResponsesResponse, error) { rsp, err := c.ReusableResponsesWithBody(ctx, contentType, body, reqEditors...) @@ -1244,6 +1326,22 @@ func ParseMultipleRequestAndResponseTypesResponse(rsp *http.Response) (*Multiple return response, nil } +// ParseReservedGoKeywordParametersResponse parses an HTTP response from a ReservedGoKeywordParametersWithResponse call +func ParseReservedGoKeywordParametersResponse(rsp *http.Response) (*ReservedGoKeywordParametersResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &ReservedGoKeywordParametersResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + // ParseReusableResponsesResponse parses an HTTP response from a ReusableResponsesWithResponse call func ParseReusableResponsesResponse(rsp *http.Response) (*ReusableResponsesResponse, error) { bodyBytes, err := io.ReadAll(rsp.Body) diff --git a/internal/test/strict-server/echo/server.gen.go b/internal/test/strict-server/echo/server.gen.go index 46531bd8a4..ebd374b9f1 100644 --- a/internal/test/strict-server/echo/server.gen.go +++ b/internal/test/strict-server/echo/server.gen.go @@ -34,6 +34,9 @@ type ServerInterface interface { // (POST /multiple) MultipleRequestAndResponseTypes(ctx echo.Context) error + // (GET /reserved-go-keyword-parameters/{type}) + ReservedGoKeywordParameters(ctx echo.Context, pType string) error + // (POST /reusable-responses) ReusableResponses(ctx echo.Context) error @@ -85,6 +88,22 @@ func (w *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(ctx echo.Contex return err } +// ReservedGoKeywordParameters converts echo context to params. +func (w *ServerInterfaceWrapper) ReservedGoKeywordParameters(ctx echo.Context) error { + var err error + // ------------- Path parameter "type" ------------- + var pType string + + err = runtime.BindStyledParameterWithLocation("simple", false, "type", runtime.ParamLocationPath, ctx.Param("type"), &pType) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter type: %s", err)) + } + + // Invoke the callback with all the unmarshalled arguments + err = w.Handler.ReservedGoKeywordParameters(ctx, pType) + return err +} + // ReusableResponses converts echo context to params. func (w *ServerInterfaceWrapper) ReusableResponses(ctx echo.Context) error { var err error @@ -207,6 +226,7 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL router.POST(baseURL+"/json", wrapper.JSONExample) router.POST(baseURL+"/multipart", wrapper.MultipartExample) router.POST(baseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes) + router.GET(baseURL+"/reserved-go-keyword-parameters/:type", wrapper.ReservedGoKeywordParameters) router.POST(baseURL+"/reusable-responses", wrapper.ReusableResponses) router.POST(baseURL+"/text", wrapper.TextExample) router.POST(baseURL+"/unknown", wrapper.UnknownExample) @@ -379,6 +399,24 @@ func (response MultipleRequestAndResponseTypes400Response) VisitMultipleRequestA return nil } +type ReservedGoKeywordParametersRequestObject struct { + Type string `json:"type"` +} + +type ReservedGoKeywordParametersResponseObject interface { + VisitReservedGoKeywordParametersResponse(w http.ResponseWriter) error +} + +type ReservedGoKeywordParameters200TextResponse string + +func (response ReservedGoKeywordParameters200TextResponse) VisitReservedGoKeywordParametersResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "text/plain") + w.WriteHeader(200) + + _, err := w.Write([]byte(response)) + return err +} + type ReusableResponsesRequestObject struct { Body *ReusableResponsesJSONRequestBody } @@ -646,6 +684,9 @@ type StrictServerInterface interface { // (POST /multiple) MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, error) + // (GET /reserved-go-keyword-parameters/{type}) + ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) + // (POST /reusable-responses) ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error) @@ -796,6 +837,31 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx echo.Context) error return nil } +// ReservedGoKeywordParameters operation middleware +func (sh *strictHandler) ReservedGoKeywordParameters(ctx echo.Context, pType string) error { + var request ReservedGoKeywordParametersRequestObject + + request.Type = pType + + handler := func(ctx echo.Context, request interface{}) (interface{}, error) { + return sh.ssi.ReservedGoKeywordParameters(ctx.Request().Context(), request.(ReservedGoKeywordParametersRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "ReservedGoKeywordParameters") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(ReservedGoKeywordParametersResponseObject); ok { + return validResponse.VisitReservedGoKeywordParametersResponse(ctx.Response()) + } else if response != nil { + return fmt.Errorf("Unexpected response type: %T", response) + } + return nil +} + // ReusableResponses operation middleware func (sh *strictHandler) ReusableResponses(ctx echo.Context) error { var request ReusableResponsesRequestObject @@ -974,21 +1040,23 @@ func (sh *strictHandler) HeadersExample(ctx echo.Context, params HeadersExampleP // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/+xYS4/iOBD+K1btnkaB0D194rbTGmnfI9Ezp9UcirgAzya2166QRoj/vnJsaBjSCFo8", - "pNXeEqde/qq+KsdLKExljSbNHoZLcOSt0Z7alzFKR//U5Dm8SfKFU5aV0TCEDyhH6dsqA0e1x3FJa/Ug", - "XxjNpFtVtLZUBQbV/JsP+kvwxYwqDE8/OprAEH7IX0LJ41ef0zNWtiRYrVbZdxF8+g0ymBFKcm208fFu", - "1zYvLMEQPDulpxCMRLH7TjGlmabkgrcgmoIIAus4hkuwzlhyrCJGcyxr6vaUVsz4GxUcd6D0xOxj+Wg0", - "o9JeSDWZkCPNIoEngg0vfG2tcUxSjBcieChYeHJzcpABKw6BwdP2ukgBe8hgTs5HR3f9QX8Q8mUsabQK", - "hvC+XcrAIs/aDW0SZE1X3n99+vSnUF5gzaZCVgWW5UJU6PwMy5KkUJpNiLEu2PehdeXazP8ik/rHhGUo", - "m7aCPhi5uETFtIW5Vc/3g8GVCnOVwUN01mVjE1S+xbDWzATrsgP0L/pvbRotyDnj0s7yqi5ZWXS8naxd", - "tP9YixwD+cZePjGu6klkvBDq5/J0U+BTM+gkydPMNF7MTCPYCElYikbxTKwVv2O30gKFV3paklgHlXVm", - "sqTUc3/ScpT28jnYuDiXsh0rz72maXpt8mpXki6MJPk2s6rCKeVWT3fVg21kGMJ4waFs97vrmYooA6Zn", - "zm2JSh8eHVdqJ/8jfTZiR7quzya9neR1E3dNKi8K1GIc+DjxgcRdvvZIOkqeRlsStxlxhzHaO61do2uG", - "5L8+qT7T81FD6oxkvXY1ngpYHRdfxyxpHQPbG7l/BIpzJcnklX040fLNQPWWCjVRJHtpF70Y22st4dHo", - "whHvDu1wAtaGxcZYOJjzjEREIBPeiIZEVXsWFr0XitsuUqp4uJe01zy+vET2GD2FyX5EVt9dKKfvbpXR", - "h8Hd6SrvL1w3O8P3FT6Ofv8YZU79wznblD/xjHI+vzeiczhW97buALop/HMUeJnpBak5SYFaCkdcO01S", - "zBWuf1v3uJkMvKTVosOKuPX61xLCCEkXC5CBxoo273epCJQLyLKrKTt0PXHQ1j1kh+4svv6Hf6gvedNz", - "6TpdZRAvZWKx1K4MGWW2wzyPlzl93+B0Sq6vTI5Wwerr6t8AAAD//ygSomqZEwAA", + "H4sIAAAAAAAC/+xYX2/bNhD/KgS3p0KynDRPeluDotu6rYOTPg15oMWzzFYiuePJimHouw8UJf+pFS/O", + "7BgY+mbRd787/u4Pj1zxzJTWaNDkeLriCM4a7aD9mAqJ8HcFjvyXBJehsqSM5il/J+Sk+6+JOELlxLSA", + "Xt3LZ0YT6FZVWFuoTHjV5Ivz+ivusjmUwv/6EWHGU/5DsnElCf+6BB5FaQvgTdNE33jw6SOP+ByEBGy9", + "DT+vdrFpaYGn3BEqnXMPEsSuB8WUJsgBvTUv2jnhBXo/0hW3aCwgqcDRQhQVDFvqVsz0C2QUdqD0zOxz", + "eWs0CaUdk2o2AwRNrCOPeQzHXGWtQQLJpkvmLWTEHOACkEecFHnH+N32OuscdjziC0AXDF2NxqOxj5ex", + "oIVVPOVv26WIW0HzdkPrAFkzFPdf7z79wZRjoiJTClKZKIolKwW6uSgKkExpMt7HKiM34q0pbCP/i+zU", + "33dc+rRpM+idkctzZEybmFv5fD0ev1JiNhG/CcaGMNZOJVsV1sLMRFUMkP5Zf9Wm1gwQDXY7S8qqIGUF", + "0nawdtn+vRd5DuVrvGRmsIylIHEm1k9l6aLEd81gsEju5qZ2bG5qRoZJEAWrFc1Zr/hNdSvNBHNK5wWw", + "3qloMJIFdD33Jy0n3V7uPcbZaynaQXmM67qO2+BVWIDOjAT5MlhVihwSq/NddY8tiKd8uiSftvvd9URJ", + "FHGCR0psIZQ+fHS8Ujv5zvTJCjuUK0J7JMo4N/FXWNYGZWwFihII0CUrb73xwDkMlPKfa0mWCc2mwLQo", + "QTIxI0D2wbAO0u2V7KSz+8F8DCIbqPa8XX+kf624p6Q9g3nEvQGeBlZCXSv0QSesIDpA28O/5ud/CkDP", + "Zpj04h1Tw22wb1Fr6hBmzrfEocgN8BcsTbYkLjMwHM64vdn3Nc4gH8mnz/17eHzWkX/C1vfatX0sYVVY", + "fJqzTus5tL2wkz6DxYWSYJLS3hyJfDFSnYVMzRTIuNtFHHx7qiXcGp0h0O4I5O8T2hBbg/lrDs2BBQYi", + "5gyrgZWVI2aFc0xR20UKFa5KEvaax+eNZ7fB0v2mnR6K6pszxfTNpSJ6M746XuXtmfNmZ5R5oh4nv70P", + "MsfeF082Mx058Z3O7oXK2V9S4q0XleES/jkIbM70DNTCT0RaMgSqUINkCyX6R4C92uwANmEdmoWCG5tp", + "qH/dOWYgig5iXfPo0AvQw//4eeKc72bnztMm4uGJKyRLhYWPKJFNkyQ8jY1cLfIccKRMIqzizUPzTwAA", + "AP//O0NNuucUAAA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/echo/server.go b/internal/test/strict-server/echo/server.go index 5b7026809e..b0724db19f 100644 --- a/internal/test/strict-server/echo/server.go +++ b/internal/test/strict-server/echo/server.go @@ -100,3 +100,7 @@ func (s StrictServer) HeadersExample(ctx context.Context, request HeadersExample func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error) { return ReusableResponses200JSONResponse{ReusableresponseJSONResponse: ReusableresponseJSONResponse{Body: *request.Body}}, nil } + +func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) { + return ReservedGoKeywordParameters200TextResponse(""), nil +} diff --git a/internal/test/strict-server/gin/server.gen.go b/internal/test/strict-server/gin/server.gen.go index 81b9aef138..618db709a2 100644 --- a/internal/test/strict-server/gin/server.gen.go +++ b/internal/test/strict-server/gin/server.gen.go @@ -34,6 +34,9 @@ type ServerInterface interface { // (POST /multiple) MultipleRequestAndResponseTypes(c *gin.Context) + // (GET /reserved-go-keyword-parameters/{type}) + ReservedGoKeywordParameters(c *gin.Context, pType string) + // (POST /reusable-responses) ReusableResponses(c *gin.Context) @@ -101,6 +104,30 @@ func (siw *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(c *gin.Contex siw.Handler.MultipleRequestAndResponseTypes(c) } +// ReservedGoKeywordParameters operation middleware +func (siw *ServerInterfaceWrapper) ReservedGoKeywordParameters(c *gin.Context) { + + var err error + + // ------------- Path parameter "type" ------------- + var pType string + + err = runtime.BindStyledParameter("simple", false, "type", c.Param("type"), &pType) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter type: %s", err), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.ReservedGoKeywordParameters(c, pType) +} + // ReusableResponses operation middleware func (siw *ServerInterfaceWrapper) ReusableResponses(c *gin.Context) { @@ -257,6 +284,7 @@ func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options router.POST(options.BaseURL+"/json", wrapper.JSONExample) router.POST(options.BaseURL+"/multipart", wrapper.MultipartExample) router.POST(options.BaseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes) + router.GET(options.BaseURL+"/reserved-go-keyword-parameters/:type", wrapper.ReservedGoKeywordParameters) router.POST(options.BaseURL+"/reusable-responses", wrapper.ReusableResponses) router.POST(options.BaseURL+"/text", wrapper.TextExample) router.POST(options.BaseURL+"/unknown", wrapper.UnknownExample) @@ -428,6 +456,24 @@ func (response MultipleRequestAndResponseTypes400Response) VisitMultipleRequestA return nil } +type ReservedGoKeywordParametersRequestObject struct { + Type string `json:"type"` +} + +type ReservedGoKeywordParametersResponseObject interface { + VisitReservedGoKeywordParametersResponse(w http.ResponseWriter) error +} + +type ReservedGoKeywordParameters200TextResponse string + +func (response ReservedGoKeywordParameters200TextResponse) VisitReservedGoKeywordParametersResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "text/plain") + w.WriteHeader(200) + + _, err := w.Write([]byte(response)) + return err +} + type ReusableResponsesRequestObject struct { Body *ReusableResponsesJSONRequestBody } @@ -695,6 +741,9 @@ type StrictServerInterface interface { // (POST /multiple) MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, error) + // (GET /reserved-go-keyword-parameters/{type}) + ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) + // (POST /reusable-responses) ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error) @@ -856,6 +905,32 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx *gin.Context) { } } +// ReservedGoKeywordParameters operation middleware +func (sh *strictHandler) ReservedGoKeywordParameters(ctx *gin.Context, pType string) { + var request ReservedGoKeywordParametersRequestObject + + request.Type = pType + + handler := func(ctx *gin.Context, request interface{}) (interface{}, error) { + return sh.ssi.ReservedGoKeywordParameters(ctx, request.(ReservedGoKeywordParametersRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "ReservedGoKeywordParameters") + } + + response, err := handler(ctx, request) + + if err != nil { + ctx.Error(err) + } else if validResponse, ok := response.(ReservedGoKeywordParametersResponseObject); ok { + if err := validResponse.VisitReservedGoKeywordParametersResponse(ctx.Writer); err != nil { + ctx.Error(err) + } + } else if response != nil { + ctx.Error(fmt.Errorf("Unexpected response type: %T", response)) + } +} + // ReusableResponses operation middleware func (sh *strictHandler) ReusableResponses(ctx *gin.Context) { var request ReusableResponsesRequestObject @@ -1046,21 +1121,23 @@ func (sh *strictHandler) HeadersExample(ctx *gin.Context, params HeadersExampleP // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", + "AP//O0NNuucUAAA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/gin/server.go b/internal/test/strict-server/gin/server.go index 5b7026809e..b0724db19f 100644 --- a/internal/test/strict-server/gin/server.go +++ b/internal/test/strict-server/gin/server.go @@ -100,3 +100,7 @@ func (s StrictServer) HeadersExample(ctx context.Context, request HeadersExample func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error) { return ReusableResponses200JSONResponse{ReusableresponseJSONResponse: ReusableresponseJSONResponse{Body: *request.Body}}, nil } + +func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) { + return ReservedGoKeywordParameters200TextResponse(""), nil +} diff --git a/internal/test/strict-server/strict-schema.yaml b/internal/test/strict-server/strict-schema.yaml index a9a2c41097..da0ed07a74 100644 --- a/internal/test/strict-server/strict-schema.yaml +++ b/internal/test/strict-server/strict-schema.yaml @@ -228,6 +228,23 @@ paths: $ref: "#/components/responses/badrequest" default: description: Unknown error + /reserved-go-keyword-parameters/{type}: + get: + operationId: ReservedGoKeywordParameters + description: Parameters can be named after Go keywords + parameters: + - name: type + in: path + required: true + schema: + type: string + responses: + 200: + description: OK + content: + text/plain: + schema: + type: string components: responses: badrequest: diff --git a/pkg/codegen/templates/strict/strict-echo.tmpl b/pkg/codegen/templates/strict/strict-echo.tmpl index c858c09f8e..4bd6aec5d5 100644 --- a/pkg/codegen/templates/strict/strict-echo.tmpl +++ b/pkg/codegen/templates/strict/strict-echo.tmpl @@ -18,8 +18,7 @@ type strictHandler struct { var request {{$opid | ucFirst}}RequestObject {{range .PathParams -}} - {{$varName := .GoVariableName -}} - request.{{$varName | ucFirst}} = {{$varName}} + request.{{.GoName}} = {{.GoVariableName}} {{end -}} {{if .RequiresParamObject -}} diff --git a/pkg/codegen/templates/strict/strict-gin.tmpl b/pkg/codegen/templates/strict/strict-gin.tmpl index 8097e2801c..9622fb2915 100644 --- a/pkg/codegen/templates/strict/strict-gin.tmpl +++ b/pkg/codegen/templates/strict/strict-gin.tmpl @@ -18,8 +18,7 @@ type strictHandler struct { var request {{$opid | ucFirst}}RequestObject {{range .PathParams -}} - {{$varName := .GoVariableName -}} - request.{{$varName | ucFirst}} = {{$varName}} + request.{{.GoName}} = {{.GoVariableName}} {{end -}} {{if .RequiresParamObject -}} diff --git a/pkg/codegen/templates/strict/strict-http.tmpl b/pkg/codegen/templates/strict/strict-http.tmpl index b1d2e9dba4..d04503dbc5 100644 --- a/pkg/codegen/templates/strict/strict-http.tmpl +++ b/pkg/codegen/templates/strict/strict-http.tmpl @@ -35,8 +35,7 @@ type strictHandler struct { var request {{$opid | ucFirst}}RequestObject {{range .PathParams -}} - {{$varName := .GoVariableName -}} - request.{{$varName | ucFirst}} = {{$varName}} + request.{{.GoName}} = {{.GoVariableName}} {{end -}} {{if .RequiresParamObject -}} From ffe428be7df3e65f29a1f26e30e7c07eeb3bede4 Mon Sep 17 00:00:00 2001 From: Alex Mammay Date: Tue, 14 Mar 2023 11:59:23 -0400 Subject: [PATCH 33/82] issue958 (#959) --- internal/test/issues/issue-958/config.yaml | 8 + internal/test/issues/issue-958/doc.go | 3 + internal/test/issues/issue-958/issue.gen.go | 234 ++++++++++++++++++ .../test/issues/issue-958/pkga/config.yaml | 9 + internal/test/issues/issue-958/pkga/doc.go | 3 + .../issues/issue-958/pkga/responses.gen.go | 21 ++ internal/test/issues/issue-958/pkga/spec.yaml | 45 ++++ internal/test/issues/issue-958/spec.yaml | 14 ++ 8 files changed, 337 insertions(+) create mode 100644 internal/test/issues/issue-958/config.yaml create mode 100644 internal/test/issues/issue-958/doc.go create mode 100644 internal/test/issues/issue-958/issue.gen.go create mode 100644 internal/test/issues/issue-958/pkga/config.yaml create mode 100644 internal/test/issues/issue-958/pkga/doc.go create mode 100644 internal/test/issues/issue-958/pkga/responses.gen.go create mode 100644 internal/test/issues/issue-958/pkga/spec.yaml create mode 100644 internal/test/issues/issue-958/spec.yaml diff --git a/internal/test/issues/issue-958/config.yaml b/internal/test/issues/issue-958/config.yaml new file mode 100644 index 0000000000..1cf2e1966b --- /dev/null +++ b/internal/test/issues/issue-958/config.yaml @@ -0,0 +1,8 @@ +package: issue958 +generate: + client: true +output: issue.gen.go +output-options: + skip-prune: true +import-mapping: + ./pkga/spec.yaml: github.com/deepmap/oapi-codegen/internal/test/issues/issue-958/pkga diff --git a/internal/test/issues/issue-958/doc.go b/internal/test/issues/issue-958/doc.go new file mode 100644 index 0000000000..3be1f22d5e --- /dev/null +++ b/internal/test/issues/issue-958/doc.go @@ -0,0 +1,3 @@ +package issue958 + +//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml spec.yaml diff --git a/internal/test/issues/issue-958/issue.gen.go b/internal/test/issues/issue-958/issue.gen.go new file mode 100644 index 0000000000..088b3f60b8 --- /dev/null +++ b/internal/test/issues/issue-958/issue.gen.go @@ -0,0 +1,234 @@ +// Package issue958 provides primitives to interact with the openapi HTTP API. +// +// Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT. +package issue958 + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "strings" +) + +// RequestEditorFn is the function signature for the RequestEditor callback function +type RequestEditorFn func(ctx context.Context, req *http.Request) error + +// Doer performs HTTP requests. +// +// The standard http.Client implements this interface. +type HttpRequestDoer interface { + Do(req *http.Request) (*http.Response, error) +} + +// Client which conforms to the OpenAPI3 specification for this service. +type Client struct { + // The endpoint of the server conforming to this interface, with scheme, + // https://api.deepmap.com for example. This can contain a path relative + // to the server, such as https://api.deepmap.com/dev-test, and all the + // paths in the swagger spec will be appended to the server. + Server string + + // Doer for performing requests, typically a *http.Client with any + // customized settings, such as certificate chains. + Client HttpRequestDoer + + // A list of callbacks for modifying requests which are generated before sending over + // the network. + RequestEditors []RequestEditorFn +} + +// ClientOption allows setting custom parameters during construction +type ClientOption func(*Client) error + +// Creates a new Client, with reasonable defaults +func NewClient(server string, opts ...ClientOption) (*Client, error) { + // create a client with sane default values + client := Client{ + Server: server, + } + // mutate client and add all optional params + for _, o := range opts { + if err := o(&client); err != nil { + return nil, err + } + } + // ensure the server URL always has a trailing slash + if !strings.HasSuffix(client.Server, "/") { + client.Server += "/" + } + // create httpClient, if not already present + if client.Client == nil { + client.Client = &http.Client{} + } + return &client, nil +} + +// WithHTTPClient allows overriding the default Doer, which is +// automatically created using http.Client. This is useful for tests. +func WithHTTPClient(doer HttpRequestDoer) ClientOption { + return func(c *Client) error { + c.Client = doer + return nil + } +} + +// WithRequestEditorFn allows setting up a callback function, which will be +// called right before sending the request. This can be used to mutate the request. +func WithRequestEditorFn(fn RequestEditorFn) ClientOption { + return func(c *Client) error { + c.RequestEditors = append(c.RequestEditors, fn) + return nil + } +} + +// The interface specification for the client above. +type ClientInterface interface { + // ExampleGet request + ExampleGet(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) +} + +func (c *Client) ExampleGet(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewExampleGetRequest(c.Server) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +// NewExampleGetRequest generates requests for ExampleGet +func NewExampleGetRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/example") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error { + for _, r := range c.RequestEditors { + if err := r(ctx, req); err != nil { + return err + } + } + for _, r := range additionalEditors { + if err := r(ctx, req); err != nil { + return err + } + } + return nil +} + +// ClientWithResponses builds on ClientInterface to offer response payloads +type ClientWithResponses struct { + ClientInterface +} + +// NewClientWithResponses creates a new ClientWithResponses, which wraps +// Client with return type handling +func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) { + client, err := NewClient(server, opts...) + if err != nil { + return nil, err + } + return &ClientWithResponses{client}, nil +} + +// WithBaseURL overrides the baseURL. +func WithBaseURL(baseURL string) ClientOption { + return func(c *Client) error { + newBaseURL, err := url.Parse(baseURL) + if err != nil { + return err + } + c.Server = newBaseURL.String() + return nil + } +} + +// ClientWithResponsesInterface is the interface specification for the client with responses above. +type ClientWithResponsesInterface interface { + // ExampleGet request + ExampleGetWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ExampleGetResponse, error) +} + +type ExampleGetResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *Document +} + +// Status returns HTTPResponse.Status +func (r ExampleGetResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r ExampleGetResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +// ExampleGetWithResponse request returning *ExampleGetResponse +func (c *ClientWithResponses) ExampleGetWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ExampleGetResponse, error) { + rsp, err := c.ExampleGet(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseExampleGetResponse(rsp) +} + +// ParseExampleGetResponse parses an HTTP response from a ExampleGetWithResponse call +func ParseExampleGetResponse(rsp *http.Response) (*ExampleGetResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &ExampleGetResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest Document + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} diff --git a/internal/test/issues/issue-958/pkga/config.yaml b/internal/test/issues/issue-958/pkga/config.yaml new file mode 100644 index 0000000000..25f36109a1 --- /dev/null +++ b/internal/test/issues/issue-958/pkga/config.yaml @@ -0,0 +1,9 @@ +package: pkga +generate: + echo-server: false + client: false + models: true + embedded-spec: false +output-options: + skip-prune: true +output: responses.gen.go diff --git a/internal/test/issues/issue-958/pkga/doc.go b/internal/test/issues/issue-958/pkga/doc.go new file mode 100644 index 0000000000..92d00ebabe --- /dev/null +++ b/internal/test/issues/issue-958/pkga/doc.go @@ -0,0 +1,3 @@ +package pkga + +//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml spec.yaml diff --git a/internal/test/issues/issue-958/pkga/responses.gen.go b/internal/test/issues/issue-958/pkga/responses.gen.go new file mode 100644 index 0000000000..81d18b3154 --- /dev/null +++ b/internal/test/issues/issue-958/pkga/responses.gen.go @@ -0,0 +1,21 @@ +// Package pkga provides primitives to interact with the openapi HTTP API. +// +// Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT. +package pkga + +// ArrayValue defines model for ArrayValue. +type ArrayValue = []Value + +// Document defines model for Document. +type Document struct { + Fields *map[string]Value `json:"fields,omitempty"` +} + +// Value defines model for Value. +type Value struct { + ArrayValue *ArrayValue `json:"arrayValue,omitempty"` + StringValue *string `json:"stringValue,omitempty"` +} + +// N200 defines model for 200. +type N200 = Document diff --git a/internal/test/issues/issue-958/pkga/spec.yaml b/internal/test/issues/issue-958/pkga/spec.yaml new file mode 100644 index 0000000000..3fc5ea0900 --- /dev/null +++ b/internal/test/issues/issue-958/pkga/spec.yaml @@ -0,0 +1,45 @@ +openapi: 3.0.2 +info: + version: '0.0.1' + title: example + description: | + Make sure client with responses can reference external responses +paths: + /example: + get: + operationId: exampleGet + responses: + '200': + description: "OK" + content: + 'application/json': + schema: + $ref: '#/components/schemas/Document' +components: + responses: + 200: + description: "OK" + content: + 'application/json': + schema: + $ref: '#/components/schemas/Document' + schemas: + Document: + type: object + properties: + fields: + type: object + additionalProperties: + $ref: '#/components/schemas/Value' + Value: + type: object + properties: + stringValue: + type: string + arrayValue: + $ref: '#/components/schemas/ArrayValue' + ArrayValue: + type: array + items: + $ref: '#/components/schemas/Value' + diff --git a/internal/test/issues/issue-958/spec.yaml b/internal/test/issues/issue-958/spec.yaml new file mode 100644 index 0000000000..685ab4fbaf --- /dev/null +++ b/internal/test/issues/issue-958/spec.yaml @@ -0,0 +1,14 @@ +openapi: 3.0.2 +info: + version: '0.0.1' + title: example + description: | + Make sure client with responses can reference external responses +paths: + /example: + get: + operationId: exampleGet + responses: + 200: + $ref: "./pkga/spec.yaml#/components/responses/200" + From 1e2beac7d8ec66e24eac3cf81bc2258dde1563b1 Mon Sep 17 00:00:00 2001 From: Benyamin Beyzaie Date: Tue, 14 Mar 2023 19:29:47 +0330 Subject: [PATCH 34/82] fix generated client code cannot convert UUIDs to string when used as path parameters. (#956) --- pkg/runtime/styleparam.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkg/runtime/styleparam.go b/pkg/runtime/styleparam.go index 8f7e12927a..06b2e2506e 100644 --- a/pkg/runtime/styleparam.go +++ b/pkg/runtime/styleparam.go @@ -27,6 +27,7 @@ import ( "time" "github.com/deepmap/oapi-codegen/pkg/types" + "github.com/google/uuid" ) // Parameter escaping works differently based on where a header is found @@ -428,6 +429,10 @@ func primitiveToString(value interface{}) (string, error) { case reflect.Struct: // If input has Marshaler, such as object has Additional Property or AnyOf, // We use this Marshaler and convert into interface{} before styling. + if v, ok := value.(uuid.UUID); ok { + output = v.String() + break + } if m, ok := value.(json.Marshaler); ok { buf, err := m.MarshalJSON() if err != nil { From 619de1645625cd0baa6a40883f85578cd4bd8142 Mon Sep 17 00:00:00 2001 From: Benyamin Beyzaie Date: Tue, 14 Mar 2023 19:30:48 +0330 Subject: [PATCH 35/82] Fix incorrectly generated empty array for security requirements (#955) --- pkg/codegen/template_helpers.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/codegen/template_helpers.go b/pkg/codegen/template_helpers.go index 7585a26801..16671fb393 100644 --- a/pkg/codegen/template_helpers.go +++ b/pkg/codegen/template_helpers.go @@ -263,7 +263,11 @@ func getConditionOfResponseName(statusCodeVar, responseName string) string { // This outputs a string array func toStringArray(sarr []string) string { - return `[]string{"` + strings.Join(sarr, `","`) + `"}` + s := strings.Join(sarr, `","`) + if len(s) > 0 { + s = `"` + s + `"` + } + return `[]string{` + s + `}` } func stripNewLines(s string) string { From 22d1cf4f30325220698beedc40c708cb76e8910c Mon Sep 17 00:00:00 2001 From: HJ Blom <12938666+hjblom@users.noreply.github.com> Date: Tue, 14 Mar 2023 17:13:44 +0100 Subject: [PATCH 36/82] Fix README.md example usage (#982) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c916753cdb..f51aa46b5e 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ into objects which match the OpenAPI 3.0 definition. The code generator in this directory does a lot of that for you. You would run it like so: go install github.com/deepmap/oapi-codegen/cmd/oapi-codegen@latest - oapi-codegen petstore-expanded.yaml > petstore.gen.go + oapi-codegen -package petstore petstore-expanded.yaml > petstore.gen.go Let's go through that `petstore.gen.go` file to show you everything which was generated. From afac8ae432f6f7e2f3f04ba252685a88a6f53162 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81kos=20Pap?= Date: Tue, 14 Mar 2023 17:14:26 +0100 Subject: [PATCH 37/82] Add proper Godoc comment for properties marked as deprecated (#976) * Add proper Godoc comment for properties marked as deprecated Also allow to specify a reason for deprecation using an extension: x-deprecated-reason * Add proper Godoc comment for properties marked as deprecated (fix description) --- internal/test/schemas/schemas.gen.go | 180 +++++++++++++++++++++++---- internal/test/schemas/schemas.yaml | 40 +++++- pkg/codegen/extension.go | 17 ++- pkg/codegen/schema.go | 14 +++ pkg/codegen/utils.go | 9 ++ 5 files changed, 232 insertions(+), 28 deletions(-) diff --git a/internal/test/schemas/schemas.gen.go b/internal/test/schemas/schemas.gen.go index b6a9f2086b..a042df18a5 100644 --- a/internal/test/schemas/schemas.gen.go +++ b/internal/test/schemas/schemas.gen.go @@ -48,6 +48,24 @@ type AnyType2 = interface{} // CustomStringType defines model for CustomStringType. type CustomStringType = string +// DeprecatedProperty defines model for DeprecatedProperty. +type DeprecatedProperty struct { + // NewProp Use this now! + NewProp string `json:"newProp"` + // Deprecated: + OldProp1 *string `json:"oldProp1,omitempty"` + + // OldProp2 It used to do this and that + // Deprecated: + OldProp2 *string `json:"oldProp2,omitempty"` + // Deprecated: Use NewProp instead! + OldProp3 *string `json:"oldProp3,omitempty"` + + // OldProp4 It used to do this and that + // Deprecated: Use NewProp instead! + OldProp4 *string `json:"oldProp4,omitempty"` +} + // EnumInObjInArray defines model for EnumInObjInArray. type EnumInObjInArray = []struct { Val *EnumInObjInArrayVal `json:"val,omitempty"` @@ -184,6 +202,9 @@ type ClientInterface interface { Issue9WithBody(ctx context.Context, params *Issue9Params, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) Issue9(ctx context.Context, params *Issue9Params, body Issue9JSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // Issue975 request + Issue975(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) } func (c *Client) EnsureEverythingIsReferenced(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { @@ -306,6 +327,18 @@ func (c *Client) Issue9(ctx context.Context, params *Issue9Params, body Issue9JS return c.Client.Do(req) } +func (c *Client) Issue975(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewIssue975Request(c.Server) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + // NewEnsureEverythingIsReferencedRequest generates requests for EnsureEverythingIsReferenced func NewEnsureEverythingIsReferencedRequest(server string) (*http.Request, error) { var err error @@ -585,6 +618,33 @@ func NewIssue9RequestWithBody(server string, params *Issue9Params, contentType s return req, nil } +// NewIssue975Request generates requests for Issue975 +func NewIssue975Request(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/issues/975") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error { for _, r := range c.RequestEditors { if err := r(ctx, req); err != nil { @@ -655,6 +715,9 @@ type ClientWithResponsesInterface interface { Issue9WithBodyWithResponse(ctx context.Context, params *Issue9Params, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*Issue9Response, error) Issue9WithResponse(ctx context.Context, params *Issue9Params, body Issue9JSONRequestBody, reqEditors ...RequestEditorFn) (*Issue9Response, error) + + // Issue975 request + Issue975WithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*Issue975Response, error) } type EnsureEverythingIsReferencedResponse struct { @@ -839,6 +902,28 @@ func (r Issue9Response) StatusCode() int { return 0 } +type Issue975Response struct { + Body []byte + HTTPResponse *http.Response + JSON200 *DeprecatedProperty +} + +// Status returns HTTPResponse.Status +func (r Issue975Response) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r Issue975Response) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + // EnsureEverythingIsReferencedWithResponse request returning *EnsureEverythingIsReferencedResponse func (c *ClientWithResponses) EnsureEverythingIsReferencedWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*EnsureEverythingIsReferencedResponse, error) { rsp, err := c.EnsureEverythingIsReferenced(ctx, reqEditors...) @@ -927,6 +1012,15 @@ func (c *ClientWithResponses) Issue9WithResponse(ctx context.Context, params *Is return ParseIssue9Response(rsp) } +// Issue975WithResponse request returning *Issue975Response +func (c *ClientWithResponses) Issue975WithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*Issue975Response, error) { + rsp, err := c.Issue975(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseIssue975Response(rsp) +} + // ParseEnsureEverythingIsReferencedResponse parses an HTTP response from a EnsureEverythingIsReferencedWithResponse call func ParseEnsureEverythingIsReferencedResponse(rsp *http.Response) (*EnsureEverythingIsReferencedResponse, error) { bodyBytes, err := io.ReadAll(rsp.Body) @@ -1120,6 +1214,32 @@ func ParseIssue9Response(rsp *http.Response) (*Issue9Response, error) { return response, nil } +// ParseIssue975Response parses an HTTP response from a Issue975WithResponse call +func ParseIssue975Response(rsp *http.Response) (*Issue975Response, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &Issue975Response{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest DeprecatedProperty + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + // ServerInterface represents all server handlers. type ServerInterface interface { @@ -1146,6 +1266,9 @@ type ServerInterface interface { // (GET /issues/9) Issue9(ctx echo.Context, params Issue9Params) error + + // (GET /issues/975) + Issue975(ctx echo.Context) error } // ServerInterfaceWrapper converts echo contexts to parameters. @@ -1271,6 +1394,17 @@ func (w *ServerInterfaceWrapper) Issue9(ctx echo.Context) error { return err } +// Issue975 converts echo context to params. +func (w *ServerInterfaceWrapper) Issue975(ctx echo.Context) error { + var err error + + ctx.Set(Access_tokenScopes, []string{""}) + + // Invoke the callback with all the unmarshalled arguments + err = w.Handler.Issue975(ctx) + return err +} + // This is a simple interface which specifies echo.Route addition functions which // are present on both echo.Echo and echo.Group, since we want to allow using // either of them for path registration @@ -1307,33 +1441,37 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL router.GET(baseURL+"/issues/375", wrapper.GetIssues375) router.GET(baseURL+"/issues/41/:1param", wrapper.Issue41) router.GET(baseURL+"/issues/9", wrapper.Issue9) + router.GET(baseURL+"/issues/975", wrapper.Issue975) } // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", + "7tMAMZKIRc6LEVfE8H8FAAD//5edhkCXEgAA", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/schemas/schemas.yaml b/internal/test/schemas/schemas.yaml index 3d73527c60..319faa7bf6 100644 --- a/internal/test/schemas/schemas.yaml +++ b/internal/test/schemas/schemas.yaml @@ -121,6 +121,19 @@ paths: application/json: schema: $ref: "#/components/schemas/EnumInObjInArray" + /issues/975: + get: + operationId: Issue975 + description: | + Deprecated fields should get a proper comment + responses: + 200: + description: A struct with deprecated fields with varying level of documentation + content: + application/json: + schema: + $ref: "#/components/schemas/DeprecatedProperty" + components: schemas: GenericObject: @@ -165,6 +178,32 @@ components: enum: - first - second + DeprecatedProperty: + type: object + required: + - newProp + - oldProp + properties: + newProp: + type: string + description: Use this now! + oldProp1: + type: string + deprecated: true + # description: No description on this one to test generation in that case + oldProp2: + type: string + deprecated: true + description: It used to do this and that + oldProp3: + type: string + deprecated: true + x-deprecated-reason: Use NewProp instead! + oldProp4: + type: string + deprecated: true + x-deprecated-reason: Use NewProp instead! + description: It used to do this and that parameters: StringInPath: name: str @@ -183,4 +222,3 @@ components: JWT-format access token. security: - access-token: [ ] - diff --git a/pkg/codegen/extension.go b/pkg/codegen/extension.go index 483d6d8142..ca4c3b6693 100644 --- a/pkg/codegen/extension.go +++ b/pkg/codegen/extension.go @@ -12,12 +12,13 @@ const ( // extGoName is used to override a field name extGoName = "x-go-name" // extGoTypeName is used to override a generated typename for something. - extGoTypeName = "x-go-type-name" - extPropGoJsonIgnore = "x-go-json-ignore" - extPropOmitEmpty = "x-omitempty" - extPropExtraTags = "x-oapi-codegen-extra-tags" - extEnumVarNames = "x-enum-varnames" - extEnumNames = "x-enumNames" + extGoTypeName = "x-go-type-name" + extPropGoJsonIgnore = "x-go-json-ignore" + extPropOmitEmpty = "x-omitempty" + extPropExtraTags = "x-oapi-codegen-extra-tags" + extEnumVarNames = "x-enum-varnames" + extEnumNames = "x-enumNames" + extDeprecationReason = "x-deprecated-reason" ) func extString(extPropValue interface{}) (string, error) { @@ -82,3 +83,7 @@ func extParseEnumVarNames(extPropValue interface{}) ([]string, error) { } return names, nil } + +func extParseDeprecationReason(extPropValue interface{}) (string, error) { + return extString(extPropValue) +} diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 252914a4b3..457e102fe7 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -85,6 +85,7 @@ type Property struct { WriteOnly bool NeedsFormTag bool Extensions map[string]interface{} + Deprecated bool } func (p Property) GoFieldName() string { @@ -388,6 +389,7 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { ReadOnly: p.Value.ReadOnly, WriteOnly: p.Value.WriteOnly, Extensions: p.Value.Extensions, + Deprecated: p.Value.Deprecated, } outSchema.Properties = append(outSchema.Properties, prop) } @@ -622,6 +624,18 @@ func GenFieldsFromProperties(props []Property) []string { field += fmt.Sprintf("%s\n", StringWithTypeNameToGoComment(p.Description, p.GoFieldName())) } + if p.Deprecated { + // This comment has to be on its own line for godoc & IDEs to pick up + var deprecationReason string + if _, ok := p.Extensions[extDeprecationReason]; ok { + if extOmitEmpty, err := extParseDeprecationReason(p.Extensions[extDeprecationReason]); err == nil { + deprecationReason = extOmitEmpty + } + } + + field += fmt.Sprintf("%s\n", DeprecationComment(deprecationReason)) + } + field += fmt.Sprintf(" %s %s", goFieldName, p.GoTypeDef()) // Support x-omitempty diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index 53ee299606..c386cd3f60 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -694,6 +694,15 @@ func StringWithTypeNameToGoComment(in, typeName string) string { return stringToGoCommentWithPrefix(in, typeName) } +func DeprecationComment(reason string) string { + var content = "Deprecated:" // The colon is required at the end even without reason + if reason != "" { + content += fmt.Sprintf(" %s", reason) + } + + return stringToGoCommentWithPrefix(content, "") +} + func stringToGoCommentWithPrefix(in, prefix string) string { if len(in) == 0 || len(strings.TrimSpace(in)) == 0 { // ignore empty comment return "" From f9216021873f56c1b2ce646600fdf0f83b4a3f47 Mon Sep 17 00:00:00 2001 From: Ivan Pushkin Date: Tue, 14 Mar 2023 17:14:39 +0100 Subject: [PATCH 38/82] Add form struct tag for x-www-form-urlencoded request schemas (#1000) --- pkg/codegen/operations.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index 7de40d61cc..28b991f904 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -663,6 +663,17 @@ func GenerateBodyDefinitions(operationID string, bodyOrRef *openapi3.RequestBody // type under #/components, we'll define a type for it, so // that we have an easy to use type for marshaling. if bodySchema.RefType == "" { + if contentType == "application/x-www-form-urlencoded" { + // Apply the appropriate structure tag if the request + // schema was defined under the operations' section. + for i := range bodySchema.Properties { + bodySchema.Properties[i].NeedsFormTag = true + } + + // Regenerate the Golang struct adding the new form tag. + bodySchema.GoType = GenStructFromSchema(bodySchema) + } + td := TypeDefinition{ TypeName: bodyTypeName, Schema: bodySchema, From adf8a06973c056defffc84c3a1d5ac13b3fe5968 Mon Sep 17 00:00:00 2001 From: Hendrik Helmken <98942576+hhelmken@users.noreply.github.com> Date: Tue, 14 Mar 2023 17:18:50 +0100 Subject: [PATCH 39/82] Use different order of arguments for json merge (#998) --- internal/test/any_of/param/param.gen.go | 8 +-- internal/test/components/components.gen.go | 70 +++++++++++----------- pkg/codegen/templates/union.tmpl | 2 +- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/internal/test/any_of/param/param.gen.go b/internal/test/any_of/param/param.gen.go index 7de9459481..07dd59bca2 100644 --- a/internal/test/any_of/param/param.gen.go +++ b/internal/test/any_of/param/param.gen.go @@ -70,7 +70,7 @@ func (t *Test) MergeTest0(v Test0) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -96,7 +96,7 @@ func (t *Test) MergeTest1(v Test1) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -132,7 +132,7 @@ func (t *Test2) MergeTest20(v Test20) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -158,7 +158,7 @@ func (t *Test2) MergeTest21(v Test21) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } diff --git a/internal/test/components/components.gen.go b/internal/test/components/components.gen.go index 8dec2e5cd3..eb60975e05 100644 --- a/internal/test/components/components.gen.go +++ b/internal/test/components/components.gen.go @@ -833,7 +833,7 @@ func (t *AnyOfObject1) MergeOneOfVariant4(v OneOfVariant4) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -859,7 +859,7 @@ func (t *AnyOfObject1) MergeOneOfVariant5(v OneOfVariant5) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -895,7 +895,7 @@ func (t *OneOfObject1) MergeOneOfVariant1(v OneOfVariant1) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -921,7 +921,7 @@ func (t *OneOfObject1) MergeOneOfVariant2(v OneOfVariant2) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -947,7 +947,7 @@ func (t *OneOfObject1) MergeOneOfVariant3(v OneOfVariant3) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -983,7 +983,7 @@ func (t *OneOfObject10) MergeOneOfObject100(v OneOfObject100) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1009,7 +1009,7 @@ func (t *OneOfObject10) MergeOneOfObject101(v OneOfObject101) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1107,7 +1107,7 @@ func (t *OneOfObject11_AdditionalProperties) MergeOneOfObject110(v OneOfObject11 return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1133,7 +1133,7 @@ func (t *OneOfObject11_AdditionalProperties) MergeOneOfObject111(v OneOfObject11 return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1159,7 +1159,7 @@ func (t *OneOfObject11_AdditionalProperties) MergeOneOfObject112(v OneOfObject11 return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1195,7 +1195,7 @@ func (t *OneOfObject12) MergeOneOfObject120(v OneOfObject120) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1221,7 +1221,7 @@ func (t *OneOfObject12) MergeOneOfObject121(v OneOfObject121) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1247,7 +1247,7 @@ func (t *OneOfObject12) MergeOneOfVariant3(v OneOfVariant3) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1273,7 +1273,7 @@ func (t *OneOfObject12) MergeOneOfVariant4(v OneOfVariant4) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1313,7 +1313,7 @@ func (t *OneOfObject13) MergeOneOfVariant1(v OneOfVariant1) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1343,7 +1343,7 @@ func (t *OneOfObject13) MergeOneOfVariant6(v OneOfVariant6) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1392,7 +1392,7 @@ func (t *OneOfObject2) MergeOneOfObject20(v OneOfObject20) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1418,7 +1418,7 @@ func (t *OneOfObject2) MergeOneOfObject21(v OneOfObject21) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1444,7 +1444,7 @@ func (t *OneOfObject2) MergeOneOfObject22(v OneOfObject22) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1480,7 +1480,7 @@ func (t *OneOfObject3_Union) MergeOneOfVariant1(v OneOfVariant1) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1506,7 +1506,7 @@ func (t *OneOfObject3_Union) MergeOneOfVariant2(v OneOfVariant2) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1532,7 +1532,7 @@ func (t *OneOfObject3_Union) MergeOneOfVariant3(v OneOfVariant3) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1568,7 +1568,7 @@ func (t *OneOfObject4) MergeOneOfVariant1(v OneOfVariant1) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1594,7 +1594,7 @@ func (t *OneOfObject4) MergeOneOfVariant2(v OneOfVariant2) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1620,7 +1620,7 @@ func (t *OneOfObject4) MergeOneOfVariant3(v OneOfVariant3) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1692,7 +1692,7 @@ func (t *OneOfObject5) MergeOneOfVariant4(v OneOfVariant4) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1720,7 +1720,7 @@ func (t *OneOfObject5) MergeOneOfVariant5(v OneOfVariant5) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1781,7 +1781,7 @@ func (t *OneOfObject6) MergeOneOfVariant4(v OneOfVariant4) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1809,7 +1809,7 @@ func (t *OneOfObject6) MergeOneOfVariant5(v OneOfVariant5) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -2046,7 +2046,7 @@ func (t *OneOfObject7_Item) MergeOneOfVariant1(v OneOfVariant1) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -2072,7 +2072,7 @@ func (t *OneOfObject7_Item) MergeOneOfVariant2(v OneOfVariant2) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -2108,7 +2108,7 @@ func (t *OneOfObject8) MergeOneOfVariant1(v OneOfVariant1) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -2134,7 +2134,7 @@ func (t *OneOfObject8) MergeOneOfVariant2(v OneOfVariant2) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -2208,7 +2208,7 @@ func (t *OneOfObject9) MergeOneOfVariant1(v OneOfVariant1) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -2238,7 +2238,7 @@ func (t *OneOfObject9) MergeOneOfVariant6(v OneOfVariant6) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } diff --git a/pkg/codegen/templates/union.tmpl b/pkg/codegen/templates/union.tmpl index 06c91f4f13..8bb34a2562 100644 --- a/pkg/codegen/templates/union.tmpl +++ b/pkg/codegen/templates/union.tmpl @@ -53,7 +53,7 @@ return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } From 497e0009532e8b09c2cba18c610687f9e999e0c9 Mon Sep 17 00:00:00 2001 From: Andrew Young <90873162+octomad@users.noreply.github.com> Date: Tue, 14 Mar 2023 09:20:04 -0700 Subject: [PATCH 40/82] Fix allOf merges using external refs (#941) Co-authored-by: Andrew Young --- pkg/codegen/codegen_test.go | 5 ++++- pkg/codegen/filter_test.go | 10 ++++++++-- pkg/codegen/merge_schemas.go | 4 ++-- pkg/codegen/test_schema.json | 15 +++++++++++++++ pkg/codegen/test_spec.yaml | 28 ++++++++++++++++++++++++++++ 5 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 pkg/codegen/test_schema.json diff --git a/pkg/codegen/codegen_test.go b/pkg/codegen/codegen_test.go index e3878f58dd..6ae61211a9 100644 --- a/pkg/codegen/codegen_test.go +++ b/pkg/codegen/codegen_test.go @@ -145,8 +145,11 @@ func TestExampleOpenAPICodeGeneration(t *testing.T) { }, } + loader := openapi3.NewLoader() + loader.IsExternalRefsAllowed = true + // Get a spec from the test definition in this file: - swagger, err := openapi3.NewLoader().LoadFromData([]byte(testOpenAPIDefinition)) + swagger, err := loader.LoadFromData([]byte(testOpenAPIDefinition)) assert.NoError(t, err) // Run our code generation: diff --git a/pkg/codegen/filter_test.go b/pkg/codegen/filter_test.go index d3a5aec546..774d016a84 100644 --- a/pkg/codegen/filter_test.go +++ b/pkg/codegen/filter_test.go @@ -23,8 +23,11 @@ func TestFilterOperationsByTag(t *testing.T) { }, } + loader := openapi3.NewLoader() + loader.IsExternalRefsAllowed = true + // Get a spec from the test definition in this file: - swagger, err := openapi3.NewLoader().LoadFromData([]byte(testOpenAPIDefinition)) + swagger, err := loader.LoadFromData([]byte(testOpenAPIDefinition)) assert.NoError(t, err) // Run our code generation: @@ -49,8 +52,11 @@ func TestFilterOperationsByTag(t *testing.T) { }, } + loader := openapi3.NewLoader() + loader.IsExternalRefsAllowed = true + // Get a spec from the test definition in this file: - swagger, err := openapi3.NewLoader().LoadFromData([]byte(testOpenAPIDefinition)) + swagger, err := loader.LoadFromData([]byte(testOpenAPIDefinition)) assert.NoError(t, err) // Run our code generation: diff --git a/pkg/codegen/merge_schemas.go b/pkg/codegen/merge_schemas.go index ba5b86db51..84256b172e 100644 --- a/pkg/codegen/merge_schemas.go +++ b/pkg/codegen/merge_schemas.go @@ -53,10 +53,10 @@ func valueWithPropagatedRef(ref *openapi3.SchemaRef) (openapi3.Schema, error) { } pathParts := strings.Split(ref.Ref, "#") - if len(pathParts) != 2 { + if len(pathParts) < 1 || len(pathParts) > 2 { return openapi3.Schema{}, fmt.Errorf("unsupported reference: %s", ref.Ref) } - remoteComponent, _ := pathParts[0], pathParts[1] + remoteComponent := pathParts[0] // remote ref schema := *ref.Value diff --git a/pkg/codegen/test_schema.json b/pkg/codegen/test_schema.json new file mode 100644 index 0000000000..d64939498e --- /dev/null +++ b/pkg/codegen/test_schema.json @@ -0,0 +1,15 @@ +{ + "title": "node", + "type": "object", + "description": "Represents a node", + "properties": { + "id": { + "type": "string", + "format": "uri-reference" + }, + "type": { + "type": "string", + "pattern": "^[A-Z][a-zA-Z0-9]*$" + } + } +} \ No newline at end of file diff --git a/pkg/codegen/test_spec.yaml b/pkg/codegen/test_spec.yaml index 7491c69c31..b50f7491c5 100644 --- a/pkg/codegen/test_spec.yaml +++ b/pkg/codegen/test_spec.yaml @@ -108,6 +108,25 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' + /user: + get: + tags: + - mergeAllOf + summary: Merges allOf ref-ing a JSON schema + operationId: getUser + responses: + 200: + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/User' + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' components: schemas: @@ -177,3 +196,12 @@ components: - na - single - double + User: + allOf: + - $ref: ./test_schema.json + - type: object + additionalProperties: false + properties: + name: + type: string + description: User name From 189619a673d8a2fb251f6f6b3ac111d68b9d541a Mon Sep 17 00:00:00 2001 From: Steven Hartland Date: Tue, 14 Mar 2023 22:45:39 +0000 Subject: [PATCH 41/82] fix(oapi-codegen): command line parsing compatibility (#852) Improve command line compatibility between old and new style configs so existing user setups work as expected where possible. This restores -generate and -templates flags from deprecated states as the new configuration format doesn't provide the needed functionality with out them. It makes all but -alias-types work with new config files. The -alias-types doesn't do anything in either config mode any more. For -generate the use case is one configuration and multiple output files for different generation types, which we use extensively. For -templates having to have go .tmpl inside a .yaml config file works for simple snippets but for large templates its not practical, hence the direction option is required. --- cmd/oapi-codegen/oapi-codegen.go | 122 +++++++++++++++++-------------- 1 file changed, 66 insertions(+), 56 deletions(-) diff --git a/cmd/oapi-codegen/oapi-codegen.go b/cmd/oapi-codegen/oapi-codegen.go index aa33a76ea7..eb213e478f 100644 --- a/cmd/oapi-codegen/oapi-codegen.go +++ b/cmd/oapi-codegen/oapi-codegen.go @@ -21,7 +21,6 @@ import ( "path" "path/filepath" "runtime/debug" - "strings" "gopkg.in/yaml.v2" @@ -42,13 +41,13 @@ var ( flagPrintVersion bool flagPackageName string flagPrintUsage bool + flagGenerate string + flagTemplatesDir string - // The options below are deprecated, and they will be removed in a future + // Deprecated: The options below will be removed in a future // release. Please use the new config file format. - flagGenerate string flagIncludeTags string flagExcludeTags string - flagTemplatesDir string flagImportMapping string flagExcludeSchemas string flagResponseTypeSuffix string @@ -164,10 +163,8 @@ func main() { // config style. It should work correctly if we go down the old path, // even if we have a simple config file readable as both types. deprecatedFlagNames := map[string]bool{ - "generate": true, "include-tags": true, "exclude-tags": true, - "templates": true, "import-mapping": true, "exclude-schemas": true, "response-type-suffix": true, @@ -216,9 +213,8 @@ func main() { OutputFile: flagOutputFile, } } - var err error - opts, err = updateConfigFromFlags(opts) - if err != nil { + + if err := updateConfigFromFlags(&opts); err != nil { errExit("error processing flags: %v\n", err) } } else { @@ -352,51 +348,54 @@ func detectPackageName(cfg *configuration) error { } // updateConfigFromFlags updates a loaded configuration from flags. Flags -// override anything in the file. We generate errors for command line options -// associated with the old style configuration -func updateConfigFromFlags(cfg configuration) (configuration, error) { +// override anything in the file. We generate errors for any unsupported +// command line flags. +func updateConfigFromFlags(cfg *configuration) error { if flagPackageName != "" { cfg.PackageName = flagPackageName } - var unsupportedFlags []string - if flagGenerate != "types,client,server,spec" { - unsupportedFlags = append(unsupportedFlags, "--generate") + // Override generation and output options from generate command line flag. + if err := generationTargets(&cfg.Configuration, util.ParseCommandLineList(flagGenerate)); err != nil { + return err + } } if flagIncludeTags != "" { - unsupportedFlags = append(unsupportedFlags, "--include-tags") + cfg.OutputOptions.IncludeTags = util.ParseCommandLineList(flagIncludeTags) } if flagExcludeTags != "" { - unsupportedFlags = append(unsupportedFlags, "--exclude-tags") + cfg.OutputOptions.ExcludeTags = util.ParseCommandLineList(flagExcludeTags) } if flagTemplatesDir != "" { - unsupportedFlags = append(unsupportedFlags, "--templates") + templates, err := loadTemplateOverrides(flagTemplatesDir) + if err != nil { + return fmt.Errorf("load templates from %q: %w", flagTemplatesDir, err) + } + cfg.OutputOptions.UserTemplates = templates } if flagImportMapping != "" { - unsupportedFlags = append(unsupportedFlags, "--import-mapping") + var err error + cfg.ImportMapping, err = util.ParseCommandlineMap(flagImportMapping) + if err != nil { + return err + } } if flagExcludeSchemas != "" { - unsupportedFlags = append(unsupportedFlags, "--exclude-schemas") + cfg.OutputOptions.ExcludeSchemas = util.ParseCommandLineList(flagExcludeSchemas) } if flagResponseTypeSuffix != "" { - unsupportedFlags = append(unsupportedFlags, "--response-type-suffix") + cfg.OutputOptions.ResponseTypeSuffix = flagResponseTypeSuffix } if flagAliasTypes { - unsupportedFlags = append(unsupportedFlags, "--alias-types") - } - - if len(unsupportedFlags) > 0 { - return configuration{}, fmt.Errorf("flags %s aren't supported in "+ - "new config style, please use --old-config-style or update your configuration ", - strings.Join(unsupportedFlags, ", ")) + return fmt.Errorf("--alias-types isn't supported any more") } if cfg.OutputFile == "" { cfg.OutputFile = flagOutputFile } - return cfg, nil + return nil } // updateOldConfigFromFlags parses the flags and the config file. Anything which is @@ -434,6 +433,40 @@ func updateOldConfigFromFlags(cfg oldConfiguration) oldConfiguration { return cfg } +// generationTargets sets cfg options based on the generation targets. +func generationTargets(cfg *codegen.Configuration, targets []string) error { + opts := codegen.GenerateOptions{} // Blank to start with. + for _, opt := range targets { + switch opt { + case "chi-server", "chi": + opts.ChiServer = true + case "server", "echo-server", "echo": + opts.EchoServer = true + case "gin", "gin-server": + opts.GinServer = true + case "gorilla", "gorilla-server": + opts.GorillaServer = true + case "strict-server": + opts.Strict = true + case "client": + opts.Client = true + case "types", "models": + opts.Models = true + case "spec", "embedded-spec": + opts.EmbeddedSpec = true + case "skip-fmt": + cfg.OutputOptions.SkipFmt = true + case "skip-prune": + cfg.OutputOptions.SkipPrune = true + default: + return fmt.Errorf("unknown generate option %q", opt) + } + } + cfg.Generate = opts + + return nil +} + func newConfigFromOldConfig(c oldConfiguration) configuration { // Take flags into account. cfg := updateOldConfigFromFlags(c) @@ -445,33 +478,10 @@ func newConfigFromOldConfig(c oldConfiguration) configuration { } opts.OutputOptions.ResponseTypeSuffix = flagResponseTypeSuffix - for _, g := range cfg.GenerateTargets { - switch g { - case "client": - opts.Generate.Client = true - case "chi-server": - opts.Generate.ChiServer = true - case "server": - opts.Generate.EchoServer = true - case "gin": - opts.Generate.GinServer = true - case "gorilla": - opts.Generate.GorillaServer = true - case "strict-server": - opts.Generate.Strict = true - case "types": - opts.Generate.Models = true - case "spec": - opts.Generate.EmbeddedSpec = true - case "skip-fmt": - opts.OutputOptions.SkipFmt = true - case "skip-prune": - opts.OutputOptions.SkipPrune = true - default: - fmt.Printf("unknown generate option %s\n", g) - flag.PrintDefaults() - os.Exit(1) - } + if err := generationTargets(&opts, cfg.GenerateTargets); err != nil { + fmt.Println(err) + flag.PrintDefaults() + os.Exit(1) } opts.OutputOptions.IncludeTags = cfg.IncludeTags From b42721b9b95325c3bc7a88fb58be6770632b4bed Mon Sep 17 00:00:00 2001 From: Ryan Marken Date: Tue, 14 Mar 2023 19:10:11 -0400 Subject: [PATCH 42/82] fix959 (#992) * issue958 * String manipulation * Adjust logic to provide external refs --------- Co-authored-by: Alex Mammay Co-authored-by: Marcin Romaszewicz <47459980+deepmap-marcinr@users.noreply.github.com> --- internal/test/issues/issue-958/issue.gen.go | 4 +++- pkg/codegen/operations.go | 21 ++++++++++++--------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/internal/test/issues/issue-958/issue.gen.go b/internal/test/issues/issue-958/issue.gen.go index 088b3f60b8..4b355f94f4 100644 --- a/internal/test/issues/issue-958/issue.gen.go +++ b/internal/test/issues/issue-958/issue.gen.go @@ -11,6 +11,7 @@ import ( "net/http" "net/url" "strings" + externalRef0 "github.com/deepmap/oapi-codegen/internal/test/issues/issue-958/pkga" ) // RequestEditorFn is the function signature for the RequestEditor callback function @@ -179,6 +180,7 @@ type ClientWithResponsesInterface interface { type ExampleGetResponse struct { Body []byte HTTPResponse *http.Response + JSON200 *externalRef0.Document JSON200 *Document } @@ -222,7 +224,7 @@ func ParseExampleGetResponse(rsp *http.Response) (*ExampleGetResponse, error) { switch { case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest Document + var dest externalRef0.Document if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index 28b991f904..7213a846e6 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -278,7 +278,9 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]ResponseTypeDefini sortedResponsesKeys := SortedResponsesKeys(responses) for _, responseName := range sortedResponsesKeys { responseRef := responses[responseName] - + refParts := strings.Split(responseRef.Ref, "#") + // Checking to see if reference belongs to external doc so child content can be adjusted. + _, isExternalImport := importMapping[refParts[0]] // We can only generate a type if we have a value: if responseRef.Value != nil { sortedContentKeys := SortedContentKeys(responseRef.Value.Content) @@ -286,7 +288,15 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]ResponseTypeDefini contentType := responseRef.Value.Content[contentTypeName] // We can only generate a type if we have a schema: if contentType.Schema != nil { - responseSchema, err := GenerateGoSchema(contentType.Schema, []string{responseName}) + // Create a copy as to not disturb original. + schemaCopy := *contentType.Schema + // When an external reference is provided, adjust the ref to contain full path so imports can be attached. + if isExternalImport && IsGoTypeReference(schemaCopy.Ref) { + schemaParts := strings.Split(schemaCopy.Ref, "#") + refDef := schemaParts[len(schemaParts)-1] + schemaCopy.Ref = fmt.Sprintf("%s#%s", refParts[0], refDef) + } + responseSchema, err := GenerateGoSchema(&schemaCopy, []string{responseName}) if err != nil { return nil, fmt.Errorf("Unable to determine Go type for %s.%s: %w", o.OperationId, contentTypeName, err) } @@ -313,13 +323,6 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]ResponseTypeDefini ResponseName: responseName, ContentTypeName: contentTypeName, } - if IsGoTypeReference(contentType.Schema.Ref) { - refType, err := RefPathToGoType(contentType.Schema.Ref) - if err != nil { - return nil, fmt.Errorf("error dereferencing response Ref: %w", err) - } - td.Schema.RefType = refType - } tds = append(tds, td) } } From 6d85384de3c3f35825987b0d0afb03217da709ce Mon Sep 17 00:00:00 2001 From: marcinromaszewicz Date: Tue, 14 Mar 2023 16:12:21 -0700 Subject: [PATCH 43/82] Revert "fix959 (#992)" This reverts commit b42721b9b95325c3bc7a88fb58be6770632b4bed. This is one of two related commits that are causing a crash. --- internal/test/issues/issue-958/issue.gen.go | 4 +--- pkg/codegen/operations.go | 21 +++++++++------------ 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/internal/test/issues/issue-958/issue.gen.go b/internal/test/issues/issue-958/issue.gen.go index 4b355f94f4..088b3f60b8 100644 --- a/internal/test/issues/issue-958/issue.gen.go +++ b/internal/test/issues/issue-958/issue.gen.go @@ -11,7 +11,6 @@ import ( "net/http" "net/url" "strings" - externalRef0 "github.com/deepmap/oapi-codegen/internal/test/issues/issue-958/pkga" ) // RequestEditorFn is the function signature for the RequestEditor callback function @@ -180,7 +179,6 @@ type ClientWithResponsesInterface interface { type ExampleGetResponse struct { Body []byte HTTPResponse *http.Response - JSON200 *externalRef0.Document JSON200 *Document } @@ -224,7 +222,7 @@ func ParseExampleGetResponse(rsp *http.Response) (*ExampleGetResponse, error) { switch { case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest externalRef0.Document + var dest Document if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index 7213a846e6..28b991f904 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -278,9 +278,7 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]ResponseTypeDefini sortedResponsesKeys := SortedResponsesKeys(responses) for _, responseName := range sortedResponsesKeys { responseRef := responses[responseName] - refParts := strings.Split(responseRef.Ref, "#") - // Checking to see if reference belongs to external doc so child content can be adjusted. - _, isExternalImport := importMapping[refParts[0]] + // We can only generate a type if we have a value: if responseRef.Value != nil { sortedContentKeys := SortedContentKeys(responseRef.Value.Content) @@ -288,15 +286,7 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]ResponseTypeDefini contentType := responseRef.Value.Content[contentTypeName] // We can only generate a type if we have a schema: if contentType.Schema != nil { - // Create a copy as to not disturb original. - schemaCopy := *contentType.Schema - // When an external reference is provided, adjust the ref to contain full path so imports can be attached. - if isExternalImport && IsGoTypeReference(schemaCopy.Ref) { - schemaParts := strings.Split(schemaCopy.Ref, "#") - refDef := schemaParts[len(schemaParts)-1] - schemaCopy.Ref = fmt.Sprintf("%s#%s", refParts[0], refDef) - } - responseSchema, err := GenerateGoSchema(&schemaCopy, []string{responseName}) + responseSchema, err := GenerateGoSchema(contentType.Schema, []string{responseName}) if err != nil { return nil, fmt.Errorf("Unable to determine Go type for %s.%s: %w", o.OperationId, contentTypeName, err) } @@ -323,6 +313,13 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]ResponseTypeDefini ResponseName: responseName, ContentTypeName: contentTypeName, } + if IsGoTypeReference(contentType.Schema.Ref) { + refType, err := RefPathToGoType(contentType.Schema.Ref) + if err != nil { + return nil, fmt.Errorf("error dereferencing response Ref: %w", err) + } + td.Schema.RefType = refType + } tds = append(tds, td) } } From 48862580da47f425f124a0cbf68dfed37a392371 Mon Sep 17 00:00:00 2001 From: marcinromaszewicz Date: Tue, 14 Mar 2023 16:12:59 -0700 Subject: [PATCH 44/82] Revert "issue958 (#959)" This reverts commit ffe428be7df3e65f29a1f26e30e7c07eeb3bede4. The example and the fix crash the code generator. --- internal/test/issues/issue-958/config.yaml | 8 - internal/test/issues/issue-958/doc.go | 3 - internal/test/issues/issue-958/issue.gen.go | 234 ------------------ .../test/issues/issue-958/pkga/config.yaml | 9 - internal/test/issues/issue-958/pkga/doc.go | 3 - .../issues/issue-958/pkga/responses.gen.go | 21 -- internal/test/issues/issue-958/pkga/spec.yaml | 45 ---- internal/test/issues/issue-958/spec.yaml | 14 -- 8 files changed, 337 deletions(-) delete mode 100644 internal/test/issues/issue-958/config.yaml delete mode 100644 internal/test/issues/issue-958/doc.go delete mode 100644 internal/test/issues/issue-958/issue.gen.go delete mode 100644 internal/test/issues/issue-958/pkga/config.yaml delete mode 100644 internal/test/issues/issue-958/pkga/doc.go delete mode 100644 internal/test/issues/issue-958/pkga/responses.gen.go delete mode 100644 internal/test/issues/issue-958/pkga/spec.yaml delete mode 100644 internal/test/issues/issue-958/spec.yaml diff --git a/internal/test/issues/issue-958/config.yaml b/internal/test/issues/issue-958/config.yaml deleted file mode 100644 index 1cf2e1966b..0000000000 --- a/internal/test/issues/issue-958/config.yaml +++ /dev/null @@ -1,8 +0,0 @@ -package: issue958 -generate: - client: true -output: issue.gen.go -output-options: - skip-prune: true -import-mapping: - ./pkga/spec.yaml: github.com/deepmap/oapi-codegen/internal/test/issues/issue-958/pkga diff --git a/internal/test/issues/issue-958/doc.go b/internal/test/issues/issue-958/doc.go deleted file mode 100644 index 3be1f22d5e..0000000000 --- a/internal/test/issues/issue-958/doc.go +++ /dev/null @@ -1,3 +0,0 @@ -package issue958 - -//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml spec.yaml diff --git a/internal/test/issues/issue-958/issue.gen.go b/internal/test/issues/issue-958/issue.gen.go deleted file mode 100644 index 088b3f60b8..0000000000 --- a/internal/test/issues/issue-958/issue.gen.go +++ /dev/null @@ -1,234 +0,0 @@ -// Package issue958 provides primitives to interact with the openapi HTTP API. -// -// Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT. -package issue958 - -import ( - "context" - "encoding/json" - "fmt" - "io" - "net/http" - "net/url" - "strings" -) - -// RequestEditorFn is the function signature for the RequestEditor callback function -type RequestEditorFn func(ctx context.Context, req *http.Request) error - -// Doer performs HTTP requests. -// -// The standard http.Client implements this interface. -type HttpRequestDoer interface { - Do(req *http.Request) (*http.Response, error) -} - -// Client which conforms to the OpenAPI3 specification for this service. -type Client struct { - // The endpoint of the server conforming to this interface, with scheme, - // https://api.deepmap.com for example. This can contain a path relative - // to the server, such as https://api.deepmap.com/dev-test, and all the - // paths in the swagger spec will be appended to the server. - Server string - - // Doer for performing requests, typically a *http.Client with any - // customized settings, such as certificate chains. - Client HttpRequestDoer - - // A list of callbacks for modifying requests which are generated before sending over - // the network. - RequestEditors []RequestEditorFn -} - -// ClientOption allows setting custom parameters during construction -type ClientOption func(*Client) error - -// Creates a new Client, with reasonable defaults -func NewClient(server string, opts ...ClientOption) (*Client, error) { - // create a client with sane default values - client := Client{ - Server: server, - } - // mutate client and add all optional params - for _, o := range opts { - if err := o(&client); err != nil { - return nil, err - } - } - // ensure the server URL always has a trailing slash - if !strings.HasSuffix(client.Server, "/") { - client.Server += "/" - } - // create httpClient, if not already present - if client.Client == nil { - client.Client = &http.Client{} - } - return &client, nil -} - -// WithHTTPClient allows overriding the default Doer, which is -// automatically created using http.Client. This is useful for tests. -func WithHTTPClient(doer HttpRequestDoer) ClientOption { - return func(c *Client) error { - c.Client = doer - return nil - } -} - -// WithRequestEditorFn allows setting up a callback function, which will be -// called right before sending the request. This can be used to mutate the request. -func WithRequestEditorFn(fn RequestEditorFn) ClientOption { - return func(c *Client) error { - c.RequestEditors = append(c.RequestEditors, fn) - return nil - } -} - -// The interface specification for the client above. -type ClientInterface interface { - // ExampleGet request - ExampleGet(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) -} - -func (c *Client) ExampleGet(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewExampleGetRequest(c.Server) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -// NewExampleGetRequest generates requests for ExampleGet -func NewExampleGetRequest(server string) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/example") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error { - for _, r := range c.RequestEditors { - if err := r(ctx, req); err != nil { - return err - } - } - for _, r := range additionalEditors { - if err := r(ctx, req); err != nil { - return err - } - } - return nil -} - -// ClientWithResponses builds on ClientInterface to offer response payloads -type ClientWithResponses struct { - ClientInterface -} - -// NewClientWithResponses creates a new ClientWithResponses, which wraps -// Client with return type handling -func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) { - client, err := NewClient(server, opts...) - if err != nil { - return nil, err - } - return &ClientWithResponses{client}, nil -} - -// WithBaseURL overrides the baseURL. -func WithBaseURL(baseURL string) ClientOption { - return func(c *Client) error { - newBaseURL, err := url.Parse(baseURL) - if err != nil { - return err - } - c.Server = newBaseURL.String() - return nil - } -} - -// ClientWithResponsesInterface is the interface specification for the client with responses above. -type ClientWithResponsesInterface interface { - // ExampleGet request - ExampleGetWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ExampleGetResponse, error) -} - -type ExampleGetResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *Document -} - -// Status returns HTTPResponse.Status -func (r ExampleGetResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r ExampleGetResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -// ExampleGetWithResponse request returning *ExampleGetResponse -func (c *ClientWithResponses) ExampleGetWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ExampleGetResponse, error) { - rsp, err := c.ExampleGet(ctx, reqEditors...) - if err != nil { - return nil, err - } - return ParseExampleGetResponse(rsp) -} - -// ParseExampleGetResponse parses an HTTP response from a ExampleGetWithResponse call -func ParseExampleGetResponse(rsp *http.Response) (*ExampleGetResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &ExampleGetResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest Document - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - } - - return response, nil -} diff --git a/internal/test/issues/issue-958/pkga/config.yaml b/internal/test/issues/issue-958/pkga/config.yaml deleted file mode 100644 index 25f36109a1..0000000000 --- a/internal/test/issues/issue-958/pkga/config.yaml +++ /dev/null @@ -1,9 +0,0 @@ -package: pkga -generate: - echo-server: false - client: false - models: true - embedded-spec: false -output-options: - skip-prune: true -output: responses.gen.go diff --git a/internal/test/issues/issue-958/pkga/doc.go b/internal/test/issues/issue-958/pkga/doc.go deleted file mode 100644 index 92d00ebabe..0000000000 --- a/internal/test/issues/issue-958/pkga/doc.go +++ /dev/null @@ -1,3 +0,0 @@ -package pkga - -//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml spec.yaml diff --git a/internal/test/issues/issue-958/pkga/responses.gen.go b/internal/test/issues/issue-958/pkga/responses.gen.go deleted file mode 100644 index 81d18b3154..0000000000 --- a/internal/test/issues/issue-958/pkga/responses.gen.go +++ /dev/null @@ -1,21 +0,0 @@ -// Package pkga provides primitives to interact with the openapi HTTP API. -// -// Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT. -package pkga - -// ArrayValue defines model for ArrayValue. -type ArrayValue = []Value - -// Document defines model for Document. -type Document struct { - Fields *map[string]Value `json:"fields,omitempty"` -} - -// Value defines model for Value. -type Value struct { - ArrayValue *ArrayValue `json:"arrayValue,omitempty"` - StringValue *string `json:"stringValue,omitempty"` -} - -// N200 defines model for 200. -type N200 = Document diff --git a/internal/test/issues/issue-958/pkga/spec.yaml b/internal/test/issues/issue-958/pkga/spec.yaml deleted file mode 100644 index 3fc5ea0900..0000000000 --- a/internal/test/issues/issue-958/pkga/spec.yaml +++ /dev/null @@ -1,45 +0,0 @@ -openapi: 3.0.2 -info: - version: '0.0.1' - title: example - description: | - Make sure client with responses can reference external responses -paths: - /example: - get: - operationId: exampleGet - responses: - '200': - description: "OK" - content: - 'application/json': - schema: - $ref: '#/components/schemas/Document' -components: - responses: - 200: - description: "OK" - content: - 'application/json': - schema: - $ref: '#/components/schemas/Document' - schemas: - Document: - type: object - properties: - fields: - type: object - additionalProperties: - $ref: '#/components/schemas/Value' - Value: - type: object - properties: - stringValue: - type: string - arrayValue: - $ref: '#/components/schemas/ArrayValue' - ArrayValue: - type: array - items: - $ref: '#/components/schemas/Value' - diff --git a/internal/test/issues/issue-958/spec.yaml b/internal/test/issues/issue-958/spec.yaml deleted file mode 100644 index 685ab4fbaf..0000000000 --- a/internal/test/issues/issue-958/spec.yaml +++ /dev/null @@ -1,14 +0,0 @@ -openapi: 3.0.2 -info: - version: '0.0.1' - title: example - description: | - Make sure client with responses can reference external responses -paths: - /example: - get: - operationId: exampleGet - responses: - 200: - $ref: "./pkga/spec.yaml#/components/responses/200" - From 0cfaaa77a7d2a6baa495469b706cc04b1463387b Mon Sep 17 00:00:00 2001 From: marcinromaszewicz Date: Tue, 14 Mar 2023 16:14:17 -0700 Subject: [PATCH 45/82] Fix missing import and regenerate code --- cmd/oapi-codegen/oapi-codegen.go | 1 + examples/authenticated-api/echo/api/api.gen.go | 2 +- internal/test/components/components.gen.go | 8 ++++---- internal/test/schemas/schemas.gen.go | 18 +++++++++--------- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/cmd/oapi-codegen/oapi-codegen.go b/cmd/oapi-codegen/oapi-codegen.go index eb213e478f..7d9f2cc57a 100644 --- a/cmd/oapi-codegen/oapi-codegen.go +++ b/cmd/oapi-codegen/oapi-codegen.go @@ -21,6 +21,7 @@ import ( "path" "path/filepath" "runtime/debug" + "strings" "gopkg.in/yaml.v2" diff --git a/examples/authenticated-api/echo/api/api.gen.go b/examples/authenticated-api/echo/api/api.gen.go index 1433f2d5fd..1d0fcb1ff2 100644 --- a/examples/authenticated-api/echo/api/api.gen.go +++ b/examples/authenticated-api/echo/api/api.gen.go @@ -425,7 +425,7 @@ type ServerInterfaceWrapper struct { func (w *ServerInterfaceWrapper) ListThings(ctx echo.Context) error { var err error - ctx.Set(BearerAuthScopes, []string{""}) + ctx.Set(BearerAuthScopes, []string{}) // Invoke the callback with all the unmarshalled arguments err = w.Handler.ListThings(ctx) diff --git a/internal/test/components/components.gen.go b/internal/test/components/components.gen.go index eb60975e05..be29e17ad6 100644 --- a/internal/test/components/components.gen.go +++ b/internal/test/components/components.gen.go @@ -1870,7 +1870,7 @@ func (t *OneOfObject61) MergeOneOfVariant4(v OneOfVariant4) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1898,7 +1898,7 @@ func (t *OneOfObject61) MergeOneOfVariant5(v OneOfVariant5) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1959,7 +1959,7 @@ func (t *OneOfObject62) MergeOneOfVariant4(v OneOfVariant4) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1987,7 +1987,7 @@ func (t *OneOfObject62) MergeOneOfVariant51(v OneOfVariant51) error { return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } diff --git a/internal/test/schemas/schemas.gen.go b/internal/test/schemas/schemas.gen.go index a042df18a5..d1791abad0 100644 --- a/internal/test/schemas/schemas.gen.go +++ b/internal/test/schemas/schemas.gen.go @@ -1280,7 +1280,7 @@ type ServerInterfaceWrapper struct { func (w *ServerInterfaceWrapper) EnsureEverythingIsReferenced(ctx echo.Context) error { var err error - ctx.Set(Access_tokenScopes, []string{""}) + ctx.Set(Access_tokenScopes, []string{}) // Invoke the callback with all the unmarshalled arguments err = w.Handler.EnsureEverythingIsReferenced(ctx) @@ -1291,7 +1291,7 @@ func (w *ServerInterfaceWrapper) EnsureEverythingIsReferenced(ctx echo.Context) func (w *ServerInterfaceWrapper) Issue127(ctx echo.Context) error { var err error - ctx.Set(Access_tokenScopes, []string{""}) + ctx.Set(Access_tokenScopes, []string{}) // Invoke the callback with all the unmarshalled arguments err = w.Handler.Issue127(ctx) @@ -1302,7 +1302,7 @@ func (w *ServerInterfaceWrapper) Issue127(ctx echo.Context) error { func (w *ServerInterfaceWrapper) Issue185(ctx echo.Context) error { var err error - ctx.Set(Access_tokenScopes, []string{""}) + ctx.Set(Access_tokenScopes, []string{}) // Invoke the callback with all the unmarshalled arguments err = w.Handler.Issue185(ctx) @@ -1320,7 +1320,7 @@ func (w *ServerInterfaceWrapper) Issue209(ctx echo.Context) error { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter str: %s", err)) } - ctx.Set(Access_tokenScopes, []string{""}) + ctx.Set(Access_tokenScopes, []string{}) // Invoke the callback with all the unmarshalled arguments err = w.Handler.Issue209(ctx, str) @@ -1338,7 +1338,7 @@ func (w *ServerInterfaceWrapper) Issue30(ctx echo.Context) error { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter fallthrough: %s", err)) } - ctx.Set(Access_tokenScopes, []string{""}) + ctx.Set(Access_tokenScopes, []string{}) // Invoke the callback with all the unmarshalled arguments err = w.Handler.Issue30(ctx, pFallthrough) @@ -1349,7 +1349,7 @@ func (w *ServerInterfaceWrapper) Issue30(ctx echo.Context) error { func (w *ServerInterfaceWrapper) GetIssues375(ctx echo.Context) error { var err error - ctx.Set(Access_tokenScopes, []string{""}) + ctx.Set(Access_tokenScopes, []string{}) // Invoke the callback with all the unmarshalled arguments err = w.Handler.GetIssues375(ctx) @@ -1367,7 +1367,7 @@ func (w *ServerInterfaceWrapper) Issue41(ctx echo.Context) error { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter 1param: %s", err)) } - ctx.Set(Access_tokenScopes, []string{""}) + ctx.Set(Access_tokenScopes, []string{}) // Invoke the callback with all the unmarshalled arguments err = w.Handler.Issue41(ctx, n1param) @@ -1378,7 +1378,7 @@ func (w *ServerInterfaceWrapper) Issue41(ctx echo.Context) error { func (w *ServerInterfaceWrapper) Issue9(ctx echo.Context) error { var err error - ctx.Set(Access_tokenScopes, []string{""}) + ctx.Set(Access_tokenScopes, []string{}) // Parameter object where we will unmarshal all parameters from the context var params Issue9Params @@ -1398,7 +1398,7 @@ func (w *ServerInterfaceWrapper) Issue9(ctx echo.Context) error { func (w *ServerInterfaceWrapper) Issue975(ctx echo.Context) error { var err error - ctx.Set(Access_tokenScopes, []string{""}) + ctx.Set(Access_tokenScopes, []string{}) // Invoke the callback with all the unmarshalled arguments err = w.Handler.Issue975(ctx) From fd06f5aed35010af41fe12a17a0f75e16404af81 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Apr 2023 10:34:26 -0700 Subject: [PATCH 46/82] Bump github.com/getkin/kin-openapi from 0.114.0 to 0.115.0 (#1008) Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.114.0 to 0.115.0. - [Release notes](https://github.com/getkin/kin-openapi/releases) - [Commits](https://github.com/getkin/kin-openapi/compare/v0.114.0...v0.115.0) --- updated-dependencies: - dependency-name: github.com/getkin/kin-openapi dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index e3364ea8f0..31bc950e3e 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module github.com/deepmap/oapi-codegen require ( github.com/apapsch/go-jsonmerge/v2 v2.0.0 - github.com/getkin/kin-openapi v0.114.0 + github.com/getkin/kin-openapi v0.115.0 github.com/gin-gonic/gin v1.9.0 github.com/go-chi/chi/v5 v5.0.8 github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219 diff --git a/go.sum b/go.sum index 5e5310b857..e2d021db56 100644 --- a/go.sum +++ b/go.sum @@ -16,8 +16,8 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= -github.com/getkin/kin-openapi v0.114.0 h1:ar7QiJpDdlR+zSyPjrLf8mNnpoFP/lI90XcywMCFNe8= -github.com/getkin/kin-openapi v0.114.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc= +github.com/getkin/kin-openapi v0.115.0 h1:c8WHRLVY3G8m9jQTy0/DnIuljgRwTCB5twZytQS4JyU= +github.com/getkin/kin-openapi v0.115.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8= From b09bf82646ce421c51b9b4ff440f5d0c1d0ef3c4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 May 2023 13:53:47 -0700 Subject: [PATCH 47/82] Bump golang.org/x/text from 0.8.0 to 0.9.0 (#1023) Bumps [golang.org/x/text](https://github.com/golang/text) from 0.8.0 to 0.9.0. - [Release notes](https://github.com/golang/text/releases) - [Commits](https://github.com/golang/text/compare/v0.8.0...v0.9.0) --- updated-dependencies: - dependency-name: golang.org/x/text dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 31bc950e3e..3f1ea19e77 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/lestrrat-go/jwx v1.2.25 github.com/matryer/moq v0.3.1 github.com/stretchr/testify v1.8.2 - golang.org/x/text v0.8.0 + golang.org/x/text v0.9.0 golang.org/x/tools v0.7.0 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index e2d021db56..6cf490a68e 100644 --- a/go.sum +++ b/go.sum @@ -164,8 +164,8 @@ golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= From bb1cfe95233c0621471a728eebca38683d964522 Mon Sep 17 00:00:00 2001 From: Ben Randall Date: Fri, 5 May 2023 16:54:49 -0400 Subject: [PATCH 48/82] Improve logic for x-omitempty (#1033) Currently x-omitempty only enables you to force the _absences_ of `omitempty`. This PR changes the logic so that the existance of `x-omitempty` will force omit empty to be whatever the user specifies. The logic around omit empty is pretty confusing here though. For example, why is omitEmpty excluded by default if it's nullable (e.g. if `p.Nullable` then `omitEmpty = false`). --- pkg/codegen/schema.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 457e102fe7..e9fccbff99 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -638,17 +638,20 @@ func GenFieldsFromProperties(props []Property) []string { field += fmt.Sprintf(" %s %s", goFieldName, p.GoTypeDef()) + omitEmpty := !p.Nullable && + (!p.Required || p.ReadOnly || p.WriteOnly) && + (!p.Required || !p.ReadOnly || !globalState.options.Compatibility.DisableRequiredReadOnlyAsPointer) + // Support x-omitempty - overrideOmitEmpty := true - if _, ok := p.Extensions[extPropOmitEmpty]; ok { - if extOmitEmpty, err := extParseOmitEmpty(p.Extensions[extPropOmitEmpty]); err == nil { - overrideOmitEmpty = extOmitEmpty + if extOmitEmptyValue, ok := p.Extensions[extPropOmitEmpty]; ok { + if extOmitEmpty, err := extParseOmitEmpty(extOmitEmptyValue); err == nil { + omitEmpty = extOmitEmpty } } fieldTags := make(map[string]string) - if (p.Required && !p.ReadOnly && !p.WriteOnly) || p.Nullable || !overrideOmitEmpty || (p.Required && p.ReadOnly && globalState.options.Compatibility.DisableRequiredReadOnlyAsPointer) { + if !omitEmpty { fieldTags["json"] = p.JsonFieldName if p.NeedsFormTag { fieldTags["form"] = p.JsonFieldName From 844e5dbaf7ce7513fe6d94c0dd42ff6f03e263e7 Mon Sep 17 00:00:00 2001 From: Ilya Bogdanov <11041596+Warboss-rus@users.noreply.github.com> Date: Fri, 5 May 2023 23:56:49 +0300 Subject: [PATCH 49/82] Extract strict middleware definition into a separate file in runtime package to allow middlewares to be reused (#1021) Co-authored-by: ilya.bogdanov --- .../strict/api/petstore-server.gen.go | 5 ++--- .../gen/spec_base/issue.gen.go | 6 +++--- .../gen/spec_ext/issue.gen.go | 7 +++---- internal/test/strict-server/chi/server.gen.go | 5 ++--- .../test/strict-server/echo/server.gen.go | 5 ++--- internal/test/strict-server/gin/server.gen.go | 5 ++--- pkg/codegen/templates/strict/strict-echo.tmpl | 5 ++--- pkg/codegen/templates/strict/strict-gin.tmpl | 5 ++--- pkg/codegen/templates/strict/strict-http.tmpl | 5 ++--- pkg/runtime/strictmiddleware.go | 21 +++++++++++++++++++ 10 files changed, 41 insertions(+), 28 deletions(-) create mode 100644 pkg/runtime/strictmiddleware.go diff --git a/examples/petstore-expanded/strict/api/petstore-server.gen.go b/examples/petstore-expanded/strict/api/petstore-server.gen.go index cd9352ac11..822dee72ae 100644 --- a/examples/petstore-expanded/strict/api/petstore-server.gen.go +++ b/examples/petstore-expanded/strict/api/petstore-server.gen.go @@ -408,9 +408,8 @@ type StrictServerInterface interface { FindPetByID(ctx context.Context, request FindPetByIDRequestObject) (FindPetByIDResponseObject, error) } -type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, args interface{}) (interface{}, error) - -type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc +type StrictHandlerFunc = runtime.StrictHttpHandlerFunc +type StrictMiddlewareFunc = runtime.StrictHttpMiddlewareFunc type StrictHTTPServerOptions struct { RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) diff --git a/internal/test/issues/issue-removed-external-ref/gen/spec_base/issue.gen.go b/internal/test/issues/issue-removed-external-ref/gen/spec_base/issue.gen.go index 09e8df32f5..69766e1c31 100644 --- a/internal/test/issues/issue-removed-external-ref/gen/spec_base/issue.gen.go +++ b/internal/test/issues/issue-removed-external-ref/gen/spec_base/issue.gen.go @@ -10,6 +10,7 @@ import ( "net/http" externalRef0 "github.com/deepmap/oapi-codegen/internal/test/issues/issue-removed-external-ref/gen/spec_ext" + "github.com/deepmap/oapi-codegen/pkg/runtime" "github.com/go-chi/chi/v5" ) @@ -244,9 +245,8 @@ type StrictServerInterface interface { PostNoTrouble(ctx context.Context, request PostNoTroubleRequestObject) (PostNoTroubleResponseObject, error) } -type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, args interface{}) (interface{}, error) - -type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc +type StrictHandlerFunc = runtime.StrictHttpHandlerFunc +type StrictMiddlewareFunc = runtime.StrictHttpMiddlewareFunc type StrictHTTPServerOptions struct { RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) diff --git a/internal/test/issues/issue-removed-external-ref/gen/spec_ext/issue.gen.go b/internal/test/issues/issue-removed-external-ref/gen/spec_ext/issue.gen.go index 21222f879f..ed5a474465 100644 --- a/internal/test/issues/issue-removed-external-ref/gen/spec_ext/issue.gen.go +++ b/internal/test/issues/issue-removed-external-ref/gen/spec_ext/issue.gen.go @@ -4,10 +4,10 @@ package spec_ext import ( - "context" "fmt" "net/http" + "github.com/deepmap/oapi-codegen/pkg/runtime" "github.com/go-chi/chi/v5" ) @@ -161,9 +161,8 @@ type PascalJSONResponse PascalSchema type StrictServerInterface interface { } -type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, args interface{}) (interface{}, error) - -type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc +type StrictHandlerFunc = runtime.StrictHttpHandlerFunc +type StrictMiddlewareFunc = runtime.StrictHttpMiddlewareFunc type StrictHTTPServerOptions struct { RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) diff --git a/internal/test/strict-server/chi/server.gen.go b/internal/test/strict-server/chi/server.gen.go index 236277cfa6..b3904b50e6 100644 --- a/internal/test/strict-server/chi/server.gen.go +++ b/internal/test/strict-server/chi/server.gen.go @@ -892,9 +892,8 @@ type StrictServerInterface interface { HeadersExample(ctx context.Context, request HeadersExampleRequestObject) (HeadersExampleResponseObject, error) } -type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, args interface{}) (interface{}, error) - -type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc +type StrictHandlerFunc = runtime.StrictHttpHandlerFunc +type StrictMiddlewareFunc = runtime.StrictHttpMiddlewareFunc type StrictHTTPServerOptions struct { RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) diff --git a/internal/test/strict-server/echo/server.gen.go b/internal/test/strict-server/echo/server.gen.go index ebd374b9f1..0912230952 100644 --- a/internal/test/strict-server/echo/server.gen.go +++ b/internal/test/strict-server/echo/server.gen.go @@ -706,9 +706,8 @@ type StrictServerInterface interface { HeadersExample(ctx context.Context, request HeadersExampleRequestObject) (HeadersExampleResponseObject, error) } -type StrictHandlerFunc func(ctx echo.Context, args interface{}) (interface{}, error) - -type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc +type StrictHandlerFunc = runtime.StrictEchoHandlerFunc +type StrictMiddlewareFunc = runtime.StrictEchoMiddlewareFunc func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface { return &strictHandler{ssi: ssi, middlewares: middlewares} diff --git a/internal/test/strict-server/gin/server.gen.go b/internal/test/strict-server/gin/server.gen.go index 618db709a2..78b68e597d 100644 --- a/internal/test/strict-server/gin/server.gen.go +++ b/internal/test/strict-server/gin/server.gen.go @@ -763,9 +763,8 @@ type StrictServerInterface interface { HeadersExample(ctx context.Context, request HeadersExampleRequestObject) (HeadersExampleResponseObject, error) } -type StrictHandlerFunc func(ctx *gin.Context, args interface{}) (interface{}, error) - -type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc +type StrictHandlerFunc = runtime.StrictGinHandlerFunc +type StrictMiddlewareFunc = runtime.StrictGinMiddlewareFunc func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface { return &strictHandler{ssi: ssi, middlewares: middlewares} diff --git a/pkg/codegen/templates/strict/strict-echo.tmpl b/pkg/codegen/templates/strict/strict-echo.tmpl index 4bd6aec5d5..86def37a35 100644 --- a/pkg/codegen/templates/strict/strict-echo.tmpl +++ b/pkg/codegen/templates/strict/strict-echo.tmpl @@ -1,6 +1,5 @@ -type StrictHandlerFunc func(ctx echo.Context, args interface{}) (interface{}, error) - -type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc +type StrictHandlerFunc = runtime.StrictEchoHandlerFunc +type StrictMiddlewareFunc = runtime.StrictEchoMiddlewareFunc func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface { return &strictHandler{ssi: ssi, middlewares: middlewares} diff --git a/pkg/codegen/templates/strict/strict-gin.tmpl b/pkg/codegen/templates/strict/strict-gin.tmpl index 9622fb2915..23d8f0b4ec 100644 --- a/pkg/codegen/templates/strict/strict-gin.tmpl +++ b/pkg/codegen/templates/strict/strict-gin.tmpl @@ -1,6 +1,5 @@ -type StrictHandlerFunc func(ctx *gin.Context, args interface{}) (interface{}, error) - -type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc +type StrictHandlerFunc = runtime.StrictGinHandlerFunc +type StrictMiddlewareFunc = runtime.StrictGinMiddlewareFunc func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface { return &strictHandler{ssi: ssi, middlewares: middlewares} diff --git a/pkg/codegen/templates/strict/strict-http.tmpl b/pkg/codegen/templates/strict/strict-http.tmpl index d04503dbc5..b16ed1d399 100644 --- a/pkg/codegen/templates/strict/strict-http.tmpl +++ b/pkg/codegen/templates/strict/strict-http.tmpl @@ -1,6 +1,5 @@ -type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, args interface{}) (interface{}, error) - -type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc +type StrictHandlerFunc = runtime.StrictHttpHandlerFunc +type StrictMiddlewareFunc = runtime.StrictHttpMiddlewareFunc type StrictHTTPServerOptions struct { RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) diff --git a/pkg/runtime/strictmiddleware.go b/pkg/runtime/strictmiddleware.go new file mode 100644 index 0000000000..fac240e12d --- /dev/null +++ b/pkg/runtime/strictmiddleware.go @@ -0,0 +1,21 @@ +package runtime + +import ( + "context" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/labstack/echo/v4" +) + +type StrictEchoHandlerFunc func(ctx echo.Context, request interface{}) (response interface{}, err error) + +type StrictEchoMiddlewareFunc func(f StrictEchoHandlerFunc, operationID string) StrictEchoHandlerFunc + +type StrictHttpHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (response interface{}, err error) + +type StrictHttpMiddlewareFunc func(f StrictHttpHandlerFunc, operationID string) StrictHttpHandlerFunc + +type StrictGinHandlerFunc func(ctx *gin.Context, request interface{}) (response interface{}, err error) + +type StrictGinMiddlewareFunc func(f StrictGinHandlerFunc, operationID string) StrictGinHandlerFunc From 78c53fd8987ad79ce49578b200e3034e5017fcdf Mon Sep 17 00:00:00 2001 From: shiv3 Date: Sat, 6 May 2023 05:59:29 +0900 Subject: [PATCH 50/82] Add initialism-overrides flag (#1007) * Add initialism-overrides flag * Add testcase * FIx option --- cmd/oapi-codegen/oapi-codegen.go | 4 +++ pkg/codegen/codegen.go | 2 +- pkg/codegen/configuration.go | 7 +++--- pkg/codegen/operations.go | 19 ++++++++++----- pkg/codegen/operations_test.go | 2 +- pkg/codegen/utils.go | 18 ++++++++++++++ pkg/codegen/utils_test.go | 42 ++++++++++++++++++++++++++++++++ 7 files changed, 83 insertions(+), 11 deletions(-) diff --git a/cmd/oapi-codegen/oapi-codegen.go b/cmd/oapi-codegen/oapi-codegen.go index 7d9f2cc57a..ea9e008849 100644 --- a/cmd/oapi-codegen/oapi-codegen.go +++ b/cmd/oapi-codegen/oapi-codegen.go @@ -53,6 +53,7 @@ var ( flagExcludeSchemas string flagResponseTypeSuffix string flagAliasTypes bool + flagInitalismOverrides bool ) type configuration struct { @@ -98,6 +99,7 @@ func main() { flag.StringVar(&flagExcludeSchemas, "exclude-schemas", "", "A comma separated list of schemas which must be excluded from generation") flag.StringVar(&flagResponseTypeSuffix, "response-type-suffix", "", "the suffix used for responses types") flag.BoolVar(&flagAliasTypes, "alias-types", false, "Alias type declarations of possible") + flag.BoolVar(&flagInitalismOverrides, "initialism-overrides", false, "Use initialism overrides") flag.Parse() @@ -396,6 +398,8 @@ func updateConfigFromFlags(cfg *configuration) error { cfg.OutputFile = flagOutputFile } + cfg.OutputOptions.InitialismOverrides = flagInitalismOverrides + return nil } diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 956d589329..70dca564d3 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -138,7 +138,7 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) { } } - ops, err := OperationDefinitions(spec) + ops, err := OperationDefinitions(spec, opts.OutputOptions.InitialismOverrides) if err != nil { return "", fmt.Errorf("error creating operation definitions: %w", err) } diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index afa4fc5020..8d7f2e6a16 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -84,9 +84,10 @@ type OutputOptions struct { ExcludeTags []string `yaml:"exclude-tags,omitempty"` // Exclude operations that have one of these tags. Ignored when empty. UserTemplates map[string]string `yaml:"user-templates,omitempty"` // Override built-in templates from user-provided files - ExcludeSchemas []string `yaml:"exclude-schemas,omitempty"` // Exclude from generation schemas with given names. Ignored when empty. - ResponseTypeSuffix string `yaml:"response-type-suffix,omitempty"` // The suffix used for responses types - ClientTypeName string `yaml:"client-type-name,omitempty"` // Override the default generated client type with the value + ExcludeSchemas []string `yaml:"exclude-schemas,omitempty"` // Exclude from generation schemas with given names. Ignored when empty. + ResponseTypeSuffix string `yaml:"response-type-suffix,omitempty"` // The suffix used for responses types + ClientTypeName string `yaml:"client-type-name,omitempty"` // Override the default generated client type with the value + InitialismOverrides bool `yaml:"initialism-overrides,omitempty"` // Whether to use the initialism overrides } // UpdateDefaults sets reasonable default values for unset fields in Configuration diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index 28b991f904..048836f66b 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -483,9 +483,16 @@ func FilterParameterDefinitionByType(params []ParameterDefinition, in string) [] } // OperationDefinitions returns all operations for a swagger definition. -func OperationDefinitions(swagger *openapi3.T) ([]OperationDefinition, error) { +func OperationDefinitions(swagger *openapi3.T, initialismOverrides bool) ([]OperationDefinition, error) { var operations []OperationDefinition + var toCamelCaseFunc func(string) string + if initialismOverrides { + toCamelCaseFunc = ToCamelCaseWithInitialism + } else { + toCamelCaseFunc = ToCamelCase + } + for _, requestPath := range SortedPathsKeys(swagger.Paths) { pathItem := swagger.Paths[requestPath] // These are parameters defined for all methods on a given path. They @@ -505,13 +512,13 @@ func OperationDefinitions(swagger *openapi3.T) ([]OperationDefinition, error) { } // We rely on OperationID to generate function names, it's required if op.OperationID == "" { - op.OperationID, err = generateDefaultOperationID(opName, requestPath) + op.OperationID, err = generateDefaultOperationID(opName, requestPath, toCamelCaseFunc) if err != nil { return nil, fmt.Errorf("error generating default OperationID for %s/%s: %s", opName, requestPath, err) } } else { - op.OperationID = ToCamelCase(op.OperationID) + op.OperationID = toCamelCaseFunc(op.OperationID) } op.OperationID = typeNamePrefix(op.OperationID) + op.OperationID @@ -550,7 +557,7 @@ func OperationDefinitions(swagger *openapi3.T) ([]OperationDefinition, error) { HeaderParams: FilterParameterDefinitionByType(allParams, "header"), QueryParams: FilterParameterDefinitionByType(allParams, "query"), CookieParams: FilterParameterDefinitionByType(allParams, "cookie"), - OperationId: ToCamelCase(op.OperationID), + OperationId: toCamelCaseFunc(op.OperationID), // Replace newlines in summary. Summary: op.Summary, Method: opName, @@ -588,7 +595,7 @@ func OperationDefinitions(swagger *openapi3.T) ([]OperationDefinition, error) { return operations, nil } -func generateDefaultOperationID(opName string, requestPath string) (string, error) { +func generateDefaultOperationID(opName string, requestPath string, toCamelCaseFunc func(string) string) (string, error) { var operationId = strings.ToLower(opName) if opName == "" { @@ -605,7 +612,7 @@ func generateDefaultOperationID(opName string, requestPath string) (string, erro } } - return ToCamelCase(operationId), nil + return toCamelCaseFunc(operationId), nil } // GenerateBodyDefinitions turns the Swagger body definitions into a list of our body diff --git a/pkg/codegen/operations_test.go b/pkg/codegen/operations_test.go index 0eff03e2c2..77a54a8c25 100644 --- a/pkg/codegen/operations_test.go +++ b/pkg/codegen/operations_test.go @@ -131,7 +131,7 @@ func TestGenerateDefaultOperationID(t *testing.T) { } for _, test := range suite { - got, err := generateDefaultOperationID(test.op, test.path) + got, err := generateDefaultOperationID(test.op, test.path, ToCamelCase) if err != nil { if !test.wantErr { t.Fatalf("did not expected error but got %v", err) diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index c386cd3f60..ee51af6360 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -160,6 +160,24 @@ func ToCamelCase(str string) string { return n } +func ToCamelCaseWithInitialism(str string) string { + return replaceInitialism(ToCamelCase(str)) +} + +func replaceInitialism(s string) string { + // These strings do not apply CamelCase + // Do not do CamelCase when these characters match when the preceding character is lowercase + // ["Acl", "Api", "Ascii", "Cpu", "Css", "Dns", "Eof", "Guid", "Html", "Http", "Https", "Id", "Ip", "Json", "Qps", "Ram", "Rpc", "Sla", "Smtp", "Sql", "Ssh", "Tcp", "Tls", "Ttl", "Udp", "Ui", "Gid", "Uid", "Uuid", "Uri", "Url", "Utf8", "Vm", "Xml", "Xmpp", "Xsrf", "Xss", "Sip", "Rtp", "Amqp", "Db", "Ts"] + targetWordRegex := regexp.MustCompile(`(?i)(Acl|Api|Ascii|Cpu|Css|Dns|Eof|Guid|Html|Http|Https|Id|Ip|Json|Qps|Ram|Rpc|Sla|Smtp|Sql|Ssh|Tcp|Tls|Ttl|Udp|Ui|Gid|Uid|Uuid|Uri|Url|Utf8|Vm|Xml|Xmpp|Xsrf|Xss|Sip|Rtp|Amqp|Db|Ts)`) + return targetWordRegex.ReplaceAllStringFunc(s, func(s string) string { + // If the preceding character is lowercase, do not do CamelCase + if unicode.IsLower(rune(s[0])) { + return s + } + return strings.ToUpper(s) + }) +} + // SortedSchemaKeys returns the keys of the given SchemaRef dictionary in sorted // order, since Golang scrambles dictionary keys func SortedSchemaKeys(dict map[string]*openapi3.SchemaRef) []string { diff --git a/pkg/codegen/utils_test.go b/pkg/codegen/utils_test.go index 32708f0692..85b60318c4 100644 --- a/pkg/codegen/utils_test.go +++ b/pkg/codegen/utils_test.go @@ -446,3 +446,45 @@ func TestRefPathToObjName(t *testing.T) { assert.Equal(t, want, RefPathToObjName(in)) } } + +func Test_replaceInitialisms(t *testing.T) { + type args struct { + s string + } + tests := []struct { + name string + args args + want string + }{ + { + name: "empty string", + args: args{s: ""}, + want: "", + }, + { + name: "no initialism", + args: args{s: "foo"}, + want: "foo", + }, + { + name: "one initialism", + args: args{s: "fooId"}, + want: "fooID", + }, + { + name: "two initialism", + args: args{s: "fooIdBarApi"}, + want: "fooIDBarAPI", + }, + { + name: "already initialism", + args: args{s: "fooIDBarAPI"}, + want: "fooIDBarAPI", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equalf(t, tt.want, replaceInitialism(tt.args.s), "replaceInitialism(%v)", tt.args.s) + }) + } +} From 75dfda33da6de37cfe1fbfd1e2bec3714eaed80e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 May 2023 13:59:41 -0700 Subject: [PATCH 51/82] Bump golang.org/x/tools from 0.7.0 to 0.8.0 (#1024) Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.7.0 to 0.8.0. - [Release notes](https://github.com/golang/tools/releases) - [Commits](https://github.com/golang/tools/compare/v0.7.0...v0.8.0) --- updated-dependencies: - dependency-name: golang.org/x/tools dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 3f1ea19e77..7276f986ad 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/matryer/moq v0.3.1 github.com/stretchr/testify v1.8.2 golang.org/x/text v0.9.0 - golang.org/x/tools v0.7.0 + golang.org/x/tools v0.8.0 gopkg.in/yaml.v2 v2.4.0 ) @@ -58,9 +58,9 @@ require ( github.com/valyala/fasttemplate v1.2.2 // indirect golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect golang.org/x/crypto v0.6.0 // indirect - golang.org/x/mod v0.9.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/sys v0.6.0 // indirect + golang.org/x/mod v0.10.0 // indirect + golang.org/x/net v0.9.0 // indirect + golang.org/x/sys v0.7.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect google.golang.org/protobuf v1.28.1 // indirect diff --git a/go.sum b/go.sum index 6cf490a68e..9fe582e8d2 100644 --- a/go.sum +++ b/go.sum @@ -147,11 +147,11 @@ golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUu golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -160,8 +160,8 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= @@ -169,8 +169,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y= +golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From c94277ec7d8570e7828d732603c8d2fbb5104a1b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 May 2023 13:59:52 -0700 Subject: [PATCH 52/82] Bump github.com/getkin/kin-openapi from 0.115.0 to 0.116.0 (#1032) Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.115.0 to 0.116.0. - [Release notes](https://github.com/getkin/kin-openapi/releases) - [Commits](https://github.com/getkin/kin-openapi/compare/v0.115.0...v0.116.0) --- updated-dependencies: - dependency-name: github.com/getkin/kin-openapi dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 7276f986ad..240683feca 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module github.com/deepmap/oapi-codegen require ( github.com/apapsch/go-jsonmerge/v2 v2.0.0 - github.com/getkin/kin-openapi v0.115.0 + github.com/getkin/kin-openapi v0.116.0 github.com/gin-gonic/gin v1.9.0 github.com/go-chi/chi/v5 v5.0.8 github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219 diff --git a/go.sum b/go.sum index 9fe582e8d2..f5edf9d5cc 100644 --- a/go.sum +++ b/go.sum @@ -16,8 +16,8 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= -github.com/getkin/kin-openapi v0.115.0 h1:c8WHRLVY3G8m9jQTy0/DnIuljgRwTCB5twZytQS4JyU= -github.com/getkin/kin-openapi v0.115.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc= +github.com/getkin/kin-openapi v0.116.0 h1:o986hwgMzR972JzOG5j6+WTwWqllZLs1EJKMKCivs2E= +github.com/getkin/kin-openapi v0.116.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8= From fcb892dac336bd8ea82480c9f0fc7236ce1f05e2 Mon Sep 17 00:00:00 2001 From: Martin Micuch Date: Fri, 5 May 2023 23:00:05 +0200 Subject: [PATCH 53/82] Support for hal+json format (#1030) --- pkg/codegen/operations.go | 4 ++++ pkg/codegen/template_helpers.go | 7 ++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index 048836f66b..fe37328480 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -293,6 +293,10 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]ResponseTypeDefini var typeName string switch { + // HAL+JSON: + case StringInArray(contentTypeName, contentTypesHalJSON): + typeName = fmt.Sprintf("HALJSON%s", ToCamelCase(responseName)) + // JSON: case StringInArray(contentTypeName, contentTypesJSON): typeName = fmt.Sprintf("JSON%s", ToCamelCase(responseName)) // YAML: diff --git a/pkg/codegen/template_helpers.go b/pkg/codegen/template_helpers.go index 16671fb393..bae1e30ceb 100644 --- a/pkg/codegen/template_helpers.go +++ b/pkg/codegen/template_helpers.go @@ -34,9 +34,10 @@ const ( ) var ( - contentTypesJSON = []string{echo.MIMEApplicationJSON, "text/x-json", "application/problem+json"} - contentTypesYAML = []string{"application/yaml", "application/x-yaml", "text/yaml", "text/x-yaml"} - contentTypesXML = []string{echo.MIMEApplicationXML, echo.MIMETextXML, "application/problems+xml"} + contentTypesJSON = []string{echo.MIMEApplicationJSON, "text/x-json", "application/problem+json"} + contentTypesHalJSON = []string{"application/hal+json"} + contentTypesYAML = []string{"application/yaml", "application/x-yaml", "text/yaml", "text/x-yaml"} + contentTypesXML = []string{echo.MIMEApplicationXML, echo.MIMETextXML, "application/problems+xml"} responseTypeSuffix = "Response" From d62f8604f96e1eafb206cf97b263c34d5ada4358 Mon Sep 17 00:00:00 2001 From: Selene Date: Fri, 5 May 2023 23:02:14 +0200 Subject: [PATCH 54/82] Fix pointers equality in TypeDefinitionsEquivalent function (#952) Co-authored-by: Marcin Romaszewicz <47459980+deepmap-marcinr@users.noreply.github.com> --- pkg/codegen/utils.go | 3 ++- pkg/codegen/utils_test.go | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index ee51af6360..39225384da 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -17,6 +17,7 @@ import ( "fmt" "go/token" "net/url" + "reflect" "regexp" "sort" "strconv" @@ -922,5 +923,5 @@ func TypeDefinitionsEquivalent(t1, t2 TypeDefinition) bool { if t1.TypeName != t2.TypeName { return false } - return t1.Schema.OAPISchema == t2.Schema.OAPISchema + return reflect.DeepEqual(t1.Schema.OAPISchema, t2.Schema.OAPISchema) } diff --git a/pkg/codegen/utils_test.go b/pkg/codegen/utils_test.go index 85b60318c4..644167a03e 100644 --- a/pkg/codegen/utils_test.go +++ b/pkg/codegen/utils_test.go @@ -433,6 +433,18 @@ func TestSchemaNameToTypeName(t *testing.T) { } } + +func TestTypeDefinitionsEquivalent(t *testing.T) { + def1 := TypeDefinition{TypeName: "name", Schema: Schema{ + OAPISchema: &openapi3.Schema{}, + }} + def2 := TypeDefinition{TypeName: "name", Schema: Schema{ + OAPISchema: &openapi3.Schema{}, + }} + assert.True(t, TypeDefinitionsEquivalent(def1, def2)) +} + + func TestRefPathToObjName(t *testing.T) { t.Parallel() From e9033d161816fd0ec8704aeed30eef7cf2f7518b Mon Sep 17 00:00:00 2001 From: shirou Date: Sat, 6 May 2023 06:52:12 +0900 Subject: [PATCH 55/82] Add InternalServerError when err is not nil on strict-gin (#1012) --- internal/test/strict-server/gin/server.gen.go | 10 ++++++++++ pkg/codegen/templates/strict/strict-gin.tmpl | 1 + 2 files changed, 11 insertions(+) diff --git a/internal/test/strict-server/gin/server.gen.go b/internal/test/strict-server/gin/server.gen.go index 78b68e597d..dcac4155de 100644 --- a/internal/test/strict-server/gin/server.gen.go +++ b/internal/test/strict-server/gin/server.gen.go @@ -798,6 +798,7 @@ func (sh *strictHandler) JSONExample(ctx *gin.Context) { if err != nil { ctx.Error(err) + ctx.Status(http.StatusInternalServerError) } else if validResponse, ok := response.(JSONExampleResponseObject); ok { if err := validResponse.VisitJSONExampleResponse(ctx.Writer); err != nil { ctx.Error(err) @@ -829,6 +830,7 @@ func (sh *strictHandler) MultipartExample(ctx *gin.Context) { if err != nil { ctx.Error(err) + ctx.Status(http.StatusInternalServerError) } else if validResponse, ok := response.(MultipartExampleResponseObject); ok { if err := validResponse.VisitMultipartExampleResponse(ctx.Writer); err != nil { ctx.Error(err) @@ -895,6 +897,7 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx *gin.Context) { if err != nil { ctx.Error(err) + ctx.Status(http.StatusInternalServerError) } else if validResponse, ok := response.(MultipleRequestAndResponseTypesResponseObject); ok { if err := validResponse.VisitMultipleRequestAndResponseTypesResponse(ctx.Writer); err != nil { ctx.Error(err) @@ -921,6 +924,7 @@ func (sh *strictHandler) ReservedGoKeywordParameters(ctx *gin.Context, pType str if err != nil { ctx.Error(err) + ctx.Status(http.StatusInternalServerError) } else if validResponse, ok := response.(ReservedGoKeywordParametersResponseObject); ok { if err := validResponse.VisitReservedGoKeywordParametersResponse(ctx.Writer); err != nil { ctx.Error(err) @@ -953,6 +957,7 @@ func (sh *strictHandler) ReusableResponses(ctx *gin.Context) { if err != nil { ctx.Error(err) + ctx.Status(http.StatusInternalServerError) } else if validResponse, ok := response.(ReusableResponsesResponseObject); ok { if err := validResponse.VisitReusableResponsesResponse(ctx.Writer); err != nil { ctx.Error(err) @@ -985,6 +990,7 @@ func (sh *strictHandler) TextExample(ctx *gin.Context) { if err != nil { ctx.Error(err) + ctx.Status(http.StatusInternalServerError) } else if validResponse, ok := response.(TextExampleResponseObject); ok { if err := validResponse.VisitTextExampleResponse(ctx.Writer); err != nil { ctx.Error(err) @@ -1011,6 +1017,7 @@ func (sh *strictHandler) UnknownExample(ctx *gin.Context) { if err != nil { ctx.Error(err) + ctx.Status(http.StatusInternalServerError) } else if validResponse, ok := response.(UnknownExampleResponseObject); ok { if err := validResponse.VisitUnknownExampleResponse(ctx.Writer); err != nil { ctx.Error(err) @@ -1039,6 +1046,7 @@ func (sh *strictHandler) UnspecifiedContentType(ctx *gin.Context) { if err != nil { ctx.Error(err) + ctx.Status(http.StatusInternalServerError) } else if validResponse, ok := response.(UnspecifiedContentTypeResponseObject); ok { if err := validResponse.VisitUnspecifiedContentTypeResponse(ctx.Writer); err != nil { ctx.Error(err) @@ -1074,6 +1082,7 @@ func (sh *strictHandler) URLEncodedExample(ctx *gin.Context) { if err != nil { ctx.Error(err) + ctx.Status(http.StatusInternalServerError) } else if validResponse, ok := response.(URLEncodedExampleResponseObject); ok { if err := validResponse.VisitURLEncodedExampleResponse(ctx.Writer); err != nil { ctx.Error(err) @@ -1108,6 +1117,7 @@ func (sh *strictHandler) HeadersExample(ctx *gin.Context, params HeadersExampleP if err != nil { ctx.Error(err) + ctx.Status(http.StatusInternalServerError) } else if validResponse, ok := response.(HeadersExampleResponseObject); ok { if err := validResponse.VisitHeadersExampleResponse(ctx.Writer); err != nil { ctx.Error(err) diff --git a/pkg/codegen/templates/strict/strict-gin.tmpl b/pkg/codegen/templates/strict/strict-gin.tmpl index 23d8f0b4ec..0c36f40eeb 100644 --- a/pkg/codegen/templates/strict/strict-gin.tmpl +++ b/pkg/codegen/templates/strict/strict-gin.tmpl @@ -82,6 +82,7 @@ type strictHandler struct { if err != nil { ctx.Error(err) + ctx.Status(http.StatusInternalServerError) } else if validResponse, ok := response.({{$opid | ucFirst}}ResponseObject); ok { if err := validResponse.Visit{{$opid}}Response(ctx.Writer); err != nil { ctx.Error(err) From 8fbbe02254ebc3a9359a5565859770aaf2122e41 Mon Sep 17 00:00:00 2001 From: Christoph Petrausch <263448+hikhvar@users.noreply.github.com> Date: Fri, 5 May 2023 23:52:29 +0200 Subject: [PATCH 56/82] fix: Use helper function to detect general JSON responses (#945) With out this fix, there are no responses generated if for example the response type is 'application/vnd.api+json' Co-authored-by: Marcin Romaszewicz <47459980+deepmap-marcinr@users.noreply.github.com> --- pkg/codegen/operations.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index fe37328480..01666ff38f 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -297,7 +297,7 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]ResponseTypeDefini case StringInArray(contentTypeName, contentTypesHalJSON): typeName = fmt.Sprintf("HALJSON%s", ToCamelCase(responseName)) // JSON: - case StringInArray(contentTypeName, contentTypesJSON): + case StringInArray(contentTypeName, contentTypesJSON) || util.IsMediaTypeJson(contentTypeName): typeName = fmt.Sprintf("JSON%s", ToCamelCase(responseName)) // YAML: case StringInArray(contentTypeName, contentTypesYAML): From 8b1c1e2aab0ea91835b3d5418427a64dc3beb1fb Mon Sep 17 00:00:00 2001 From: Stephen Blackstone Date: Fri, 5 May 2023 17:52:58 -0400 Subject: [PATCH 57/82] Update authenticated example - set token in echo context.. (#917) * Update authenticated example so that we demonstate how to make the token available to the handlers * Favor key instead of string --- .../authenticated-api/echo/server/jwt_authenticator.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/examples/authenticated-api/echo/server/jwt_authenticator.go b/examples/authenticated-api/echo/server/jwt_authenticator.go index 4d6b334abd..2c1699b304 100644 --- a/examples/authenticated-api/echo/server/jwt_authenticator.go +++ b/examples/authenticated-api/echo/server/jwt_authenticator.go @@ -7,6 +7,7 @@ import ( "net/http" "strings" + "github.com/deepmap/oapi-codegen/pkg/middleware" "github.com/getkin/kin-openapi/openapi3filter" "github.com/lestrrat-go/jwx/jwt" ) @@ -17,6 +18,8 @@ type JWSValidator interface { ValidateJWS(jws string) (jwt.Token, error) } +const JWTClaimsContextKey = "jwt_claims" + var ( ErrNoAuthHeader = errors.New("Authorization header is missing") ErrInvalidAuthHeader = errors.New("Authorization header is malformed") @@ -73,6 +76,12 @@ func Authenticate(v JWSValidator, ctx context.Context, input *openapi3filter.Aut if err != nil { return fmt.Errorf("token claims don't match: %w", err) } + + // Set the property on the echo context so the handler is able to + // access the claims data we generate in here. + eCtx := middleware.GetEchoContext(ctx) + eCtx.Set(JWTClaimsContextKey, token) + return nil } From a37e91dc254d08a81c5f78dd7a5ee5dffd3044b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCrbach?= Date: Wed, 25 Jan 2023 09:00:23 +0100 Subject: [PATCH 58/82] fix: strict server with union type --- internal/test/strict-server/chi/server.gen.go | 134 ++++++++++++++-- internal/test/strict-server/chi/server.go | 14 ++ internal/test/strict-server/chi/types.gen.go | 3 + .../test/strict-server/client/client.gen.go | 146 ++++++++++++++++++ .../test/strict-server/echo/server.gen.go | 124 +++++++++++++-- internal/test/strict-server/echo/server.go | 14 ++ internal/test/strict-server/echo/types.gen.go | 3 + internal/test/strict-server/gin/server.gen.go | 132 ++++++++++++++-- internal/test/strict-server/gin/server.go | 14 ++ internal/test/strict-server/gin/types.gen.go | 3 + .../test/strict-server/strict-schema.yaml | 29 ++++ internal/test/strict-server/strict_test.go | 13 +- .../templates/strict/strict-interface.tmpl | 3 +- 13 files changed, 579 insertions(+), 53 deletions(-) diff --git a/internal/test/strict-server/chi/server.gen.go b/internal/test/strict-server/chi/server.gen.go index b3904b50e6..ac1c6da023 100644 --- a/internal/test/strict-server/chi/server.gen.go +++ b/internal/test/strict-server/chi/server.gen.go @@ -54,6 +54,9 @@ type ServerInterface interface { // (POST /with-headers) HeadersExample(w http.ResponseWriter, r *http.Request, params HeadersExampleParams) + + // (POST /with-union) + UnionExample(w http.ResponseWriter, r *http.Request) } // ServerInterfaceWrapper converts contexts to parameters. @@ -275,6 +278,21 @@ func (siw *ServerInterfaceWrapper) HeadersExample(w http.ResponseWriter, r *http handler.ServeHTTP(w, r.WithContext(ctx)) } +// UnionExample operation middleware +func (siw *ServerInterfaceWrapper) UnionExample(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.UnionExample(w, r) + }) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r.WithContext(ctx)) +} + type UnescapedCookieParamError struct { ParamName string Err error @@ -418,6 +436,9 @@ func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handl r.Group(func(r chi.Router) { r.Post(options.BaseURL+"/with-headers", wrapper.HeadersExample) }) + r.Group(func(r chi.Router) { + r.Post(options.BaseURL+"/with-union", wrapper.UnionExample) + }) return r } @@ -858,6 +879,51 @@ func (response HeadersExampledefaultResponse) VisitHeadersExampleResponse(w http return nil } +type UnionExampleRequestObject struct { + Body *UnionExampleJSONRequestBody +} + +type UnionExampleResponseObject interface { + VisitUnionExampleResponse(w http.ResponseWriter) error +} + +type UnionExample200ResponseHeaders struct { + Header1 string + Header2 int +} + +type UnionExample200JSONResponse struct { + Body struct { + union json.RawMessage + } + Headers UnionExample200ResponseHeaders +} + +func (response UnionExample200JSONResponse) VisitUnionExampleResponse(w http.ResponseWriter) error { + w.Header().Set("header1", fmt.Sprint(response.Headers.Header1)) + w.Header().Set("header2", fmt.Sprint(response.Headers.Header2)) + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response.Body.union) +} + +type UnionExample400Response = BadrequestResponse + +func (response UnionExample400Response) VisitUnionExampleResponse(w http.ResponseWriter) error { + w.WriteHeader(400) + return nil +} + +type UnionExampledefaultResponse struct { + StatusCode int +} + +func (response UnionExampledefaultResponse) VisitUnionExampleResponse(w http.ResponseWriter) error { + w.WriteHeader(response.StatusCode) + return nil +} + // StrictServerInterface represents all server handlers. type StrictServerInterface interface { @@ -890,6 +956,9 @@ type StrictServerInterface interface { // (POST /with-headers) HeadersExample(ctx context.Context, request HeadersExampleRequestObject) (HeadersExampleResponseObject, error) + + // (POST /with-union) + UnionExample(ctx context.Context, request UnionExampleRequestObject) (UnionExampleResponseObject, error) } type StrictHandlerFunc = runtime.StrictHttpHandlerFunc @@ -1259,26 +1328,57 @@ func (sh *strictHandler) HeadersExample(w http.ResponseWriter, r *http.Request, } } +// UnionExample operation middleware +func (sh *strictHandler) UnionExample(w http.ResponseWriter, r *http.Request) { + var request UnionExampleRequestObject + + var body UnionExampleJSONRequestBody + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) + return + } + request.Body = &body + + handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { + return sh.ssi.UnionExample(ctx, request.(UnionExampleRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "UnionExample") + } + + response, err := handler(r.Context(), w, r, request) + + if err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } else if validResponse, ok := response.(UnionExampleResponseObject); ok { + if err := validResponse.VisitUnionExampleResponse(w); err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } + } else if response != nil { + sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("Unexpected response type: %T", response)) + } +} + // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/+xYX2/bNhD/KgS3p0KynDRPeluDotu6rYOTPg15oMWzzFYiuePJimHouw8UJf+pFS/O", - "7BgY+mbRd787/u4Pj1zxzJTWaNDkeLriCM4a7aD9mAqJ8HcFjvyXBJehsqSM5il/J+Sk+6+JOELlxLSA", - "Xt3LZ0YT6FZVWFuoTHjV5Ivz+ivusjmUwv/6EWHGU/5DsnElCf+6BB5FaQvgTdNE33jw6SOP+ByEBGy9", - "DT+vdrFpaYGn3BEqnXMPEsSuB8WUJsgBvTUv2jnhBXo/0hW3aCwgqcDRQhQVDFvqVsz0C2QUdqD0zOxz", - "eWs0CaUdk2o2AwRNrCOPeQzHXGWtQQLJpkvmLWTEHOACkEecFHnH+N32OuscdjziC0AXDF2NxqOxj5ex", - "oIVVPOVv26WIW0HzdkPrAFkzFPdf7z79wZRjoiJTClKZKIolKwW6uSgKkExpMt7HKiM34q0pbCP/i+zU", - "33dc+rRpM+idkctzZEybmFv5fD0ev1JiNhG/CcaGMNZOJVsV1sLMRFUMkP5Zf9Wm1gwQDXY7S8qqIGUF", - "0nawdtn+vRd5DuVrvGRmsIylIHEm1k9l6aLEd81gsEju5qZ2bG5qRoZJEAWrFc1Zr/hNdSvNBHNK5wWw", - "3qloMJIFdD33Jy0n3V7uPcbZaynaQXmM67qO2+BVWIDOjAT5MlhVihwSq/NddY8tiKd8uiSftvvd9URJ", - "FHGCR0psIZQ+fHS8Ujv5zvTJCjuUK0J7JMo4N/FXWNYGZWwFihII0CUrb73xwDkMlPKfa0mWCc2mwLQo", - "QTIxI0D2wbAO0u2V7KSz+8F8DCIbqPa8XX+kf624p6Q9g3nEvQGeBlZCXSv0QSesIDpA28O/5ud/CkDP", - "Zpj04h1Tw22wb1Fr6hBmzrfEocgN8BcsTbYkLjMwHM64vdn3Nc4gH8mnz/17eHzWkX/C1vfatX0sYVVY", - "fJqzTus5tL2wkz6DxYWSYJLS3hyJfDFSnYVMzRTIuNtFHHx7qiXcGp0h0O4I5O8T2hBbg/lrDs2BBQYi", - "5gyrgZWVI2aFc0xR20UKFa5KEvaax+eNZ7fB0v2mnR6K6pszxfTNpSJ6M746XuXtmfNmZ5R5oh4nv70P", - "MsfeF082Mx058Z3O7oXK2V9S4q0XleES/jkIbM70DNTCT0RaMgSqUINkCyX6R4C92uwANmEdmoWCG5tp", - "qH/dOWYgig5iXfPo0AvQw//4eeKc72bnztMm4uGJKyRLhYWPKJFNkyQ8jY1cLfIccKRMIqzizUPzTwAA", - "AP//O0NNuucUAAA=", + "H4sIAAAAAAAC/+xYS2/jNhD+KwO2p4VkOdmcdOsGi227bVM4yanIgRZHNnclkiVHVgzD/72gKL9ixbW3", + "fqDB3vSYF795cmYs06XRChU5ls6YRWe0cti8DLmw+HeFjvybQJdZaUhqxVL2gYtB+28eMYuV48MCF+ye", + "PtOKUDWs3JhCZtyzJl+c558xl42x5P7pR4s5S9kPycqUJPx1CT7z0hTI5vN59MKCu88sYmPkAm1jbXi8", + "2pRNU4MsZY6sVCPmhQSy604yqQhHaL02T9oa4QkWdqQzZqw2aEkGjCa8qLBbU/tFD79gRuEEUuV6G8tb", + "rYhL5UDIPEeLiqAFD7wMB64yRltCAcMpeA0ZgUM7QcsiRpK8Yex+/Tu0BjsWsQlaFxRd9fq9vveXNqi4", + "kSxl75tPETOcxs2Blg4yusvvv97f/QHSAa9Il5xkxotiCiW3bsyLAgVIRdrbWGXkeqxRZRvP/yJa9o8t", + "lj5smgj6oMX0FBHTBOZaPF/3+2cKzHnEboKyLhlLo5K1DGvE5LwqOkB/VF+VrhWgtdq2J0vKqiBpuKV1", + "Z22i/fuCZB/Il/KSXNsyFpz4iVA/lqaLAt8Wg84kuR/r2sFY10AaBPICakljWDC+yG6pgIOTalQgLIyK", + "Oj1ZYFtzf1Ji0J7lwcs4eS5FG1Ke47qu48Z5lS1QZVqg+DaxsuQjTIwabbJ72ZxYyoZT8mG7XV2PFEQR", + "I3ymxBRcqt2t40zl5DvSR0vskK4Wm5Yo4pGOv+K01lbEhlteIqF1ycxrn3vBI+xI5T+XlJBxBUMExUsU", + "wHNCC580tCLdVsoOWr2f9OdAshLV9NvlS/rXjHlImh7MIuYVsDSgEvJaWu90shVGO2B7+tf4/E8OWKAZ", + "Jr14Q1V3GVyUqCV0FnPnS2KX5zrwC5oGaxSXGRh2R9zW7HuOHuQ9+Xrff8DnvVr+EUvfuXP7UMCq8PF1", + "zFqufWD7xkq6B4oTKVAnpbk5UPLFQHUGM5lLFHF7ijjY9lpJuNUqs0ibI5C/TyhNsBTmrzk0RggIROA0", + "1Ahl5QgMdw4kNVWkkOGqJHCreDyuLLsNmh5W5XSXV9+dyKfvLuXRm/7V4SzvTxw3G6PMK/k4+O1joDn0", + "vni0menAie94ei+Uzv6SEq9tVLpT+OdAsOrpGcqJn4iUAItUWYUCJpIvlgBbudkKWLm1axYKZqymocV2", + "55CBKNop65pFuzZAT294PXHKvdm54rRSctee6tH/hnaGftkbpFb/myWUVniXN3nxwifRniY8vb0YmEcs", + "rDlDwahs4bOayKRJEtajPVfz0QhtT+qEG+lR+CcAAP//MLFBPesWAAA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/chi/server.go b/internal/test/strict-server/chi/server.go index b0724db19f..669d4da4f4 100644 --- a/internal/test/strict-server/chi/server.go +++ b/internal/test/strict-server/chi/server.go @@ -5,6 +5,7 @@ package api import ( "context" + "encoding/json" "io" "mime/multipart" ) @@ -104,3 +105,16 @@ func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableRes func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) { return ReservedGoKeywordParameters200TextResponse(""), nil } + +func (s StrictServer) UnionExample(ctx context.Context, request UnionExampleRequestObject) (UnionExampleResponseObject, error) { + union, err := json.Marshal(*request.Body) + if err != nil { + return nil, err + } + + return UnionExample200JSONResponse{ + Body: struct{ union json.RawMessage }{ + union: union, + }, + }, nil +} diff --git a/internal/test/strict-server/chi/types.gen.go b/internal/test/strict-server/chi/types.gen.go index 33827cb7a4..023ebed8f6 100644 --- a/internal/test/strict-server/chi/types.gen.go +++ b/internal/test/strict-server/chi/types.gen.go @@ -52,3 +52,6 @@ type URLEncodedExampleFormdataRequestBody = Example // HeadersExampleJSONRequestBody defines body for HeadersExample for application/json ContentType. type HeadersExampleJSONRequestBody = Example + +// UnionExampleJSONRequestBody defines body for UnionExample for application/json ContentType. +type UnionExampleJSONRequestBody = Example diff --git a/internal/test/strict-server/client/client.gen.go b/internal/test/strict-server/client/client.gen.go index 5ec0210b50..d68c6c1e36 100644 --- a/internal/test/strict-server/client/client.gen.go +++ b/internal/test/strict-server/client/client.gen.go @@ -66,6 +66,9 @@ type URLEncodedExampleFormdataRequestBody = Example // HeadersExampleJSONRequestBody defines body for HeadersExample for application/json ContentType. type HeadersExampleJSONRequestBody = Example +// UnionExampleJSONRequestBody defines body for UnionExample for application/json ContentType. +type UnionExampleJSONRequestBody = Example + // RequestEditorFn is the function signature for the RequestEditor callback function type RequestEditorFn func(ctx context.Context, req *http.Request) error @@ -184,6 +187,11 @@ type ClientInterface interface { HeadersExampleWithBody(ctx context.Context, params *HeadersExampleParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) HeadersExample(ctx context.Context, params *HeadersExampleParams, body HeadersExampleJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // UnionExample request with any body + UnionExampleWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + UnionExample(ctx context.Context, body UnionExampleJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) } func (c *Client) JSONExampleWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { @@ -402,6 +410,30 @@ func (c *Client) HeadersExample(ctx context.Context, params *HeadersExampleParam return c.Client.Do(req) } +func (c *Client) UnionExampleWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewUnionExampleRequestWithBody(c.Server, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) UnionExample(ctx context.Context, body UnionExampleJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewUnionExampleRequest(c.Server, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + // NewJSONExampleRequest calls the generic JSONExample builder with application/json body func NewJSONExampleRequest(server string, body JSONExampleJSONRequestBody) (*http.Request, error) { var bodyReader io.Reader @@ -797,6 +829,46 @@ func NewHeadersExampleRequestWithBody(server string, params *HeadersExampleParam return req, nil } +// NewUnionExampleRequest calls the generic UnionExample builder with application/json body +func NewUnionExampleRequest(server string, body UnionExampleJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewUnionExampleRequestWithBody(server, "application/json", bodyReader) +} + +// NewUnionExampleRequestWithBody generates requests for UnionExample with any type of body +func NewUnionExampleRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/with-union") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error { for _, r := range c.RequestEditors { if err := r(ctx, req); err != nil { @@ -885,6 +957,11 @@ type ClientWithResponsesInterface interface { HeadersExampleWithBodyWithResponse(ctx context.Context, params *HeadersExampleParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*HeadersExampleResponse, error) HeadersExampleWithResponse(ctx context.Context, params *HeadersExampleParams, body HeadersExampleJSONRequestBody, reqEditors ...RequestEditorFn) (*HeadersExampleResponse, error) + + // UnionExample request with any body + UnionExampleWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UnionExampleResponse, error) + + UnionExampleWithResponse(ctx context.Context, body UnionExampleJSONRequestBody, reqEditors ...RequestEditorFn) (*UnionExampleResponse, error) } type JSONExampleResponse struct { @@ -1101,6 +1178,30 @@ func (r HeadersExampleResponse) StatusCode() int { return 0 } +type UnionExampleResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + union json.RawMessage + } +} + +// Status returns HTTPResponse.Status +func (r UnionExampleResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r UnionExampleResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + // JSONExampleWithBodyWithResponse request with arbitrary body returning *JSONExampleResponse func (c *ClientWithResponses) JSONExampleWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*JSONExampleResponse, error) { rsp, err := c.JSONExampleWithBody(ctx, contentType, body, reqEditors...) @@ -1255,6 +1356,23 @@ func (c *ClientWithResponses) HeadersExampleWithResponse(ctx context.Context, pa return ParseHeadersExampleResponse(rsp) } +// UnionExampleWithBodyWithResponse request with arbitrary body returning *UnionExampleResponse +func (c *ClientWithResponses) UnionExampleWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UnionExampleResponse, error) { + rsp, err := c.UnionExampleWithBody(ctx, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseUnionExampleResponse(rsp) +} + +func (c *ClientWithResponses) UnionExampleWithResponse(ctx context.Context, body UnionExampleJSONRequestBody, reqEditors ...RequestEditorFn) (*UnionExampleResponse, error) { + rsp, err := c.UnionExample(ctx, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseUnionExampleResponse(rsp) +} + // ParseJSONExampleResponse parses an HTTP response from a JSONExampleWithResponse call func ParseJSONExampleResponse(rsp *http.Response) (*JSONExampleResponse, error) { bodyBytes, err := io.ReadAll(rsp.Body) @@ -1457,3 +1575,31 @@ func ParseHeadersExampleResponse(rsp *http.Response) (*HeadersExampleResponse, e return response, nil } + +// ParseUnionExampleResponse parses an HTTP response from a UnionExampleWithResponse call +func ParseUnionExampleResponse(rsp *http.Response) (*UnionExampleResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &UnionExampleResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest struct { + union json.RawMessage + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} diff --git a/internal/test/strict-server/echo/server.gen.go b/internal/test/strict-server/echo/server.gen.go index 0912230952..4d8936781d 100644 --- a/internal/test/strict-server/echo/server.gen.go +++ b/internal/test/strict-server/echo/server.gen.go @@ -54,6 +54,9 @@ type ServerInterface interface { // (POST /with-headers) HeadersExample(ctx echo.Context, params HeadersExampleParams) error + + // (POST /with-union) + UnionExample(ctx echo.Context) error } // ServerInterfaceWrapper converts echo contexts to parameters. @@ -195,6 +198,15 @@ func (w *ServerInterfaceWrapper) HeadersExample(ctx echo.Context) error { return err } +// UnionExample converts echo context to params. +func (w *ServerInterfaceWrapper) UnionExample(ctx echo.Context) error { + var err error + + // Invoke the callback with all the unmarshalled arguments + err = w.Handler.UnionExample(ctx) + return err +} + // This is a simple interface which specifies echo.Route addition functions which // are present on both echo.Echo and echo.Group, since we want to allow using // either of them for path registration @@ -233,6 +245,7 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL router.POST(baseURL+"/unspecified-content-type", wrapper.UnspecifiedContentType) router.POST(baseURL+"/urlencoded", wrapper.URLEncodedExample) router.POST(baseURL+"/with-headers", wrapper.HeadersExample) + router.POST(baseURL+"/with-union", wrapper.UnionExample) } @@ -672,6 +685,51 @@ func (response HeadersExampledefaultResponse) VisitHeadersExampleResponse(w http return nil } +type UnionExampleRequestObject struct { + Body *UnionExampleJSONRequestBody +} + +type UnionExampleResponseObject interface { + VisitUnionExampleResponse(w http.ResponseWriter) error +} + +type UnionExample200ResponseHeaders struct { + Header1 string + Header2 int +} + +type UnionExample200JSONResponse struct { + Body struct { + union json.RawMessage + } + Headers UnionExample200ResponseHeaders +} + +func (response UnionExample200JSONResponse) VisitUnionExampleResponse(w http.ResponseWriter) error { + w.Header().Set("header1", fmt.Sprint(response.Headers.Header1)) + w.Header().Set("header2", fmt.Sprint(response.Headers.Header2)) + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response.Body.union) +} + +type UnionExample400Response = BadrequestResponse + +func (response UnionExample400Response) VisitUnionExampleResponse(w http.ResponseWriter) error { + w.WriteHeader(400) + return nil +} + +type UnionExampledefaultResponse struct { + StatusCode int +} + +func (response UnionExampledefaultResponse) VisitUnionExampleResponse(w http.ResponseWriter) error { + w.WriteHeader(response.StatusCode) + return nil +} + // StrictServerInterface represents all server handlers. type StrictServerInterface interface { @@ -704,6 +762,9 @@ type StrictServerInterface interface { // (POST /with-headers) HeadersExample(ctx context.Context, request HeadersExampleRequestObject) (HeadersExampleResponseObject, error) + + // (POST /with-union) + UnionExample(ctx context.Context, request UnionExampleRequestObject) (UnionExampleResponseObject, error) } type StrictHandlerFunc = runtime.StrictEchoHandlerFunc @@ -1036,26 +1097,55 @@ func (sh *strictHandler) HeadersExample(ctx echo.Context, params HeadersExampleP return nil } +// UnionExample operation middleware +func (sh *strictHandler) UnionExample(ctx echo.Context) error { + var request UnionExampleRequestObject + + var body UnionExampleJSONRequestBody + if err := ctx.Bind(&body); err != nil { + return err + } + request.Body = &body + + handler := func(ctx echo.Context, request interface{}) (interface{}, error) { + return sh.ssi.UnionExample(ctx.Request().Context(), request.(UnionExampleRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "UnionExample") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(UnionExampleResponseObject); ok { + return validResponse.VisitUnionExampleResponse(ctx.Response()) + } else if response != nil { + return fmt.Errorf("Unexpected response type: %T", response) + } + return nil +} + // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/+xYX2/bNhD/KgS3p0KynDRPeluDotu6rYOTPg15oMWzzFYiuePJimHouw8UJf+pFS/O", - "7BgY+mbRd787/u4Pj1zxzJTWaNDkeLriCM4a7aD9mAqJ8HcFjvyXBJehsqSM5il/J+Sk+6+JOELlxLSA", - "Xt3LZ0YT6FZVWFuoTHjV5Ivz+ivusjmUwv/6EWHGU/5DsnElCf+6BB5FaQvgTdNE33jw6SOP+ByEBGy9", - "DT+vdrFpaYGn3BEqnXMPEsSuB8WUJsgBvTUv2jnhBXo/0hW3aCwgqcDRQhQVDFvqVsz0C2QUdqD0zOxz", - "eWs0CaUdk2o2AwRNrCOPeQzHXGWtQQLJpkvmLWTEHOACkEecFHnH+N32OuscdjziC0AXDF2NxqOxj5ex", - "oIVVPOVv26WIW0HzdkPrAFkzFPdf7z79wZRjoiJTClKZKIolKwW6uSgKkExpMt7HKiM34q0pbCP/i+zU", - "33dc+rRpM+idkctzZEybmFv5fD0ev1JiNhG/CcaGMNZOJVsV1sLMRFUMkP5Zf9Wm1gwQDXY7S8qqIGUF", - "0nawdtn+vRd5DuVrvGRmsIylIHEm1k9l6aLEd81gsEju5qZ2bG5qRoZJEAWrFc1Zr/hNdSvNBHNK5wWw", - "3qloMJIFdD33Jy0n3V7uPcbZaynaQXmM67qO2+BVWIDOjAT5MlhVihwSq/NddY8tiKd8uiSftvvd9URJ", - "FHGCR0psIZQ+fHS8Ujv5zvTJCjuUK0J7JMo4N/FXWNYGZWwFihII0CUrb73xwDkMlPKfa0mWCc2mwLQo", - "QTIxI0D2wbAO0u2V7KSz+8F8DCIbqPa8XX+kf624p6Q9g3nEvQGeBlZCXSv0QSesIDpA28O/5ud/CkDP", - "Zpj04h1Tw22wb1Fr6hBmzrfEocgN8BcsTbYkLjMwHM64vdn3Nc4gH8mnz/17eHzWkX/C1vfatX0sYVVY", - "fJqzTus5tL2wkz6DxYWSYJLS3hyJfDFSnYVMzRTIuNtFHHx7qiXcGp0h0O4I5O8T2hBbg/lrDs2BBQYi", - "5gyrgZWVI2aFc0xR20UKFa5KEvaax+eNZ7fB0v2mnR6K6pszxfTNpSJ6M746XuXtmfNmZ5R5oh4nv70P", - "MsfeF082Mx058Z3O7oXK2V9S4q0XleES/jkIbM70DNTCT0RaMgSqUINkCyX6R4C92uwANmEdmoWCG5tp", - "qH/dOWYgig5iXfPo0AvQw//4eeKc72bnztMm4uGJKyRLhYWPKJFNkyQ8jY1cLfIccKRMIqzizUPzTwAA", - "AP//O0NNuucUAAA=", + "H4sIAAAAAAAC/+xYS2/jNhD+KwO2p4VkOdmcdOsGi227bVM4yanIgRZHNnclkiVHVgzD/72gKL9ixbW3", + "fqDB3vSYF795cmYs06XRChU5ls6YRWe0cti8DLmw+HeFjvybQJdZaUhqxVL2gYtB+28eMYuV48MCF+ye", + "PtOKUDWs3JhCZtyzJl+c558xl42x5P7pR4s5S9kPycqUJPx1CT7z0hTI5vN59MKCu88sYmPkAm1jbXi8", + "2pRNU4MsZY6sVCPmhQSy604yqQhHaL02T9oa4QkWdqQzZqw2aEkGjCa8qLBbU/tFD79gRuEEUuV6G8tb", + "rYhL5UDIPEeLiqAFD7wMB64yRltCAcMpeA0ZgUM7QcsiRpK8Yex+/Tu0BjsWsQlaFxRd9fq9vveXNqi4", + "kSxl75tPETOcxs2Blg4yusvvv97f/QHSAa9Il5xkxotiCiW3bsyLAgVIRdrbWGXkeqxRZRvP/yJa9o8t", + "lj5smgj6oMX0FBHTBOZaPF/3+2cKzHnEboKyLhlLo5K1DGvE5LwqOkB/VF+VrhWgtdq2J0vKqiBpuKV1", + "Z22i/fuCZB/Il/KSXNsyFpz4iVA/lqaLAt8Wg84kuR/r2sFY10AaBPICakljWDC+yG6pgIOTalQgLIyK", + "Oj1ZYFtzf1Ji0J7lwcs4eS5FG1Ke47qu48Z5lS1QZVqg+DaxsuQjTIwabbJ72ZxYyoZT8mG7XV2PFEQR", + "I3ymxBRcqt2t40zl5DvSR0vskK4Wm5Yo4pGOv+K01lbEhlteIqF1ycxrn3vBI+xI5T+XlJBxBUMExUsU", + "wHNCC580tCLdVsoOWr2f9OdAshLV9NvlS/rXjHlImh7MIuYVsDSgEvJaWu90shVGO2B7+tf4/E8OWKAZ", + "Jr14Q1V3GVyUqCV0FnPnS2KX5zrwC5oGaxSXGRh2R9zW7HuOHuQ9+Xrff8DnvVr+EUvfuXP7UMCq8PF1", + "zFqufWD7xkq6B4oTKVAnpbk5UPLFQHUGM5lLFHF7ijjY9lpJuNUqs0ibI5C/TyhNsBTmrzk0RggIROA0", + "1Ahl5QgMdw4kNVWkkOGqJHCreDyuLLsNmh5W5XSXV9+dyKfvLuXRm/7V4SzvTxw3G6PMK/k4+O1joDn0", + "vni0menAie94ei+Uzv6SEq9tVLpT+OdAsOrpGcqJn4iUAItUWYUCJpIvlgBbudkKWLm1axYKZqymocV2", + "55CBKNop65pFuzZAT294PXHKvdm54rRSctee6tH/hnaGftkbpFb/myWUVniXN3nxwifRniY8vb0YmEcs", + "rDlDwahs4bOayKRJEtajPVfz0QhtT+qEG+lR+CcAAP//MLFBPesWAAA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/echo/server.go b/internal/test/strict-server/echo/server.go index b0724db19f..669d4da4f4 100644 --- a/internal/test/strict-server/echo/server.go +++ b/internal/test/strict-server/echo/server.go @@ -5,6 +5,7 @@ package api import ( "context" + "encoding/json" "io" "mime/multipart" ) @@ -104,3 +105,16 @@ func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableRes func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) { return ReservedGoKeywordParameters200TextResponse(""), nil } + +func (s StrictServer) UnionExample(ctx context.Context, request UnionExampleRequestObject) (UnionExampleResponseObject, error) { + union, err := json.Marshal(*request.Body) + if err != nil { + return nil, err + } + + return UnionExample200JSONResponse{ + Body: struct{ union json.RawMessage }{ + union: union, + }, + }, nil +} diff --git a/internal/test/strict-server/echo/types.gen.go b/internal/test/strict-server/echo/types.gen.go index 33827cb7a4..023ebed8f6 100644 --- a/internal/test/strict-server/echo/types.gen.go +++ b/internal/test/strict-server/echo/types.gen.go @@ -52,3 +52,6 @@ type URLEncodedExampleFormdataRequestBody = Example // HeadersExampleJSONRequestBody defines body for HeadersExample for application/json ContentType. type HeadersExampleJSONRequestBody = Example + +// UnionExampleJSONRequestBody defines body for UnionExample for application/json ContentType. +type UnionExampleJSONRequestBody = Example diff --git a/internal/test/strict-server/gin/server.gen.go b/internal/test/strict-server/gin/server.gen.go index dcac4155de..1260b51069 100644 --- a/internal/test/strict-server/gin/server.gen.go +++ b/internal/test/strict-server/gin/server.gen.go @@ -54,6 +54,9 @@ type ServerInterface interface { // (POST /with-headers) HeadersExample(c *gin.Context, params HeadersExampleParams) + + // (POST /with-union) + UnionExample(c *gin.Context) } // ServerInterfaceWrapper converts contexts to parameters. @@ -254,6 +257,19 @@ func (siw *ServerInterfaceWrapper) HeadersExample(c *gin.Context) { siw.Handler.HeadersExample(c, params) } +// UnionExample operation middleware +func (siw *ServerInterfaceWrapper) UnionExample(c *gin.Context) { + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.UnionExample(c) +} + // GinServerOptions provides options for the Gin server. type GinServerOptions struct { BaseURL string @@ -291,6 +307,7 @@ func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options router.POST(options.BaseURL+"/unspecified-content-type", wrapper.UnspecifiedContentType) router.POST(options.BaseURL+"/urlencoded", wrapper.URLEncodedExample) router.POST(options.BaseURL+"/with-headers", wrapper.HeadersExample) + router.POST(options.BaseURL+"/with-union", wrapper.UnionExample) } type BadrequestResponse struct { @@ -729,6 +746,51 @@ func (response HeadersExampledefaultResponse) VisitHeadersExampleResponse(w http return nil } +type UnionExampleRequestObject struct { + Body *UnionExampleJSONRequestBody +} + +type UnionExampleResponseObject interface { + VisitUnionExampleResponse(w http.ResponseWriter) error +} + +type UnionExample200ResponseHeaders struct { + Header1 string + Header2 int +} + +type UnionExample200JSONResponse struct { + Body struct { + union json.RawMessage + } + Headers UnionExample200ResponseHeaders +} + +func (response UnionExample200JSONResponse) VisitUnionExampleResponse(w http.ResponseWriter) error { + w.Header().Set("header1", fmt.Sprint(response.Headers.Header1)) + w.Header().Set("header2", fmt.Sprint(response.Headers.Header2)) + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response.Body.union) +} + +type UnionExample400Response = BadrequestResponse + +func (response UnionExample400Response) VisitUnionExampleResponse(w http.ResponseWriter) error { + w.WriteHeader(400) + return nil +} + +type UnionExampledefaultResponse struct { + StatusCode int +} + +func (response UnionExampledefaultResponse) VisitUnionExampleResponse(w http.ResponseWriter) error { + w.WriteHeader(response.StatusCode) + return nil +} + // StrictServerInterface represents all server handlers. type StrictServerInterface interface { @@ -761,6 +823,9 @@ type StrictServerInterface interface { // (POST /with-headers) HeadersExample(ctx context.Context, request HeadersExampleRequestObject) (HeadersExampleResponseObject, error) + + // (POST /with-union) + UnionExample(ctx context.Context, request UnionExampleRequestObject) (UnionExampleResponseObject, error) } type StrictHandlerFunc = runtime.StrictGinHandlerFunc @@ -1127,26 +1192,59 @@ func (sh *strictHandler) HeadersExample(ctx *gin.Context, params HeadersExampleP } } +// UnionExample operation middleware +func (sh *strictHandler) UnionExample(ctx *gin.Context) { + var request UnionExampleRequestObject + + var body UnionExampleJSONRequestBody + if err := ctx.ShouldBind(&body); err != nil { + ctx.Status(http.StatusBadRequest) + ctx.Error(err) + return + } + request.Body = &body + + handler := func(ctx *gin.Context, request interface{}) (interface{}, error) { + return sh.ssi.UnionExample(ctx, request.(UnionExampleRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "UnionExample") + } + + response, err := handler(ctx, request) + + if err != nil { + ctx.Error(err) + ctx.Status(http.StatusInternalServerError) + } else if validResponse, ok := response.(UnionExampleResponseObject); ok { + if err := validResponse.VisitUnionExampleResponse(ctx.Writer); err != nil { + ctx.Error(err) + } + } else if response != nil { + ctx.Error(fmt.Errorf("Unexpected response type: %T", response)) + } +} + // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/+xYX2/bNhD/KgS3p0KynDRPeluDotu6rYOTPg15oMWzzFYiuePJimHouw8UJf+pFS/O", - "7BgY+mbRd787/u4Pj1zxzJTWaNDkeLriCM4a7aD9mAqJ8HcFjvyXBJehsqSM5il/J+Sk+6+JOELlxLSA", - "Xt3LZ0YT6FZVWFuoTHjV5Ivz+ivusjmUwv/6EWHGU/5DsnElCf+6BB5FaQvgTdNE33jw6SOP+ByEBGy9", - "DT+vdrFpaYGn3BEqnXMPEsSuB8WUJsgBvTUv2jnhBXo/0hW3aCwgqcDRQhQVDFvqVsz0C2QUdqD0zOxz", - "eWs0CaUdk2o2AwRNrCOPeQzHXGWtQQLJpkvmLWTEHOACkEecFHnH+N32OuscdjziC0AXDF2NxqOxj5ex", - "oIVVPOVv26WIW0HzdkPrAFkzFPdf7z79wZRjoiJTClKZKIolKwW6uSgKkExpMt7HKiM34q0pbCP/i+zU", - "33dc+rRpM+idkctzZEybmFv5fD0ev1JiNhG/CcaGMNZOJVsV1sLMRFUMkP5Zf9Wm1gwQDXY7S8qqIGUF", - "0nawdtn+vRd5DuVrvGRmsIylIHEm1k9l6aLEd81gsEju5qZ2bG5qRoZJEAWrFc1Zr/hNdSvNBHNK5wWw", - "3qloMJIFdD33Jy0n3V7uPcbZaynaQXmM67qO2+BVWIDOjAT5MlhVihwSq/NddY8tiKd8uiSftvvd9URJ", - "FHGCR0psIZQ+fHS8Ujv5zvTJCjuUK0J7JMo4N/FXWNYGZWwFihII0CUrb73xwDkMlPKfa0mWCc2mwLQo", - "QTIxI0D2wbAO0u2V7KSz+8F8DCIbqPa8XX+kf624p6Q9g3nEvQGeBlZCXSv0QSesIDpA28O/5ud/CkDP", - "Zpj04h1Tw22wb1Fr6hBmzrfEocgN8BcsTbYkLjMwHM64vdn3Nc4gH8mnz/17eHzWkX/C1vfatX0sYVVY", - "fJqzTus5tL2wkz6DxYWSYJLS3hyJfDFSnYVMzRTIuNtFHHx7qiXcGp0h0O4I5O8T2hBbg/lrDs2BBQYi", - "5gyrgZWVI2aFc0xR20UKFa5KEvaax+eNZ7fB0v2mnR6K6pszxfTNpSJ6M746XuXtmfNmZ5R5oh4nv70P", - "MsfeF082Mx058Z3O7oXK2V9S4q0XleES/jkIbM70DNTCT0RaMgSqUINkCyX6R4C92uwANmEdmoWCG5tp", - "qH/dOWYgig5iXfPo0AvQw//4eeKc72bnztMm4uGJKyRLhYWPKJFNkyQ8jY1cLfIccKRMIqzizUPzTwAA", - "AP//O0NNuucUAAA=", + "H4sIAAAAAAAC/+xYS2/jNhD+KwO2p4VkOdmcdOsGi227bVM4yanIgRZHNnclkiVHVgzD/72gKL9ixbW3", + "fqDB3vSYF795cmYs06XRChU5ls6YRWe0cti8DLmw+HeFjvybQJdZaUhqxVL2gYtB+28eMYuV48MCF+ye", + "PtOKUDWs3JhCZtyzJl+c558xl42x5P7pR4s5S9kPycqUJPx1CT7z0hTI5vN59MKCu88sYmPkAm1jbXi8", + "2pRNU4MsZY6sVCPmhQSy604yqQhHaL02T9oa4QkWdqQzZqw2aEkGjCa8qLBbU/tFD79gRuEEUuV6G8tb", + "rYhL5UDIPEeLiqAFD7wMB64yRltCAcMpeA0ZgUM7QcsiRpK8Yex+/Tu0BjsWsQlaFxRd9fq9vveXNqi4", + "kSxl75tPETOcxs2Blg4yusvvv97f/QHSAa9Il5xkxotiCiW3bsyLAgVIRdrbWGXkeqxRZRvP/yJa9o8t", + "lj5smgj6oMX0FBHTBOZaPF/3+2cKzHnEboKyLhlLo5K1DGvE5LwqOkB/VF+VrhWgtdq2J0vKqiBpuKV1", + "Z22i/fuCZB/Il/KSXNsyFpz4iVA/lqaLAt8Wg84kuR/r2sFY10AaBPICakljWDC+yG6pgIOTalQgLIyK", + "Oj1ZYFtzf1Ji0J7lwcs4eS5FG1Ke47qu48Z5lS1QZVqg+DaxsuQjTIwabbJ72ZxYyoZT8mG7XV2PFEQR", + "I3ymxBRcqt2t40zl5DvSR0vskK4Wm5Yo4pGOv+K01lbEhlteIqF1ycxrn3vBI+xI5T+XlJBxBUMExUsU", + "wHNCC580tCLdVsoOWr2f9OdAshLV9NvlS/rXjHlImh7MIuYVsDSgEvJaWu90shVGO2B7+tf4/E8OWKAZ", + "Jr14Q1V3GVyUqCV0FnPnS2KX5zrwC5oGaxSXGRh2R9zW7HuOHuQ9+Xrff8DnvVr+EUvfuXP7UMCq8PF1", + "zFqufWD7xkq6B4oTKVAnpbk5UPLFQHUGM5lLFHF7ijjY9lpJuNUqs0ibI5C/TyhNsBTmrzk0RggIROA0", + "1Ahl5QgMdw4kNVWkkOGqJHCreDyuLLsNmh5W5XSXV9+dyKfvLuXRm/7V4SzvTxw3G6PMK/k4+O1joDn0", + "vni0menAie94ei+Uzv6SEq9tVLpT+OdAsOrpGcqJn4iUAItUWYUCJpIvlgBbudkKWLm1axYKZqymocV2", + "55CBKNop65pFuzZAT294PXHKvdm54rRSctee6tH/hnaGftkbpFb/myWUVniXN3nxwifRniY8vb0YmEcs", + "rDlDwahs4bOayKRJEtajPVfz0QhtT+qEG+lR+CcAAP//MLFBPesWAAA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/gin/server.go b/internal/test/strict-server/gin/server.go index b0724db19f..669d4da4f4 100644 --- a/internal/test/strict-server/gin/server.go +++ b/internal/test/strict-server/gin/server.go @@ -5,6 +5,7 @@ package api import ( "context" + "encoding/json" "io" "mime/multipart" ) @@ -104,3 +105,16 @@ func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableRes func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) { return ReservedGoKeywordParameters200TextResponse(""), nil } + +func (s StrictServer) UnionExample(ctx context.Context, request UnionExampleRequestObject) (UnionExampleResponseObject, error) { + union, err := json.Marshal(*request.Body) + if err != nil { + return nil, err + } + + return UnionExample200JSONResponse{ + Body: struct{ union json.RawMessage }{ + union: union, + }, + }, nil +} diff --git a/internal/test/strict-server/gin/types.gen.go b/internal/test/strict-server/gin/types.gen.go index 33827cb7a4..023ebed8f6 100644 --- a/internal/test/strict-server/gin/types.gen.go +++ b/internal/test/strict-server/gin/types.gen.go @@ -52,3 +52,6 @@ type URLEncodedExampleFormdataRequestBody = Example // HeadersExampleJSONRequestBody defines body for HeadersExample for application/json ContentType. type HeadersExampleJSONRequestBody = Example + +// UnionExampleJSONRequestBody defines body for UnionExample for application/json ContentType. +type UnionExampleJSONRequestBody = Example diff --git a/internal/test/strict-server/strict-schema.yaml b/internal/test/strict-server/strict-schema.yaml index da0ed07a74..253002d498 100644 --- a/internal/test/strict-server/strict-schema.yaml +++ b/internal/test/strict-server/strict-schema.yaml @@ -245,6 +245,35 @@ paths: text/plain: schema: type: string + /with-union: + post: + operationId: UnionExample + description: Union type + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/example" + responses: + 200: + description: OK + headers: + header1: + schema: + type: string + header2: + schema: + type: integer + content: + application/json: + schema: + oneOf: + - type: string + - $ref: "#/components/schemas/example" + 400: + $ref: "#/components/responses/badrequest" + default: + description: Unknown error components: responses: badrequest: diff --git a/internal/test/strict-server/strict_test.go b/internal/test/strict-server/strict_test.go index 860cc4cb8d..eb130eabcb 100644 --- a/internal/test/strict-server/strict_test.go +++ b/internal/test/strict-server/strict_test.go @@ -16,7 +16,7 @@ import ( "github.com/labstack/echo/v4" "github.com/stretchr/testify/assert" - "github.com/deepmap/oapi-codegen/internal/test/strict-server/chi" + api "github.com/deepmap/oapi-codegen/internal/test/strict-server/chi" api3 "github.com/deepmap/oapi-codegen/internal/test/strict-server/client" api4 "github.com/deepmap/oapi-codegen/internal/test/strict-server/echo" api2 "github.com/deepmap/oapi-codegen/internal/test/strict-server/gin" @@ -212,4 +212,15 @@ func testImpl(t *testing.T, handler http.Handler) { assert.NoError(t, err) assert.Equal(t, requestBody, responseBody) }) + t.Run("UnionResponses", func(t *testing.T) { + value := "union" + requestBody := api3.Example{Value: &value} + rr := testutil.NewRequest().Post("/with-union").WithJsonBody(requestBody).GoWithHTTPHandler(t, handler).Recorder + assert.Equal(t, http.StatusOK, rr.Code) + assert.True(t, strings.HasPrefix(rr.Header().Get("Content-Type"), "application/json")) + var responseBody api3.Example + err := json.NewDecoder(rr.Body).Decode(&responseBody) + assert.NoError(t, err) + assert.Equal(t, requestBody, responseBody) + }) } diff --git a/pkg/codegen/templates/strict/strict-interface.tmpl b/pkg/codegen/templates/strict/strict-interface.tmpl index 1911f56e8d..c3ed5aa8c2 100644 --- a/pkg/codegen/templates/strict/strict-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-interface.tmpl @@ -79,7 +79,8 @@ w.WriteHeader({{if $fixedStatusCode}}{{$statusCode}}{{else}}response.StatusCode{{end}}) {{$hasBodyVar := or ($hasHeaders) (not $fixedStatusCode) (not .IsSupported)}} {{if eq .NameTag "JSON" -}} - return json.NewEncoder(w).Encode({{if $hasBodyVar}}response.Body{{else}}response{{end}}) + {{$hasUnionElements := ne 0 (len .Schema.UnionElements)}} + return json.NewEncoder(w).Encode(response{{if $hasBodyVar}}.Body{{end}}{{if $hasUnionElements}}.union{{end}}) {{else if eq .NameTag "Text" -}} _, err := w.Write([]byte({{if $hasBodyVar}}response.Body{{else}}response{{end}})) return err From 259a9182888c55d8f09dab727dec350e4417d2ce Mon Sep 17 00:00:00 2001 From: reinkrul Date: Tue, 14 Mar 2023 16:57:31 +0100 Subject: [PATCH 59/82] Fix incorrect fieldname reserved keywords in path parameters (#999) --- internal/test/strict-server/chi/server.go | 4 ++++ internal/test/strict-server/echo/server.go | 3 +++ internal/test/strict-server/gin/server.go | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/internal/test/strict-server/chi/server.go b/internal/test/strict-server/chi/server.go index 669d4da4f4..26889b0571 100644 --- a/internal/test/strict-server/chi/server.go +++ b/internal/test/strict-server/chi/server.go @@ -118,3 +118,7 @@ func (s StrictServer) UnionExample(ctx context.Context, request UnionExampleRequ }, }, nil } + +func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) { + return ReservedGoKeywordParameters200TextResponse(""), nil +} diff --git a/internal/test/strict-server/echo/server.go b/internal/test/strict-server/echo/server.go index 669d4da4f4..2ee87e9f2f 100644 --- a/internal/test/strict-server/echo/server.go +++ b/internal/test/strict-server/echo/server.go @@ -118,3 +118,6 @@ func (s StrictServer) UnionExample(ctx context.Context, request UnionExampleRequ }, }, nil } +func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) { + return ReservedGoKeywordParameters200TextResponse(""), nil +} diff --git a/internal/test/strict-server/gin/server.go b/internal/test/strict-server/gin/server.go index 669d4da4f4..26889b0571 100644 --- a/internal/test/strict-server/gin/server.go +++ b/internal/test/strict-server/gin/server.go @@ -118,3 +118,7 @@ func (s StrictServer) UnionExample(ctx context.Context, request UnionExampleRequ }, }, nil } + +func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) { + return ReservedGoKeywordParameters200TextResponse(""), nil +} From c03f4a007e04025d1364f77cf9bb0bf46c8f7198 Mon Sep 17 00:00:00 2001 From: marcinromaszewicz Date: Fri, 5 May 2023 15:47:02 -0700 Subject: [PATCH 60/82] Revert "Merge branch 'johanneswuerbach-fix-union'" This reverts commit 74f8084d241826388ca770cdfce13d4e42f182eb, reversing changes made to 8b1c1e2aab0ea91835b3d5418427a64dc3beb1fb. I did not mean to merge this, managing too many branches! --- internal/test/strict-server/chi/server.gen.go | 134 ++-------------- internal/test/strict-server/chi/server.go | 18 --- internal/test/strict-server/chi/types.gen.go | 3 - .../test/strict-server/client/client.gen.go | 146 ------------------ .../test/strict-server/echo/server.gen.go | 124 ++------------- internal/test/strict-server/echo/server.go | 17 -- internal/test/strict-server/echo/types.gen.go | 3 - internal/test/strict-server/gin/server.gen.go | 132 ++-------------- internal/test/strict-server/gin/server.go | 18 --- internal/test/strict-server/gin/types.gen.go | 3 - .../test/strict-server/strict-schema.yaml | 29 ---- internal/test/strict-server/strict_test.go | 13 +- .../templates/strict/strict-interface.tmpl | 3 +- 13 files changed, 53 insertions(+), 590 deletions(-) diff --git a/internal/test/strict-server/chi/server.gen.go b/internal/test/strict-server/chi/server.gen.go index ac1c6da023..b3904b50e6 100644 --- a/internal/test/strict-server/chi/server.gen.go +++ b/internal/test/strict-server/chi/server.gen.go @@ -54,9 +54,6 @@ type ServerInterface interface { // (POST /with-headers) HeadersExample(w http.ResponseWriter, r *http.Request, params HeadersExampleParams) - - // (POST /with-union) - UnionExample(w http.ResponseWriter, r *http.Request) } // ServerInterfaceWrapper converts contexts to parameters. @@ -278,21 +275,6 @@ func (siw *ServerInterfaceWrapper) HeadersExample(w http.ResponseWriter, r *http handler.ServeHTTP(w, r.WithContext(ctx)) } -// UnionExample operation middleware -func (siw *ServerInterfaceWrapper) UnionExample(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - - var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.UnionExample(w, r) - }) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r.WithContext(ctx)) -} - type UnescapedCookieParamError struct { ParamName string Err error @@ -436,9 +418,6 @@ func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handl r.Group(func(r chi.Router) { r.Post(options.BaseURL+"/with-headers", wrapper.HeadersExample) }) - r.Group(func(r chi.Router) { - r.Post(options.BaseURL+"/with-union", wrapper.UnionExample) - }) return r } @@ -879,51 +858,6 @@ func (response HeadersExampledefaultResponse) VisitHeadersExampleResponse(w http return nil } -type UnionExampleRequestObject struct { - Body *UnionExampleJSONRequestBody -} - -type UnionExampleResponseObject interface { - VisitUnionExampleResponse(w http.ResponseWriter) error -} - -type UnionExample200ResponseHeaders struct { - Header1 string - Header2 int -} - -type UnionExample200JSONResponse struct { - Body struct { - union json.RawMessage - } - Headers UnionExample200ResponseHeaders -} - -func (response UnionExample200JSONResponse) VisitUnionExampleResponse(w http.ResponseWriter) error { - w.Header().Set("header1", fmt.Sprint(response.Headers.Header1)) - w.Header().Set("header2", fmt.Sprint(response.Headers.Header2)) - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response.Body.union) -} - -type UnionExample400Response = BadrequestResponse - -func (response UnionExample400Response) VisitUnionExampleResponse(w http.ResponseWriter) error { - w.WriteHeader(400) - return nil -} - -type UnionExampledefaultResponse struct { - StatusCode int -} - -func (response UnionExampledefaultResponse) VisitUnionExampleResponse(w http.ResponseWriter) error { - w.WriteHeader(response.StatusCode) - return nil -} - // StrictServerInterface represents all server handlers. type StrictServerInterface interface { @@ -956,9 +890,6 @@ type StrictServerInterface interface { // (POST /with-headers) HeadersExample(ctx context.Context, request HeadersExampleRequestObject) (HeadersExampleResponseObject, error) - - // (POST /with-union) - UnionExample(ctx context.Context, request UnionExampleRequestObject) (UnionExampleResponseObject, error) } type StrictHandlerFunc = runtime.StrictHttpHandlerFunc @@ -1328,57 +1259,26 @@ func (sh *strictHandler) HeadersExample(w http.ResponseWriter, r *http.Request, } } -// UnionExample operation middleware -func (sh *strictHandler) UnionExample(w http.ResponseWriter, r *http.Request) { - var request UnionExampleRequestObject - - var body UnionExampleJSONRequestBody - if err := json.NewDecoder(r.Body).Decode(&body); err != nil { - sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) - return - } - request.Body = &body - - handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.UnionExample(ctx, request.(UnionExampleRequestObject)) - } - for _, middleware := range sh.middlewares { - handler = middleware(handler, "UnionExample") - } - - response, err := handler(r.Context(), w, r, request) - - if err != nil { - sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(UnionExampleResponseObject); ok { - if err := validResponse.VisitUnionExampleResponse(w); err != nil { - sh.options.ResponseErrorHandlerFunc(w, r, err) - } - } else if response != nil { - sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("Unexpected response type: %T", response)) - } -} - // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", + "AP//O0NNuucUAAA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/chi/server.go b/internal/test/strict-server/chi/server.go index 26889b0571..b0724db19f 100644 --- a/internal/test/strict-server/chi/server.go +++ b/internal/test/strict-server/chi/server.go @@ -5,7 +5,6 @@ package api import ( "context" - "encoding/json" "io" "mime/multipart" ) @@ -105,20 +104,3 @@ func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableRes func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) { return ReservedGoKeywordParameters200TextResponse(""), nil } - -func (s StrictServer) UnionExample(ctx context.Context, request UnionExampleRequestObject) (UnionExampleResponseObject, error) { - union, err := json.Marshal(*request.Body) - if err != nil { - return nil, err - } - - return UnionExample200JSONResponse{ - Body: struct{ union json.RawMessage }{ - union: union, - }, - }, nil -} - -func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) { - return ReservedGoKeywordParameters200TextResponse(""), nil -} diff --git a/internal/test/strict-server/chi/types.gen.go b/internal/test/strict-server/chi/types.gen.go index 023ebed8f6..33827cb7a4 100644 --- a/internal/test/strict-server/chi/types.gen.go +++ b/internal/test/strict-server/chi/types.gen.go @@ -52,6 +52,3 @@ type URLEncodedExampleFormdataRequestBody = Example // HeadersExampleJSONRequestBody defines body for HeadersExample for application/json ContentType. type HeadersExampleJSONRequestBody = Example - -// UnionExampleJSONRequestBody defines body for UnionExample for application/json ContentType. -type UnionExampleJSONRequestBody = Example diff --git a/internal/test/strict-server/client/client.gen.go b/internal/test/strict-server/client/client.gen.go index d68c6c1e36..5ec0210b50 100644 --- a/internal/test/strict-server/client/client.gen.go +++ b/internal/test/strict-server/client/client.gen.go @@ -66,9 +66,6 @@ type URLEncodedExampleFormdataRequestBody = Example // HeadersExampleJSONRequestBody defines body for HeadersExample for application/json ContentType. type HeadersExampleJSONRequestBody = Example -// UnionExampleJSONRequestBody defines body for UnionExample for application/json ContentType. -type UnionExampleJSONRequestBody = Example - // RequestEditorFn is the function signature for the RequestEditor callback function type RequestEditorFn func(ctx context.Context, req *http.Request) error @@ -187,11 +184,6 @@ type ClientInterface interface { HeadersExampleWithBody(ctx context.Context, params *HeadersExampleParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) HeadersExample(ctx context.Context, params *HeadersExampleParams, body HeadersExampleJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) - - // UnionExample request with any body - UnionExampleWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - - UnionExample(ctx context.Context, body UnionExampleJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) } func (c *Client) JSONExampleWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { @@ -410,30 +402,6 @@ func (c *Client) HeadersExample(ctx context.Context, params *HeadersExampleParam return c.Client.Do(req) } -func (c *Client) UnionExampleWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewUnionExampleRequestWithBody(c.Server, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) UnionExample(ctx context.Context, body UnionExampleJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewUnionExampleRequest(c.Server, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - // NewJSONExampleRequest calls the generic JSONExample builder with application/json body func NewJSONExampleRequest(server string, body JSONExampleJSONRequestBody) (*http.Request, error) { var bodyReader io.Reader @@ -829,46 +797,6 @@ func NewHeadersExampleRequestWithBody(server string, params *HeadersExampleParam return req, nil } -// NewUnionExampleRequest calls the generic UnionExample builder with application/json body -func NewUnionExampleRequest(server string, body UnionExampleJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewUnionExampleRequestWithBody(server, "application/json", bodyReader) -} - -// NewUnionExampleRequestWithBody generates requests for UnionExample with any type of body -func NewUnionExampleRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/with-union") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("POST", queryURL.String(), body) - if err != nil { - return nil, err - } - - req.Header.Add("Content-Type", contentType) - - return req, nil -} - func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error { for _, r := range c.RequestEditors { if err := r(ctx, req); err != nil { @@ -957,11 +885,6 @@ type ClientWithResponsesInterface interface { HeadersExampleWithBodyWithResponse(ctx context.Context, params *HeadersExampleParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*HeadersExampleResponse, error) HeadersExampleWithResponse(ctx context.Context, params *HeadersExampleParams, body HeadersExampleJSONRequestBody, reqEditors ...RequestEditorFn) (*HeadersExampleResponse, error) - - // UnionExample request with any body - UnionExampleWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UnionExampleResponse, error) - - UnionExampleWithResponse(ctx context.Context, body UnionExampleJSONRequestBody, reqEditors ...RequestEditorFn) (*UnionExampleResponse, error) } type JSONExampleResponse struct { @@ -1178,30 +1101,6 @@ func (r HeadersExampleResponse) StatusCode() int { return 0 } -type UnionExampleResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *struct { - union json.RawMessage - } -} - -// Status returns HTTPResponse.Status -func (r UnionExampleResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r UnionExampleResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - // JSONExampleWithBodyWithResponse request with arbitrary body returning *JSONExampleResponse func (c *ClientWithResponses) JSONExampleWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*JSONExampleResponse, error) { rsp, err := c.JSONExampleWithBody(ctx, contentType, body, reqEditors...) @@ -1356,23 +1255,6 @@ func (c *ClientWithResponses) HeadersExampleWithResponse(ctx context.Context, pa return ParseHeadersExampleResponse(rsp) } -// UnionExampleWithBodyWithResponse request with arbitrary body returning *UnionExampleResponse -func (c *ClientWithResponses) UnionExampleWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UnionExampleResponse, error) { - rsp, err := c.UnionExampleWithBody(ctx, contentType, body, reqEditors...) - if err != nil { - return nil, err - } - return ParseUnionExampleResponse(rsp) -} - -func (c *ClientWithResponses) UnionExampleWithResponse(ctx context.Context, body UnionExampleJSONRequestBody, reqEditors ...RequestEditorFn) (*UnionExampleResponse, error) { - rsp, err := c.UnionExample(ctx, body, reqEditors...) - if err != nil { - return nil, err - } - return ParseUnionExampleResponse(rsp) -} - // ParseJSONExampleResponse parses an HTTP response from a JSONExampleWithResponse call func ParseJSONExampleResponse(rsp *http.Response) (*JSONExampleResponse, error) { bodyBytes, err := io.ReadAll(rsp.Body) @@ -1575,31 +1457,3 @@ func ParseHeadersExampleResponse(rsp *http.Response) (*HeadersExampleResponse, e return response, nil } - -// ParseUnionExampleResponse parses an HTTP response from a UnionExampleWithResponse call -func ParseUnionExampleResponse(rsp *http.Response) (*UnionExampleResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &UnionExampleResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest struct { - union json.RawMessage - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - } - - return response, nil -} diff --git a/internal/test/strict-server/echo/server.gen.go b/internal/test/strict-server/echo/server.gen.go index 4d8936781d..0912230952 100644 --- a/internal/test/strict-server/echo/server.gen.go +++ b/internal/test/strict-server/echo/server.gen.go @@ -54,9 +54,6 @@ type ServerInterface interface { // (POST /with-headers) HeadersExample(ctx echo.Context, params HeadersExampleParams) error - - // (POST /with-union) - UnionExample(ctx echo.Context) error } // ServerInterfaceWrapper converts echo contexts to parameters. @@ -198,15 +195,6 @@ func (w *ServerInterfaceWrapper) HeadersExample(ctx echo.Context) error { return err } -// UnionExample converts echo context to params. -func (w *ServerInterfaceWrapper) UnionExample(ctx echo.Context) error { - var err error - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.UnionExample(ctx) - return err -} - // This is a simple interface which specifies echo.Route addition functions which // are present on both echo.Echo and echo.Group, since we want to allow using // either of them for path registration @@ -245,7 +233,6 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL router.POST(baseURL+"/unspecified-content-type", wrapper.UnspecifiedContentType) router.POST(baseURL+"/urlencoded", wrapper.URLEncodedExample) router.POST(baseURL+"/with-headers", wrapper.HeadersExample) - router.POST(baseURL+"/with-union", wrapper.UnionExample) } @@ -685,51 +672,6 @@ func (response HeadersExampledefaultResponse) VisitHeadersExampleResponse(w http return nil } -type UnionExampleRequestObject struct { - Body *UnionExampleJSONRequestBody -} - -type UnionExampleResponseObject interface { - VisitUnionExampleResponse(w http.ResponseWriter) error -} - -type UnionExample200ResponseHeaders struct { - Header1 string - Header2 int -} - -type UnionExample200JSONResponse struct { - Body struct { - union json.RawMessage - } - Headers UnionExample200ResponseHeaders -} - -func (response UnionExample200JSONResponse) VisitUnionExampleResponse(w http.ResponseWriter) error { - w.Header().Set("header1", fmt.Sprint(response.Headers.Header1)) - w.Header().Set("header2", fmt.Sprint(response.Headers.Header2)) - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response.Body.union) -} - -type UnionExample400Response = BadrequestResponse - -func (response UnionExample400Response) VisitUnionExampleResponse(w http.ResponseWriter) error { - w.WriteHeader(400) - return nil -} - -type UnionExampledefaultResponse struct { - StatusCode int -} - -func (response UnionExampledefaultResponse) VisitUnionExampleResponse(w http.ResponseWriter) error { - w.WriteHeader(response.StatusCode) - return nil -} - // StrictServerInterface represents all server handlers. type StrictServerInterface interface { @@ -762,9 +704,6 @@ type StrictServerInterface interface { // (POST /with-headers) HeadersExample(ctx context.Context, request HeadersExampleRequestObject) (HeadersExampleResponseObject, error) - - // (POST /with-union) - UnionExample(ctx context.Context, request UnionExampleRequestObject) (UnionExampleResponseObject, error) } type StrictHandlerFunc = runtime.StrictEchoHandlerFunc @@ -1097,55 +1036,26 @@ func (sh *strictHandler) HeadersExample(ctx echo.Context, params HeadersExampleP return nil } -// UnionExample operation middleware -func (sh *strictHandler) UnionExample(ctx echo.Context) error { - var request UnionExampleRequestObject - - var body UnionExampleJSONRequestBody - if err := ctx.Bind(&body); err != nil { - return err - } - request.Body = &body - - handler := func(ctx echo.Context, request interface{}) (interface{}, error) { - return sh.ssi.UnionExample(ctx.Request().Context(), request.(UnionExampleRequestObject)) - } - for _, middleware := range sh.middlewares { - handler = middleware(handler, "UnionExample") - } - - response, err := handler(ctx, request) - - if err != nil { - return err - } else if validResponse, ok := response.(UnionExampleResponseObject); ok { - return validResponse.VisitUnionExampleResponse(ctx.Response()) - } else if response != nil { - return fmt.Errorf("Unexpected response type: %T", response) - } - return nil -} - // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", + "AP//O0NNuucUAAA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/echo/server.go b/internal/test/strict-server/echo/server.go index 2ee87e9f2f..b0724db19f 100644 --- a/internal/test/strict-server/echo/server.go +++ b/internal/test/strict-server/echo/server.go @@ -5,7 +5,6 @@ package api import ( "context" - "encoding/json" "io" "mime/multipart" ) @@ -105,19 +104,3 @@ func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableRes func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) { return ReservedGoKeywordParameters200TextResponse(""), nil } - -func (s StrictServer) UnionExample(ctx context.Context, request UnionExampleRequestObject) (UnionExampleResponseObject, error) { - union, err := json.Marshal(*request.Body) - if err != nil { - return nil, err - } - - return UnionExample200JSONResponse{ - Body: struct{ union json.RawMessage }{ - union: union, - }, - }, nil -} -func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) { - return ReservedGoKeywordParameters200TextResponse(""), nil -} diff --git a/internal/test/strict-server/echo/types.gen.go b/internal/test/strict-server/echo/types.gen.go index 023ebed8f6..33827cb7a4 100644 --- a/internal/test/strict-server/echo/types.gen.go +++ b/internal/test/strict-server/echo/types.gen.go @@ -52,6 +52,3 @@ type URLEncodedExampleFormdataRequestBody = Example // HeadersExampleJSONRequestBody defines body for HeadersExample for application/json ContentType. type HeadersExampleJSONRequestBody = Example - -// UnionExampleJSONRequestBody defines body for UnionExample for application/json ContentType. -type UnionExampleJSONRequestBody = Example diff --git a/internal/test/strict-server/gin/server.gen.go b/internal/test/strict-server/gin/server.gen.go index 1260b51069..dcac4155de 100644 --- a/internal/test/strict-server/gin/server.gen.go +++ b/internal/test/strict-server/gin/server.gen.go @@ -54,9 +54,6 @@ type ServerInterface interface { // (POST /with-headers) HeadersExample(c *gin.Context, params HeadersExampleParams) - - // (POST /with-union) - UnionExample(c *gin.Context) } // ServerInterfaceWrapper converts contexts to parameters. @@ -257,19 +254,6 @@ func (siw *ServerInterfaceWrapper) HeadersExample(c *gin.Context) { siw.Handler.HeadersExample(c, params) } -// UnionExample operation middleware -func (siw *ServerInterfaceWrapper) UnionExample(c *gin.Context) { - - for _, middleware := range siw.HandlerMiddlewares { - middleware(c) - if c.IsAborted() { - return - } - } - - siw.Handler.UnionExample(c) -} - // GinServerOptions provides options for the Gin server. type GinServerOptions struct { BaseURL string @@ -307,7 +291,6 @@ func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options router.POST(options.BaseURL+"/unspecified-content-type", wrapper.UnspecifiedContentType) router.POST(options.BaseURL+"/urlencoded", wrapper.URLEncodedExample) router.POST(options.BaseURL+"/with-headers", wrapper.HeadersExample) - router.POST(options.BaseURL+"/with-union", wrapper.UnionExample) } type BadrequestResponse struct { @@ -746,51 +729,6 @@ func (response HeadersExampledefaultResponse) VisitHeadersExampleResponse(w http return nil } -type UnionExampleRequestObject struct { - Body *UnionExampleJSONRequestBody -} - -type UnionExampleResponseObject interface { - VisitUnionExampleResponse(w http.ResponseWriter) error -} - -type UnionExample200ResponseHeaders struct { - Header1 string - Header2 int -} - -type UnionExample200JSONResponse struct { - Body struct { - union json.RawMessage - } - Headers UnionExample200ResponseHeaders -} - -func (response UnionExample200JSONResponse) VisitUnionExampleResponse(w http.ResponseWriter) error { - w.Header().Set("header1", fmt.Sprint(response.Headers.Header1)) - w.Header().Set("header2", fmt.Sprint(response.Headers.Header2)) - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response.Body.union) -} - -type UnionExample400Response = BadrequestResponse - -func (response UnionExample400Response) VisitUnionExampleResponse(w http.ResponseWriter) error { - w.WriteHeader(400) - return nil -} - -type UnionExampledefaultResponse struct { - StatusCode int -} - -func (response UnionExampledefaultResponse) VisitUnionExampleResponse(w http.ResponseWriter) error { - w.WriteHeader(response.StatusCode) - return nil -} - // StrictServerInterface represents all server handlers. type StrictServerInterface interface { @@ -823,9 +761,6 @@ type StrictServerInterface interface { // (POST /with-headers) HeadersExample(ctx context.Context, request HeadersExampleRequestObject) (HeadersExampleResponseObject, error) - - // (POST /with-union) - UnionExample(ctx context.Context, request UnionExampleRequestObject) (UnionExampleResponseObject, error) } type StrictHandlerFunc = runtime.StrictGinHandlerFunc @@ -1192,59 +1127,26 @@ func (sh *strictHandler) HeadersExample(ctx *gin.Context, params HeadersExampleP } } -// UnionExample operation middleware -func (sh *strictHandler) UnionExample(ctx *gin.Context) { - var request UnionExampleRequestObject - - var body UnionExampleJSONRequestBody - if err := ctx.ShouldBind(&body); err != nil { - ctx.Status(http.StatusBadRequest) - ctx.Error(err) - return - } - request.Body = &body - - handler := func(ctx *gin.Context, request interface{}) (interface{}, error) { - return sh.ssi.UnionExample(ctx, request.(UnionExampleRequestObject)) - } - for _, middleware := range sh.middlewares { - handler = middleware(handler, "UnionExample") - } - - response, err := handler(ctx, request) - - if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) - } else if validResponse, ok := response.(UnionExampleResponseObject); ok { - if err := validResponse.VisitUnionExampleResponse(ctx.Writer); err != nil { - ctx.Error(err) - } - } else if response != nil { - ctx.Error(fmt.Errorf("Unexpected response type: %T", response)) - } -} - // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", + "AP//O0NNuucUAAA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/gin/server.go b/internal/test/strict-server/gin/server.go index 26889b0571..b0724db19f 100644 --- a/internal/test/strict-server/gin/server.go +++ b/internal/test/strict-server/gin/server.go @@ -5,7 +5,6 @@ package api import ( "context" - "encoding/json" "io" "mime/multipart" ) @@ -105,20 +104,3 @@ func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableRes func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) { return ReservedGoKeywordParameters200TextResponse(""), nil } - -func (s StrictServer) UnionExample(ctx context.Context, request UnionExampleRequestObject) (UnionExampleResponseObject, error) { - union, err := json.Marshal(*request.Body) - if err != nil { - return nil, err - } - - return UnionExample200JSONResponse{ - Body: struct{ union json.RawMessage }{ - union: union, - }, - }, nil -} - -func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) { - return ReservedGoKeywordParameters200TextResponse(""), nil -} diff --git a/internal/test/strict-server/gin/types.gen.go b/internal/test/strict-server/gin/types.gen.go index 023ebed8f6..33827cb7a4 100644 --- a/internal/test/strict-server/gin/types.gen.go +++ b/internal/test/strict-server/gin/types.gen.go @@ -52,6 +52,3 @@ type URLEncodedExampleFormdataRequestBody = Example // HeadersExampleJSONRequestBody defines body for HeadersExample for application/json ContentType. type HeadersExampleJSONRequestBody = Example - -// UnionExampleJSONRequestBody defines body for UnionExample for application/json ContentType. -type UnionExampleJSONRequestBody = Example diff --git a/internal/test/strict-server/strict-schema.yaml b/internal/test/strict-server/strict-schema.yaml index 253002d498..da0ed07a74 100644 --- a/internal/test/strict-server/strict-schema.yaml +++ b/internal/test/strict-server/strict-schema.yaml @@ -245,35 +245,6 @@ paths: text/plain: schema: type: string - /with-union: - post: - operationId: UnionExample - description: Union type - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/example" - responses: - 200: - description: OK - headers: - header1: - schema: - type: string - header2: - schema: - type: integer - content: - application/json: - schema: - oneOf: - - type: string - - $ref: "#/components/schemas/example" - 400: - $ref: "#/components/responses/badrequest" - default: - description: Unknown error components: responses: badrequest: diff --git a/internal/test/strict-server/strict_test.go b/internal/test/strict-server/strict_test.go index eb130eabcb..860cc4cb8d 100644 --- a/internal/test/strict-server/strict_test.go +++ b/internal/test/strict-server/strict_test.go @@ -16,7 +16,7 @@ import ( "github.com/labstack/echo/v4" "github.com/stretchr/testify/assert" - api "github.com/deepmap/oapi-codegen/internal/test/strict-server/chi" + "github.com/deepmap/oapi-codegen/internal/test/strict-server/chi" api3 "github.com/deepmap/oapi-codegen/internal/test/strict-server/client" api4 "github.com/deepmap/oapi-codegen/internal/test/strict-server/echo" api2 "github.com/deepmap/oapi-codegen/internal/test/strict-server/gin" @@ -212,15 +212,4 @@ func testImpl(t *testing.T, handler http.Handler) { assert.NoError(t, err) assert.Equal(t, requestBody, responseBody) }) - t.Run("UnionResponses", func(t *testing.T) { - value := "union" - requestBody := api3.Example{Value: &value} - rr := testutil.NewRequest().Post("/with-union").WithJsonBody(requestBody).GoWithHTTPHandler(t, handler).Recorder - assert.Equal(t, http.StatusOK, rr.Code) - assert.True(t, strings.HasPrefix(rr.Header().Get("Content-Type"), "application/json")) - var responseBody api3.Example - err := json.NewDecoder(rr.Body).Decode(&responseBody) - assert.NoError(t, err) - assert.Equal(t, requestBody, responseBody) - }) } diff --git a/pkg/codegen/templates/strict/strict-interface.tmpl b/pkg/codegen/templates/strict/strict-interface.tmpl index c3ed5aa8c2..1911f56e8d 100644 --- a/pkg/codegen/templates/strict/strict-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-interface.tmpl @@ -79,8 +79,7 @@ w.WriteHeader({{if $fixedStatusCode}}{{$statusCode}}{{else}}response.StatusCode{{end}}) {{$hasBodyVar := or ($hasHeaders) (not $fixedStatusCode) (not .IsSupported)}} {{if eq .NameTag "JSON" -}} - {{$hasUnionElements := ne 0 (len .Schema.UnionElements)}} - return json.NewEncoder(w).Encode(response{{if $hasBodyVar}}.Body{{end}}{{if $hasUnionElements}}.union{{end}}) + return json.NewEncoder(w).Encode({{if $hasBodyVar}}response.Body{{else}}response{{end}}) {{else if eq .NameTag "Text" -}} _, err := w.Write([]byte({{if $hasBodyVar}}response.Body{{else}}response{{end}})) return err From 71bd0507ae18c83ae7bc150d63700e56b5f97339 Mon Sep 17 00:00:00 2001 From: Mikhail Yohman Date: Fri, 5 May 2023 18:15:09 -0600 Subject: [PATCH 61/82] Updated code to find AdditionalTypes under AdditionalPropertiesType key as well. (#1017) --- pkg/codegen/codegen_test.go | 46 ++ pkg/codegen/schema.go | 5 + ...st_schema_additional_properties_types.yaml | 513 ++++++++++++++++++ 3 files changed, 564 insertions(+) create mode 100644 pkg/codegen/test_schema_additional_properties_types.yaml diff --git a/pkg/codegen/codegen_test.go b/pkg/codegen/codegen_test.go index 6ae61211a9..499174be03 100644 --- a/pkg/codegen/codegen_test.go +++ b/pkg/codegen/codegen_test.go @@ -201,6 +201,49 @@ type GetTestByNameResponse struct { checkLint(t, "test.gen.go", []byte(code)) } +// Validate any types nested under AdditionalPropertiesTypes is propagated up as with normal Property AdditionalTypes +func TestExampleOpenAPICodeGenerationSchemaAdditionalPropertyTypes(t *testing.T) { + + // Input vars for code generation: + packageName := "testswagger" + opts := Configuration{ + PackageName: packageName, + Generate: GenerateOptions{ + EchoServer: false, + Client: false, + Models: true, + EmbeddedSpec: false, + }, + } + + loader := openapi3.NewLoader() + loader.IsExternalRefsAllowed = true + + // Get a spec from the test definition in this file: + swagger, err := loader.LoadFromData([]byte(testSchemaArrayTypes)) + assert.NoError(t, err) + + // Run our code generation: + code, err := Generate(swagger, opts) + assert.NoError(t, err) + assert.NotEmpty(t, code) + + // Check that we have valid (formattable) code: + _, err = format.Source([]byte(code)) + assert.NoError(t, err) + + // Check that we have a package: + assert.Contains(t, code, "package testswagger") + + // Check that AdditionalPropertyTypes structs are propagated up properly: + assert.Contains(t, code, "[]PatchedBulkWritableCircuitTerminationRequest_Relationships_Destination_Objects_Item") + assert.Contains(t, code, "type PatchedBulkWritableCircuitTerminationRequest_Relationships_Destination_Objects_Item struct {") + assert.Contains(t, code, "[]BulkWritableCircuitTerminationRequest_Relationships_Destination_Objects_Item") + assert.Contains(t, code, "type BulkWritableCircuitTerminationRequest_Relationships_Destination_Objects_Item struct {") + assert.Contains(t, code, "[]WritableCircuitTerminationRequest_Relationships_Destination_Objects_Item ") + assert.Contains(t, code, "type WritableCircuitTerminationRequest_Relationships_Destination_Objects_Item struct {") +} + func TestGoTypeImport(t *testing.T) { packageName := "api" opts := Configuration{ @@ -309,5 +352,8 @@ func (t *ExampleSchema_Item) FromExternalRef0NewPet(v externalRef0.NewPet) error } +//go:embed test_schema_additional_properties_types.yaml +var testSchemaArrayTypes string + //go:embed test_spec.yaml var testOpenAPIDefinition string diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index e9fccbff99..92f72b4c8c 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -71,6 +71,11 @@ func (s Schema) GetAdditionalTypeDefs() []TypeDefinition { for _, p := range s.Properties { result = append(result, p.Schema.GetAdditionalTypeDefs()...) } + // Some schema definitions may be used for key/value and not specify any properties, but provide properties + // within the additionalProperties. See test_schema_array_types.yaml in tests. + if s.AdditionalPropertiesType != nil { + result = append(result, s.AdditionalPropertiesType.GetAdditionalTypeDefs()...) + } result = append(result, s.AdditionalTypes...) return result } diff --git a/pkg/codegen/test_schema_additional_properties_types.yaml b/pkg/codegen/test_schema_additional_properties_types.yaml new file mode 100644 index 0000000000..0cbf800d05 --- /dev/null +++ b/pkg/codegen/test_schema_additional_properties_types.yaml @@ -0,0 +1,513 @@ +openapi: 3.0.3 +info: + title: API Documentation + version: 1.5.7 (1.3) + description: Source of truth and network automation platform + license: + name: Apache v2 License +paths: + /circuits/circuit-terminations/: + post: + operationId: circuits_circuit_terminations_create + description: |- + Base class to use for API ViewSets based on OrganizationalModel or PrimaryModel. + + Can also be used for models derived from BaseModel, so long as they support Notes. + tags: + - circuits + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/WritableCircuitTerminationRequest" + required: true + security: + - cookieAuth: [] + - tokenAuth: [] + responses: + "201": + content: + application/json; version=1.3: + schema: + $ref: "#/components/schemas/CircuitTermination" + description: "" + put: + operationId: circuits_circuit_terminations_bulk_update + description: |- + Base class to use for API ViewSets based on OrganizationalModel or PrimaryModel. + + Can also be used for models derived from BaseModel, so long as they support Notes. + tags: + - circuits + requestBody: + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/BulkWritableCircuitTerminationRequest" + required: true + security: + - cookieAuth: [] + - tokenAuth: [] + responses: + "200": + content: + application/json; version=1.3: + schema: + type: array + items: + $ref: "#/components/schemas/CircuitTermination" + description: "" + patch: + operationId: circuits_circuit_terminations_bulk_partial_update + description: |- + Base class to use for API ViewSets based on OrganizationalModel or PrimaryModel. + + Can also be used for models derived from BaseModel, so long as they support Notes. + tags: + - circuits + requestBody: + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/PatchedBulkWritableCircuitTerminationRequest" + required: true + security: + - cookieAuth: [] + - tokenAuth: [] + responses: + "200": + content: + application/json; version=1.3: + schema: + type: array + items: + $ref: "#/components/schemas/CircuitTermination" + description: "" +components: + schemas: + CircuitTermination: + type: object + description: |- + Base class to use for serializers based on OrganizationalModel or PrimaryModel. + + Can also be used for models derived from BaseModel, so long as they support custom fields and relationships. + properties: + id: + type: string + format: uuid + readOnly: true + display: + type: string + readOnly: true + description: Human friendly display value + url: + type: string + format: uri + readOnly: true + description: + type: string + maxLength: 200 + required: + - display + - id + - url + WritableCircuitTerminationRequest: + type: object + description: |- + Base class to use for serializers based on OrganizationalModel or PrimaryModel. + + Can also be used for models derived from BaseModel, so long as they support custom fields and relationships. + properties: + circuit: + type: string + format: uuid + site: + type: string + format: uuid + nullable: true + location: + type: string + format: uuid + nullable: true + provider_network: + type: string + format: uuid + nullable: true + description: + type: string + maxLength: 200 + custom_fields: + type: object + additionalProperties: {} + relationships: + type: object + additionalProperties: + type: object + required: + - id + - url + - name + - type + properties: + id: + type: string + format: uuid + readOnly: true + url: + type: string + format: uri + readOnly: true + name: + type: string + readOnly: true + type: + type: string + readOnly: true + example: one-to-many + source: + type: object + properties: + label: + type: string + readOnly: true + object_type: + type: string + readOnly: true + example: dcim.site + objects: + type: array + items: + type: object + properties: + id: + type: string + format: uuid + url: + type: string + format: uri + readOnly: true + display: + type: string + readOnly: true + additionalProperties: true + destination: + type: object + properties: + label: + type: string + readOnly: true + object_type: + type: string + readOnly: true + example: dcim.site + objects: + type: array + items: + type: object + properties: + id: + type: string + format: uuid + url: + type: string + format: uri + readOnly: true + display: + type: string + readOnly: true + additionalProperties: true + peer: + type: object + properties: + label: + type: string + readOnly: true + object_type: + type: string + readOnly: true + example: dcim.site + objects: + type: array + items: + type: object + properties: + id: + type: string + format: uuid + url: + type: string + format: uri + readOnly: true + display: + type: string + readOnly: true + additionalProperties: true + required: + - circuit + BulkWritableCircuitTerminationRequest: + type: object + description: |- + Base class to use for serializers based on OrganizationalModel or PrimaryModel. + + Can also be used for models derived from BaseModel, so long as they support custom fields and relationships. + properties: + id: + type: string + format: uuid + description: + type: string + maxLength: 200 + custom_fields: + type: object + additionalProperties: true + relationships: + type: object + additionalProperties: + type: object + required: + - id + - url + - name + - type + properties: + id: + type: string + format: uuid + readOnly: true + url: + type: string + format: uri + readOnly: true + name: + type: string + readOnly: true + type: + type: string + readOnly: true + example: one-to-many + source: + type: object + properties: + label: + type: string + readOnly: true + object_type: + type: string + readOnly: true + example: dcim.site + objects: + type: array + items: + type: object + properties: + id: + type: string + format: uuid + url: + type: string + format: uri + readOnly: true + display: + type: string + readOnly: true + additionalProperties: true + destination: + type: object + properties: + label: + type: string + readOnly: true + object_type: + type: string + readOnly: true + example: dcim.site + objects: + type: array + items: + type: object + properties: + id: + type: string + format: uuid + url: + type: string + format: uri + readOnly: true + display: + type: string + readOnly: true + additionalProperties: true + peer: + type: object + properties: + label: + type: string + readOnly: true + object_type: + type: string + readOnly: true + example: dcim.site + objects: + type: array + items: + type: object + properties: + id: + type: string + format: uuid + url: + type: string + format: uri + readOnly: true + display: + type: string + readOnly: true + additionalProperties: true + required: + - id + PatchedBulkWritableCircuitTerminationRequest: + type: object + description: |- + Base class to use for serializers based on OrganizationalModel or PrimaryModel. + + Can also be used for models derived from BaseModel, so long as they support custom fields and relationships. + properties: + id: + type: string + format: uuid + port_speed: + type: integer + maximum: 2147483647 + minimum: 0 + nullable: true + title: Port speed (Kbps) + upstream_speed: + type: integer + maximum: 2147483647 + minimum: 0 + nullable: true + title: Upstream speed (Kbps) + description: Upstream speed, if different from port speed + xconnect_id: + type: string + title: Cross-connect ID + maxLength: 50 + pp_info: + type: string + title: Patch panel/port(s) + maxLength: 100 + description: + type: string + maxLength: 200 + custom_fields: + type: object + additionalProperties: {} + relationships: + type: object + additionalProperties: + type: object + required: + - id + - url + - name + - type + properties: + id: + type: string + format: uuid + readOnly: true + url: + type: string + format: uri + readOnly: true + name: + type: string + readOnly: true + type: + type: string + readOnly: true + example: one-to-many + source: + type: object + properties: + label: + type: string + readOnly: true + object_type: + type: string + readOnly: true + example: dcim.site + objects: + type: array + items: + type: object + properties: + id: + type: string + format: uuid + url: + type: string + format: uri + readOnly: true + display: + type: string + readOnly: true + additionalProperties: true + destination: + type: object + properties: + label: + type: string + readOnly: true + object_type: + type: string + readOnly: true + example: dcim.site + objects: + type: array + items: + type: object + properties: + id: + type: string + format: uuid + url: + type: string + format: uri + readOnly: true + display: + type: string + readOnly: true + additionalProperties: true + peer: + type: object + properties: + label: + type: string + readOnly: true + object_type: + type: string + readOnly: true + example: dcim.site + objects: + type: array + items: + type: object + properties: + id: + type: string + format: uuid + url: + type: string + format: uri + readOnly: true + display: + type: string + readOnly: true + additionalProperties: true + required: + - id From 6a37afe72e32658db92187a0c0d0c2bdd1f95f08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Rodrigues?= Date: Sat, 6 May 2023 02:24:33 +0200 Subject: [PATCH 62/82] Assign values of type Map in deep objects (#934) * Assign values of type Map in deep objects * Ensure map value type conversion --------- Co-authored-by: Luis Rodrigues --- pkg/runtime/deepobject.go | 13 +++++++++++++ pkg/runtime/deepobject_test.go | 31 +++++++++++++++++++------------ 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/pkg/runtime/deepobject.go b/pkg/runtime/deepobject.go index 87e9dd9a24..35286b303c 100644 --- a/pkg/runtime/deepobject.go +++ b/pkg/runtime/deepobject.go @@ -200,6 +200,19 @@ func assignPathValues(dst interface{}, pathValues fieldOrValue) error { it := iv.Type() switch it.Kind() { + case reflect.Map: + dstMap := reflect.MakeMap(iv.Type()) + for key, value := range pathValues.fields { + dstKey := reflect.ValueOf(key) + dstVal := reflect.New(iv.Type().Elem()) + err := assignPathValues(dstVal.Interface(), value) + if err != nil { + return fmt.Errorf("error binding map: %w", err) + } + dstMap.SetMapIndex(dstKey, dstVal.Elem()) + } + iv.Set(dstMap) + return nil case reflect.Slice: sliceLength := len(pathValues.fields) dstSlice := reflect.MakeSlice(it, sliceLength, sliceLength) diff --git a/pkg/runtime/deepobject_test.go b/pkg/runtime/deepobject_test.go index d1a5a16377..237673ad31 100644 --- a/pkg/runtime/deepobject_test.go +++ b/pkg/runtime/deepobject_test.go @@ -17,18 +17,20 @@ type InnerObject struct { // These are all possible field types, mandatory and optional. type AllFields struct { - I int `json:"i"` - Oi *int `json:"oi,omitempty"` - F float32 `json:"f"` - Of *float32 `json:"of,omitempty"` - B bool `json:"b"` - Ob *bool `json:"ob,omitempty"` - As []string `json:"as"` - Oas *[]string `json:"oas,omitempty"` - O InnerObject `json:"o"` - Oo *InnerObject `json:"oo,omitempty"` - D MockBinder `json:"d"` - Od *MockBinder `json:"od,omitempty"` + I int `json:"i"` + Oi *int `json:"oi,omitempty"` + F float32 `json:"f"` + Of *float32 `json:"of,omitempty"` + B bool `json:"b"` + Ob *bool `json:"ob,omitempty"` + As []string `json:"as"` + Oas *[]string `json:"oas,omitempty"` + O InnerObject `json:"o"` + Oo *InnerObject `json:"oo,omitempty"` + D MockBinder `json:"d"` + Od *MockBinder `json:"od,omitempty"` + M map[string]int `json:"m"` + Om *map[string]int `json:"om,omitempty"` } func TestDeepObject(t *testing.T) { @@ -40,6 +42,9 @@ func TestDeepObject(t *testing.T) { Name: "Marcin Romaszewicz", ID: 123, } + om := map[string]int{ + "additional": 1, + } d := MockBinder{Time: time.Date(2020, 2, 1, 0, 0, 0, 0, time.UTC)} srcObj := AllFields{ @@ -58,6 +63,8 @@ func TestDeepObject(t *testing.T) { Oo: &oo, D: d, Od: &d, + M: om, + Om: &om, } marshaled, err := MarshalDeepObject(srcObj, "p") From 47bc5ecf38f6e147b49c09ded00d7451dff48ccc Mon Sep 17 00:00:00 2001 From: marcinromaszewicz Date: Fri, 5 May 2023 17:55:57 -0700 Subject: [PATCH 63/82] Revert "Updated code to find AdditionalTypes under AdditionalPropertiesType key as well. (#1017)" This reverts commit 71bd0507ae18c83ae7bc150d63700e56b5f97339. Unit tests fail with this change, because some fields in additional properties become duplicated --- pkg/codegen/codegen_test.go | 46 -- pkg/codegen/schema.go | 5 - ...st_schema_additional_properties_types.yaml | 513 ------------------ 3 files changed, 564 deletions(-) delete mode 100644 pkg/codegen/test_schema_additional_properties_types.yaml diff --git a/pkg/codegen/codegen_test.go b/pkg/codegen/codegen_test.go index 499174be03..6ae61211a9 100644 --- a/pkg/codegen/codegen_test.go +++ b/pkg/codegen/codegen_test.go @@ -201,49 +201,6 @@ type GetTestByNameResponse struct { checkLint(t, "test.gen.go", []byte(code)) } -// Validate any types nested under AdditionalPropertiesTypes is propagated up as with normal Property AdditionalTypes -func TestExampleOpenAPICodeGenerationSchemaAdditionalPropertyTypes(t *testing.T) { - - // Input vars for code generation: - packageName := "testswagger" - opts := Configuration{ - PackageName: packageName, - Generate: GenerateOptions{ - EchoServer: false, - Client: false, - Models: true, - EmbeddedSpec: false, - }, - } - - loader := openapi3.NewLoader() - loader.IsExternalRefsAllowed = true - - // Get a spec from the test definition in this file: - swagger, err := loader.LoadFromData([]byte(testSchemaArrayTypes)) - assert.NoError(t, err) - - // Run our code generation: - code, err := Generate(swagger, opts) - assert.NoError(t, err) - assert.NotEmpty(t, code) - - // Check that we have valid (formattable) code: - _, err = format.Source([]byte(code)) - assert.NoError(t, err) - - // Check that we have a package: - assert.Contains(t, code, "package testswagger") - - // Check that AdditionalPropertyTypes structs are propagated up properly: - assert.Contains(t, code, "[]PatchedBulkWritableCircuitTerminationRequest_Relationships_Destination_Objects_Item") - assert.Contains(t, code, "type PatchedBulkWritableCircuitTerminationRequest_Relationships_Destination_Objects_Item struct {") - assert.Contains(t, code, "[]BulkWritableCircuitTerminationRequest_Relationships_Destination_Objects_Item") - assert.Contains(t, code, "type BulkWritableCircuitTerminationRequest_Relationships_Destination_Objects_Item struct {") - assert.Contains(t, code, "[]WritableCircuitTerminationRequest_Relationships_Destination_Objects_Item ") - assert.Contains(t, code, "type WritableCircuitTerminationRequest_Relationships_Destination_Objects_Item struct {") -} - func TestGoTypeImport(t *testing.T) { packageName := "api" opts := Configuration{ @@ -352,8 +309,5 @@ func (t *ExampleSchema_Item) FromExternalRef0NewPet(v externalRef0.NewPet) error } -//go:embed test_schema_additional_properties_types.yaml -var testSchemaArrayTypes string - //go:embed test_spec.yaml var testOpenAPIDefinition string diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 92f72b4c8c..e9fccbff99 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -71,11 +71,6 @@ func (s Schema) GetAdditionalTypeDefs() []TypeDefinition { for _, p := range s.Properties { result = append(result, p.Schema.GetAdditionalTypeDefs()...) } - // Some schema definitions may be used for key/value and not specify any properties, but provide properties - // within the additionalProperties. See test_schema_array_types.yaml in tests. - if s.AdditionalPropertiesType != nil { - result = append(result, s.AdditionalPropertiesType.GetAdditionalTypeDefs()...) - } result = append(result, s.AdditionalTypes...) return result } diff --git a/pkg/codegen/test_schema_additional_properties_types.yaml b/pkg/codegen/test_schema_additional_properties_types.yaml deleted file mode 100644 index 0cbf800d05..0000000000 --- a/pkg/codegen/test_schema_additional_properties_types.yaml +++ /dev/null @@ -1,513 +0,0 @@ -openapi: 3.0.3 -info: - title: API Documentation - version: 1.5.7 (1.3) - description: Source of truth and network automation platform - license: - name: Apache v2 License -paths: - /circuits/circuit-terminations/: - post: - operationId: circuits_circuit_terminations_create - description: |- - Base class to use for API ViewSets based on OrganizationalModel or PrimaryModel. - - Can also be used for models derived from BaseModel, so long as they support Notes. - tags: - - circuits - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/WritableCircuitTerminationRequest" - required: true - security: - - cookieAuth: [] - - tokenAuth: [] - responses: - "201": - content: - application/json; version=1.3: - schema: - $ref: "#/components/schemas/CircuitTermination" - description: "" - put: - operationId: circuits_circuit_terminations_bulk_update - description: |- - Base class to use for API ViewSets based on OrganizationalModel or PrimaryModel. - - Can also be used for models derived from BaseModel, so long as they support Notes. - tags: - - circuits - requestBody: - content: - application/json: - schema: - type: array - items: - $ref: "#/components/schemas/BulkWritableCircuitTerminationRequest" - required: true - security: - - cookieAuth: [] - - tokenAuth: [] - responses: - "200": - content: - application/json; version=1.3: - schema: - type: array - items: - $ref: "#/components/schemas/CircuitTermination" - description: "" - patch: - operationId: circuits_circuit_terminations_bulk_partial_update - description: |- - Base class to use for API ViewSets based on OrganizationalModel or PrimaryModel. - - Can also be used for models derived from BaseModel, so long as they support Notes. - tags: - - circuits - requestBody: - content: - application/json: - schema: - type: array - items: - $ref: "#/components/schemas/PatchedBulkWritableCircuitTerminationRequest" - required: true - security: - - cookieAuth: [] - - tokenAuth: [] - responses: - "200": - content: - application/json; version=1.3: - schema: - type: array - items: - $ref: "#/components/schemas/CircuitTermination" - description: "" -components: - schemas: - CircuitTermination: - type: object - description: |- - Base class to use for serializers based on OrganizationalModel or PrimaryModel. - - Can also be used for models derived from BaseModel, so long as they support custom fields and relationships. - properties: - id: - type: string - format: uuid - readOnly: true - display: - type: string - readOnly: true - description: Human friendly display value - url: - type: string - format: uri - readOnly: true - description: - type: string - maxLength: 200 - required: - - display - - id - - url - WritableCircuitTerminationRequest: - type: object - description: |- - Base class to use for serializers based on OrganizationalModel or PrimaryModel. - - Can also be used for models derived from BaseModel, so long as they support custom fields and relationships. - properties: - circuit: - type: string - format: uuid - site: - type: string - format: uuid - nullable: true - location: - type: string - format: uuid - nullable: true - provider_network: - type: string - format: uuid - nullable: true - description: - type: string - maxLength: 200 - custom_fields: - type: object - additionalProperties: {} - relationships: - type: object - additionalProperties: - type: object - required: - - id - - url - - name - - type - properties: - id: - type: string - format: uuid - readOnly: true - url: - type: string - format: uri - readOnly: true - name: - type: string - readOnly: true - type: - type: string - readOnly: true - example: one-to-many - source: - type: object - properties: - label: - type: string - readOnly: true - object_type: - type: string - readOnly: true - example: dcim.site - objects: - type: array - items: - type: object - properties: - id: - type: string - format: uuid - url: - type: string - format: uri - readOnly: true - display: - type: string - readOnly: true - additionalProperties: true - destination: - type: object - properties: - label: - type: string - readOnly: true - object_type: - type: string - readOnly: true - example: dcim.site - objects: - type: array - items: - type: object - properties: - id: - type: string - format: uuid - url: - type: string - format: uri - readOnly: true - display: - type: string - readOnly: true - additionalProperties: true - peer: - type: object - properties: - label: - type: string - readOnly: true - object_type: - type: string - readOnly: true - example: dcim.site - objects: - type: array - items: - type: object - properties: - id: - type: string - format: uuid - url: - type: string - format: uri - readOnly: true - display: - type: string - readOnly: true - additionalProperties: true - required: - - circuit - BulkWritableCircuitTerminationRequest: - type: object - description: |- - Base class to use for serializers based on OrganizationalModel or PrimaryModel. - - Can also be used for models derived from BaseModel, so long as they support custom fields and relationships. - properties: - id: - type: string - format: uuid - description: - type: string - maxLength: 200 - custom_fields: - type: object - additionalProperties: true - relationships: - type: object - additionalProperties: - type: object - required: - - id - - url - - name - - type - properties: - id: - type: string - format: uuid - readOnly: true - url: - type: string - format: uri - readOnly: true - name: - type: string - readOnly: true - type: - type: string - readOnly: true - example: one-to-many - source: - type: object - properties: - label: - type: string - readOnly: true - object_type: - type: string - readOnly: true - example: dcim.site - objects: - type: array - items: - type: object - properties: - id: - type: string - format: uuid - url: - type: string - format: uri - readOnly: true - display: - type: string - readOnly: true - additionalProperties: true - destination: - type: object - properties: - label: - type: string - readOnly: true - object_type: - type: string - readOnly: true - example: dcim.site - objects: - type: array - items: - type: object - properties: - id: - type: string - format: uuid - url: - type: string - format: uri - readOnly: true - display: - type: string - readOnly: true - additionalProperties: true - peer: - type: object - properties: - label: - type: string - readOnly: true - object_type: - type: string - readOnly: true - example: dcim.site - objects: - type: array - items: - type: object - properties: - id: - type: string - format: uuid - url: - type: string - format: uri - readOnly: true - display: - type: string - readOnly: true - additionalProperties: true - required: - - id - PatchedBulkWritableCircuitTerminationRequest: - type: object - description: |- - Base class to use for serializers based on OrganizationalModel or PrimaryModel. - - Can also be used for models derived from BaseModel, so long as they support custom fields and relationships. - properties: - id: - type: string - format: uuid - port_speed: - type: integer - maximum: 2147483647 - minimum: 0 - nullable: true - title: Port speed (Kbps) - upstream_speed: - type: integer - maximum: 2147483647 - minimum: 0 - nullable: true - title: Upstream speed (Kbps) - description: Upstream speed, if different from port speed - xconnect_id: - type: string - title: Cross-connect ID - maxLength: 50 - pp_info: - type: string - title: Patch panel/port(s) - maxLength: 100 - description: - type: string - maxLength: 200 - custom_fields: - type: object - additionalProperties: {} - relationships: - type: object - additionalProperties: - type: object - required: - - id - - url - - name - - type - properties: - id: - type: string - format: uuid - readOnly: true - url: - type: string - format: uri - readOnly: true - name: - type: string - readOnly: true - type: - type: string - readOnly: true - example: one-to-many - source: - type: object - properties: - label: - type: string - readOnly: true - object_type: - type: string - readOnly: true - example: dcim.site - objects: - type: array - items: - type: object - properties: - id: - type: string - format: uuid - url: - type: string - format: uri - readOnly: true - display: - type: string - readOnly: true - additionalProperties: true - destination: - type: object - properties: - label: - type: string - readOnly: true - object_type: - type: string - readOnly: true - example: dcim.site - objects: - type: array - items: - type: object - properties: - id: - type: string - format: uuid - url: - type: string - format: uri - readOnly: true - display: - type: string - readOnly: true - additionalProperties: true - peer: - type: object - properties: - label: - type: string - readOnly: true - object_type: - type: string - readOnly: true - example: dcim.site - objects: - type: array - items: - type: object - properties: - id: - type: string - format: uuid - url: - type: string - format: uri - readOnly: true - display: - type: string - readOnly: true - additionalProperties: true - required: - - id From 29ebe3262399dbbf9d9ce612757e50cd2ec2862f Mon Sep 17 00:00:00 2001 From: Steven Hartland Date: Sat, 6 May 2023 02:17:06 +0100 Subject: [PATCH 64/82] chore: move install mapping to global state (#853) Move importMapping into globalState along side other global variables so its all in one place as per comment on that struct. --- pkg/codegen/codegen.go | 14 ++++++-------- pkg/codegen/utils.go | 2 +- pkg/codegen/utils_test.go | 6 +++--- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 70dca564d3..916448133a 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -37,8 +37,9 @@ var templates embed.FS // globalState stores all global state. Please don't put global state anywhere // else so that we can easily track it. var globalState struct { - options Configuration - spec *openapi3.T + options Configuration + spec *openapi3.T + importMapping importMap } // goImport represents a go package to be imported in the generated code @@ -67,8 +68,6 @@ func (im importMap) GoImports() []string { return goImports } -var importMapping importMap - func constructImportMapping(importMapping map[string]string) importMap { var ( pathToName = map[string]string{} @@ -101,8 +100,7 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) { // This is global state globalState.options = opts globalState.spec = spec - - importMapping = constructImportMapping(opts.ImportMapping) + globalState.importMapping = constructImportMapping(opts.ImportMapping) filterOperationsByTag(spec, opts) if !opts.OutputOptions.SkipPrune { @@ -237,7 +235,7 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) { var inlinedSpec string if opts.Generate.EmbeddedSpec { - inlinedSpec, err = GenerateInlinedSpec(t, importMapping, spec) + inlinedSpec, err = GenerateInlinedSpec(t, globalState.importMapping, spec) if err != nil { return "", fmt.Errorf("error generating Go handlers for Paths: %w", err) } @@ -246,7 +244,7 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) { var buf bytes.Buffer w := bufio.NewWriter(&buf) - externalImports := append(importMapping.GoImports(), importMap(xGoTypeImports).GoImports()...) + externalImports := append(globalState.importMapping.GoImports(), importMap(xGoTypeImports).GoImports()...) importsOut, err := GenerateImports(t, externalImports, opts.PackageName) if err != nil { return "", fmt.Errorf("error generating imports: %w", err) diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index 39225384da..cfca21e74c 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -369,7 +369,7 @@ func refPathToGoType(refPath string, local bool) (string, error) { return "", fmt.Errorf("unsupported reference: %s", refPath) } remoteComponent, flatComponent := pathParts[0], pathParts[1] - if goImport, ok := importMapping[remoteComponent]; !ok { + if goImport, ok := globalState.importMapping[remoteComponent]; !ok { return "", fmt.Errorf("unrecognized external reference '%s'; please provide the known import for this reference using option --import-mapping", remoteComponent) } else { goType, err := refPathToGoType("#"+flatComponent, false) diff --git a/pkg/codegen/utils_test.go b/pkg/codegen/utils_test.go index 644167a03e..0da9dfbedb 100644 --- a/pkg/codegen/utils_test.go +++ b/pkg/codegen/utils_test.go @@ -134,12 +134,12 @@ func TestSortedRequestBodyKeys(t *testing.T) { } func TestRefPathToGoType(t *testing.T) { - old := importMapping - importMapping = constructImportMapping(map[string]string{ + old := globalState.importMapping + globalState.importMapping = constructImportMapping(map[string]string{ "doc.json": "externalref0", "http://deepmap.com/doc.json": "externalref1", }) - defer func() { importMapping = old }() + defer func() { globalState.importMapping = old }() tests := []struct { name string From 7ffda6dcbe70682e5bc0015246347d8b5d288c8f Mon Sep 17 00:00:00 2001 From: marcinromaszewicz Date: Fri, 12 May 2023 13:02:31 -0700 Subject: [PATCH 65/82] Allow elevating anonymous types into named types Use the `x-go-type-name` extension to annotate certain anonymous types, so that they are generated as Go types and used inside their original container schema. Only works for objects for now. --- README.md | 4 ++ internal/test/schemas/config.yaml | 2 + internal/test/schemas/schemas.gen.go | 60 +++++++++++++++++----------- internal/test/schemas/schemas.yaml | 13 ++++++ pkg/codegen/schema.go | 26 +++++++++++- 5 files changed, 80 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index f51aa46b5e..bf7cdabda0 100644 --- a/README.md +++ b/README.md @@ -556,6 +556,10 @@ which help you to use the various OpenAPI 3 Authentication mechanism. will override any default value. This extended property isn't supported in all parts of OpenAPI, so please refer to the spec as to where it's allowed. Swagger validation tools will flag incorrect usage of this property. +- `x-go-type-name`: This property allows for assigning a Go type name to some part of a schema, + such as generating a type name for an anonymous object inside another object, or renaming + an enum. It differs from `x-go-type`, in that it doesn't completely replace some type reference, + but simply names it. - `x-go-json-ignore`: sets tag to `-` to ignore the field in json completely. - `x-oapi-codegen-extra-tags`: adds extra Go field tags to the generated struct field. This is useful for interfacing with tag based ORM or validation libraries. The extra tags that diff --git a/internal/test/schemas/config.yaml b/internal/test/schemas/config.yaml index 58b5060d37..9086953659 100644 --- a/internal/test/schemas/config.yaml +++ b/internal/test/schemas/config.yaml @@ -5,3 +5,5 @@ generate: models: true embedded-spec: true output: schemas.gen.go +output-options: + skip-prune: true diff --git a/internal/test/schemas/schemas.gen.go b/internal/test/schemas/schemas.gen.go index d1791abad0..4e2099840e 100644 --- a/internal/test/schemas/schemas.gen.go +++ b/internal/test/schemas/schemas.gen.go @@ -85,6 +85,17 @@ type NullableProperties struct { RequiredAndNullable *string `json:"requiredAndNullable"` } +// OuterTypeWithAnonymousInner defines model for OuterTypeWithAnonymousInner. +type OuterTypeWithAnonymousInner struct { + Inner InnerRenamedAnonymousObject `json:"inner"` + Name string `json:"name"` +} + +// InnerRenamedAnonymousObject defines model for . +type InnerRenamedAnonymousObject struct { + Id int `json:"id"` +} + // StringInPath defines model for StringInPath. type StringInPath = string @@ -1448,30 +1459,31 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/7RYT2/bOhL/KlNugb3YluO0aONbttstvMBrgyYPPdQ50OTYYiORKknZEQx994chZcuu", - "Jb/mpc0lksjh/ObfbzjeMmHywmjU3rHplhXc8hw92vB2663Sq5m+4T6ld4lOWFV4ZTSbsmtwYR0K7lPY", - "S7IBU7RMX9mAaZ4jmzLnacHi91JZlGzqbYkD5kSKOaejfVU025Resbqud4sByOtbz613X5RPP5b5Au0p", - "mrtUOYgiQDrBBRHYKJ8CBx3FBjtFZvENhWf1gF3r6q4q8IJNt+3bpMPcZgUsFhYdeQy4roAOHM31XEcE", - "qSkzCQsErkFpj3bJBW7ruSZd70rnTR7deheAbNnS2Jx7NmUiLLYQG18M2OPQ8EINhZG4Qj3ER2/50POV", - "i+KGTdmCW0Y++y9hE9yjvLGmQOurENX4rDBIaNzQ4qmFfzoET0Zos3lxgqMeMJOFYy+i6E7TLph92yfd", - "2491zzyUDiV4A9JEFFxL8Cn3Z5Bc/gwScmC7Z2iRu725H6MvQGnnkcsXB2e/+tWwn4ajPqyWr/ug7eGx", - "+45cfq/LfKY/Lb7N9LW1PARfeczdaRaseUb/UJc5nb9U1hFkh8JoeXD4viI71DUfeFBVD9gH1GiV+BQ3", - "tFXdSnwss4wvMrw5wnKMzATnRningW8Wr7XcnRVyev/ck4utL7f9i0879IcI7Z+7zzsNVx28XVrlq1vi", - "rWg9FwKdG3rzgJreF8gt2v/tSOL/X+6GkTEg7oSwczTXrGFMUhGF2gxMvS8iqSq9NB3kic6D4A4dLI2F", - "NbfKlA6Uc2X4VGoJZo0WvMpxBDcZcofApQQOfidLonNNlLgoV7BUjygjLK88OTFquUW7DtDWaF3UfjEa", - "j8YxuKh5odiUXY7Gows2CE0kuCVB7UqLQ1yjrXyq9Gqo3NDiEi1qEeO6Qt/TF1DLwijtAR+V8w6cCSUK", - "bfMDwTWxtrBI1QlKh2qea1egCDWtjacNhS01ymAXJS0nNTPJpux9APh+j2/mPrfoKCdcYbSLQZ6Mx/RP", - "GO1RB9C8KDIlwmnJt8AL24PueFwgvO1Y7KXFJZuyfyWtKUnTOJN9Z6sHO5nJT8pMSEZ0dKtzsifdrYM0", - "4t+AJTG3kovJm97Q/cEfEMipUGpXFoWxFJngtEcf+q4DafS/PRQWMS88tLvC6qgjTDPSS1qfGZJzjjjm", - "QTL38KzHPHvOUWR8knP7IM1GP/ugij8HDR0jccnLzP9G5/0ii3/MvLev+0mjKhBWJB8sgE2KGnatJ9nR", - "O7RlCdwi7PpFf9q9fd10B3T+P0ZWv8xpHX01WnuQ4wTv0AGT8VXycuu8rXv98C5F8eBALdvrfTRVosh4", - "64Ks6jZ4Mr5ipxgGR2PG127L2i3J0RhS3x+YcDlOtkueZT61plyl9akFn9FRw5HwgNXGWHl4Qy8shi5F", - "ZE8tjxwYZoeGOBqXdNh1Of4ZszrGoAOwTxqHjox+05+4dAFsgtNkLne7RCZW3CiBFE6fItDVL6wrTcNK", - "ZOi53qRKpM13pySCWdJyuOR1ZfYH9MEnjnD9RlI9udueVPSri2R7EWLQn9E3uxAdDIk0w4YxcT8kdoT8", - "VbyO/F2Ao/6zsT1n5OmgW9f3Z6v4qr94M4Xax8p1oSGC0sJYi8JnFT1npUQZbnwNJ0U3LIys6Moz1629", - "vZx21eOW7yXa6iDxjXlawv9jnmya0qEnPjXMHSxj51nx6kx1tdM1LBVmLZms0ANvuJAulTlq3+uw31sm", - "Hb8AdHgk/HZTiibg8sSu8HnNbUW1keEaM6IBaURJpgVcrKm+3QwTQn88vXy9pzgGAm5So7RZM45Mk6S5", - "7tMAMZKIRc6LEVfE8H8FAAD//5edhkCXEgAA", + "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", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/schemas/schemas.yaml b/internal/test/schemas/schemas.yaml index 319faa7bf6..c93e1f43ff 100644 --- a/internal/test/schemas/schemas.yaml +++ b/internal/test/schemas/schemas.yaml @@ -204,6 +204,19 @@ components: deprecated: true x-deprecated-reason: Use NewProp instead! description: It used to do this and that + OuterTypeWithAnonymousInner: + type: object + properties: + name: + type: string + inner: + type: object + x-go-type-name: InnerRenamedAnonymousObject + properties: + id: + type: integer + required: [ id ] + required: [ name, inner ] parameters: StringInPath: name: str diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index e9fccbff99..eec2ad9240 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -262,7 +262,8 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { return mergedSchema, nil } - // Check for custom Go type extension + // Check x-go-type, which will completely override the definition of this + // schema with the provided type. if extension, ok := schema.Extensions[extPropGoType]; ok { typeName, err := extTypeName(extension) if err != nil { @@ -270,6 +271,7 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { } outSchema.GoType = typeName outSchema.DefineViaAlias = true + return outSchema, nil } @@ -407,6 +409,28 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { outSchema.GoType = GenStructFromSchema(outSchema) } + + // Check for x-go-type-name. It behaves much like x-go-type, however, it will + // create a type definition for the named type, and use the named type in place + // of this schema. + if extension, ok := schema.Extensions[extGoTypeName]; ok { + typeName, err := extTypeName(extension) + if err != nil { + return outSchema, fmt.Errorf("invalid value for %q: %w", extGoTypeName, err) + } + + newTypeDef := TypeDefinition{ + TypeName: typeName, + Schema: outSchema, + } + outSchema = Schema{ + Description: newTypeDef.Schema.Description, + GoType: typeName, + DefineViaAlias: true, + AdditionalTypes: []TypeDefinition{newTypeDef}, + } + } + return outSchema, nil } else if len(schema.Enum) > 0 { err := oapiSchemaToGoType(schema, path, &outSchema) From c1a42f7e620c924f3a7074fc574c0d609105d1bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kurt=20Inge=20Sm=C3=A5dal?= Date: Sat, 13 May 2023 02:03:07 +0200 Subject: [PATCH 66/82] Handle empty application/json request bodies (#1043) --- pkg/codegen/operations.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index 01666ff38f..ab09547d5a 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -661,7 +661,7 @@ func GenerateBodyDefinitions(operationID string, bodyOrRef *openapi3.RequestBody } // If the body is a pre-defined type - if IsGoTypeReference(content.Schema.Ref) { + if content.Schema != nil && IsGoTypeReference(content.Schema.Ref) { // Convert the reference path to Go type refType, err := RefPathToGoType(content.Schema.Ref) if err != nil { From bf56ed28b78d190b11918fa24a10f1dff77aad9e Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 13 May 2023 02:03:23 +0200 Subject: [PATCH 67/82] fixes an error message containing a nil err object (#1048) Signed-off-by: Michal Wasilewski --- cmd/oapi-codegen/oapi-codegen.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/oapi-codegen/oapi-codegen.go b/cmd/oapi-codegen/oapi-codegen.go index ea9e008849..af4361004b 100644 --- a/cmd/oapi-codegen/oapi-codegen.go +++ b/cmd/oapi-codegen/oapi-codegen.go @@ -155,7 +155,7 @@ func main() { t := true oldConfigStyle = &t } else if oldErr != nil && newErr != nil { - errExit("error parsing configuration style as old version or new version: %v\n", err) + errExit("error parsing configuration style as old version or new version\n\nerror when parsing using old config version:\n%v\n\nerror when parsing using new config version:\n%v\n", oldErr, newErr) } // Else we fall through, and we still don't know, so we need to infer it from flags. } From 14548c7e7bbee8d8fbd7e706f9b6f9e3381b44fb Mon Sep 17 00:00:00 2001 From: deef Date: Fri, 12 May 2023 17:09:19 -0700 Subject: [PATCH 68/82] Add ability to try to get templates from files or remotes (#968) * Add ability to try to get templates from remotes * Allow user to add more than builtin templates * Add docs and fix broken test * Add tests for loading in templates from file and URL * Add documentation on different methods of loading user templates * fixed lint issues. Ignore lint of error from the server as its not a useful error to validate. --- README.md | 51 +++++++++++++++++++++ pkg/codegen/codegen.go | 60 ++++++++++++++++++++++--- pkg/codegen/codegen_test.go | 89 ++++++++++++++++++++++++++++++++++++- 3 files changed, 192 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index bf7cdabda0..dd123c3a66 100644 --- a/README.md +++ b/README.md @@ -793,3 +793,54 @@ on-the-fly at run time. Example: -templates my-templates/ \ -generate types,client \ petstore-expanded.yaml + +When using the configuration file, it is possible to provide templates directly +as text, as a local path, or as a URL. If the data provided to the +configuration file is more than one line, the local path and URL checks will be +ignored and will be treated as raw template text. If one line, the string +will be used to check for a local file, followed by checking performing a HTTP +GET request. If the file lookup returns any error other than not found, or the +HTTP request returns a non 200 response code, the generator will error. + +⚠️ Warning: If using urls that tracks against git repositories such as +`raw.githubusercontent.com`, it is strongly encouraged to use a tag or a hash +instead of a branch like `main`. Tracking a branch can lead to unexpected API +drift, and loss of the ability to reproduce a build. + +Examples: +```yaml +output: api.gen.go +package: api +output-options: + user-templates: + # using a local file + client-with-responses.tmpl: /home/username/workspace/templatesProject/my-client-with-responses.tmpl + + # The following are referencing a versuion of the default + # client-with-responses.tmpl file, but loaded in through + # github's raw.githubusercontent.com. The general form + # to use raw.githubusercontent.com is as follows + # https://raw.githubusercontent.com////path/to/template/template.tmpl + + # using raw.githubusercontent.com with a hash + client-with-responses.tmpl: https://raw.githubusercontent.com/deepmap/oapi-codegen/7b010099dcf1192b3bfaa3898b5f375bb9590ddf/pkg/codegen/templates/client-with-responses.tmpl + # using raw.githubusercontent.com with a tag + client-with-responses.tmpl: https://raw.githubusercontent.com/deepmap/oapi-codegen/v1.12.4/pkg/codegen/templates/client-with-responses.tmpl + # using raw.githubusercontent.com with a branch + client-with-responses.tmpl: https://raw.githubusercontent.com/deepmap/oapi-codegen/master/pkg/codegen/templates/client-with-responses.tmpl + + #This example is directly embedding the template into the config file. + client-with-responses.tmpl: | + // ClientWithResponses builds on ClientInterface to offer response payloads + type ClientWithResponses struct { + ClientInterface + } + ... + # template shortened for brevity + +``` + +Using the configuration file to load in templates **will** load in templates +with names other than those defined by the built in templates. These user +templates will not be called unless the user overrides a built in template to +call them however. \ No newline at end of file diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 916448133a..1cf431ed9c 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -19,7 +19,10 @@ import ( "bytes" "embed" "fmt" + "io" "io/fs" + "net/http" + "os" "runtime/debug" "sort" "strings" @@ -126,13 +129,18 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) { return "", fmt.Errorf("error parsing oapi-codegen templates: %w", err) } - // Override built-in templates with user-provided versions - for _, tpl := range t.Templates() { - if _, ok := opts.OutputOptions.UserTemplates[tpl.Name()]; ok { - utpl := t.New(tpl.Name()) - if _, err := utpl.Parse(opts.OutputOptions.UserTemplates[tpl.Name()]); err != nil { - return "", fmt.Errorf("error parsing user-provided template %q: %w", tpl.Name(), err) - } + // load user-provided templates. Will Override built-in versions. + for name, template := range opts.OutputOptions.UserTemplates { + utpl := t.New(name) + + txt, err := GetUserTemplateText(template) + if err != nil { + return "", fmt.Errorf("error loading user-provided template %q: %w", name, err) + } + + _, err = utpl.Parse(txt) + if err != nil { + return "", fmt.Errorf("error parsing user-provided template %q: %w", name, err) } } @@ -815,6 +823,44 @@ func SanitizeCode(goCode string) string { return strings.Replace(goCode, "\uFEFF", "", -1) } +// GetUserTemplateText attempts to retrieve the template text from a passed in URL or file +// path when inputData is more than one line. +// This function will attempt to load a file first, and if it fails, will try to get the +// data from the remote endpoint. +func GetUserTemplateText(inputData string) (template string, err error) { + //if the input data is more than one line, assume its a template and return that data. + if strings.Contains(inputData, "\n") { + return inputData, nil + } + + //load data from file + data, err := os.ReadFile(inputData) + //return data if found and loaded + if err == nil { + return string(data), nil + } + + //check for non "not found" errors + if !os.IsNotExist(err) { + return "", fmt.Errorf("failed to open file %s: %w", inputData, err) + } + + //attempt to get data from url + resp, err := http.Get(inputData) + if err != nil { + return "", fmt.Errorf("failed to execute GET request data from %s: %w", inputData, err) + } + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + return "", fmt.Errorf("got non %d status code on GET %s", resp.StatusCode, inputData) + } + data, err = io.ReadAll(resp.Body) + if err != nil { + return "", fmt.Errorf("failed to read response body from GET %s: %w", inputData, err) + } + + return string(data), nil +} + // LoadTemplates loads all of our template files into a text/template. The // path of template is relative to the templates directory. func LoadTemplates(src embed.FS, t *template.Template) error { diff --git a/pkg/codegen/codegen_test.go b/pkg/codegen/codegen_test.go index 6ae61211a9..32b2466afa 100644 --- a/pkg/codegen/codegen_test.go +++ b/pkg/codegen/codegen_test.go @@ -3,8 +3,10 @@ package codegen import ( "bytes" _ "embed" + "fmt" "go/format" "io" + "net" "net/http" "testing" @@ -77,7 +79,92 @@ func TestExamplePetStoreCodeGeneration(t *testing.T) { func TestExamplePetStoreCodeGenerationWithUserTemplates(t *testing.T) { - userTemplates := map[string]string{"typedef.tmpl": "//blah"} + userTemplates := map[string]string{"typedef.tmpl": "//blah\n//blah"} + + // Input vars for code generation: + packageName := "api" + opts := Configuration{ + PackageName: packageName, + Generate: GenerateOptions{ + Models: true, + }, + OutputOptions: OutputOptions{ + UserTemplates: userTemplates, + }, + } + + // Get a spec from the example PetStore definition: + swagger, err := examplePetstore.GetSwagger() + assert.NoError(t, err) + + // Run our code generation: + code, err := Generate(swagger, opts) + assert.NoError(t, err) + assert.NotEmpty(t, code) + + // Check that we have valid (formattable) code: + _, err = format.Source([]byte(code)) + assert.NoError(t, err) + + // Check that we have a package: + assert.Contains(t, code, "package api") + + // Check that the built-in template has been overriden + assert.Contains(t, code, "//blah") +} + +func TestExamplePetStoreCodeGenerationWithFileUserTemplates(t *testing.T) { + + userTemplates := map[string]string{"typedef.tmpl": "./templates/typedef.tmpl"} + + // Input vars for code generation: + packageName := "api" + opts := Configuration{ + PackageName: packageName, + Generate: GenerateOptions{ + Models: true, + }, + OutputOptions: OutputOptions{ + UserTemplates: userTemplates, + }, + } + + // Get a spec from the example PetStore definition: + swagger, err := examplePetstore.GetSwagger() + assert.NoError(t, err) + + // Run our code generation: + code, err := Generate(swagger, opts) + assert.NoError(t, err) + assert.NotEmpty(t, code) + + // Check that we have valid (formattable) code: + _, err = format.Source([]byte(code)) + assert.NoError(t, err) + + // Check that we have a package: + assert.Contains(t, code, "package api") + + // Check that the built-in template has been overriden + assert.Contains(t, code, "// Package api provides primitives to interact with the openapi") +} + +func TestExamplePetStoreCodeGenerationWithHTTPUserTemplates(t *testing.T) { + + ln, err := net.Listen("tcp", "127.0.0.1:0") + assert.NoError(t, err) + defer ln.Close() + + //nolint:errcheck + //Does not matter if the server returns an error on close etc. + go http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + _, writeErr := w.Write([]byte("//blah")) + assert.NoError(t, writeErr) + })) + + t.Logf("Listening on %s", ln.Addr().String()) + + userTemplates := map[string]string{"typedef.tmpl": fmt.Sprintf("http://%s", ln.Addr().String())} // Input vars for code generation: packageName := "api" From 39d636184062b22043aa2f94d686a82ad6b6efee Mon Sep 17 00:00:00 2001 From: Oleksandr Redko Date: Wed, 31 May 2023 14:26:16 +0300 Subject: [PATCH 69/82] Cmd help: uppercase first letter, and end with a period --- cmd/oapi-codegen/oapi-codegen.go | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/cmd/oapi-codegen/oapi-codegen.go b/cmd/oapi-codegen/oapi-codegen.go index af4361004b..09990d61c9 100644 --- a/cmd/oapi-codegen/oapi-codegen.go +++ b/cmd/oapi-codegen/oapi-codegen.go @@ -79,27 +79,27 @@ type oldConfiguration struct { } func main() { - flag.StringVar(&flagOutputFile, "o", "", "Where to output generated code, stdout is default") - flag.BoolVar(&flagOldConfigStyle, "old-config-style", false, "whether to use the older style config file format") - flag.BoolVar(&flagOutputConfig, "output-config", false, "when true, outputs a configuration file for oapi-codegen using current settings") - flag.StringVar(&flagConfigFile, "config", "", "a YAML config file that controls oapi-codegen behavior") - flag.BoolVar(&flagPrintVersion, "version", false, "when specified, print version and exit") - flag.StringVar(&flagPackageName, "package", "", "The package name for generated code") - flag.BoolVar(&flagPrintUsage, "help", false, "show this help and exit") - flag.BoolVar(&flagPrintUsage, "h", false, "same as -help") + flag.StringVar(&flagOutputFile, "o", "", "Where to output generated code, stdout is default.") + flag.BoolVar(&flagOldConfigStyle, "old-config-style", false, "Whether to use the older style config file format.") + flag.BoolVar(&flagOutputConfig, "output-config", false, "When true, outputs a configuration file for oapi-codegen using current settings.") + flag.StringVar(&flagConfigFile, "config", "", "A YAML config file that controls oapi-codegen behavior.") + flag.BoolVar(&flagPrintVersion, "version", false, "When specified, print version and exit.") + flag.StringVar(&flagPackageName, "package", "", "The package name for generated code.") + flag.BoolVar(&flagPrintUsage, "help", false, "Show this help and exit.") + flag.BoolVar(&flagPrintUsage, "h", false, "Same as -help.") // All flags below are deprecated, and will be removed in a future release. Please do not // update their behavior. flag.StringVar(&flagGenerate, "generate", "types,client,server,spec", - `Comma-separated list of code to generate; valid options: "types", "client", "chi-server", "server", "gin", "gorilla", "spec", "skip-fmt", "skip-prune"`) + `Comma-separated list of code to generate; valid options: "types", "client", "chi-server", "server", "gin", "gorilla", "spec", "skip-fmt", "skip-prune".`) flag.StringVar(&flagIncludeTags, "include-tags", "", "Only include operations with the given tags. Comma-separated list of tags.") flag.StringVar(&flagExcludeTags, "exclude-tags", "", "Exclude operations that are tagged with the given tags. Comma-separated list of tags.") - flag.StringVar(&flagTemplatesDir, "templates", "", "Path to directory containing user templates") - flag.StringVar(&flagImportMapping, "import-mapping", "", "A dict from the external reference to golang package path") - flag.StringVar(&flagExcludeSchemas, "exclude-schemas", "", "A comma separated list of schemas which must be excluded from generation") - flag.StringVar(&flagResponseTypeSuffix, "response-type-suffix", "", "the suffix used for responses types") - flag.BoolVar(&flagAliasTypes, "alias-types", false, "Alias type declarations of possible") - flag.BoolVar(&flagInitalismOverrides, "initialism-overrides", false, "Use initialism overrides") + flag.StringVar(&flagTemplatesDir, "templates", "", "Path to directory containing user templates.") + flag.StringVar(&flagImportMapping, "import-mapping", "", "A dict from the external reference to golang package path.") + flag.StringVar(&flagExcludeSchemas, "exclude-schemas", "", "A comma separated list of schemas which must be excluded from generation.") + flag.StringVar(&flagResponseTypeSuffix, "response-type-suffix", "", "The suffix used for responses types.") + flag.BoolVar(&flagAliasTypes, "alias-types", false, "Alias type declarations of possible.") + flag.BoolVar(&flagInitalismOverrides, "initialism-overrides", false, "Use initialism overrides.") flag.Parse() From 5058196a13c773ce8204e1d4539aae95a78d116c Mon Sep 17 00:00:00 2001 From: Big_Boulard <60930059+BigBoulard@users.noreply.github.com> Date: Thu, 1 Jun 2023 09:15:36 -0700 Subject: [PATCH 70/82] add links to source in the README.md file (#1071) --- README.md | 266 +++++++++++++++++++++++++++++------------------------- 1 file changed, 143 insertions(+), 123 deletions(-) diff --git a/README.md b/README.md index dd123c3a66..467ce1f187 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -OpenAPI Client and Server Code Generator ----------------------------------------- +## OpenAPI Client and Server Code Generator ⚠️ This README may be for the latest development version, which may contain unreleased changes. Please ensure you're looking at the README for the latest @@ -45,12 +44,12 @@ directory does a lot of that for you. You would run it like so: Let's go through that `petstore.gen.go` file to show you everything which was generated. - ## Generated Server Boilerplate The `/components/schemas` section in OpenAPI defines reusable objects, so Go types are generated for these. The Pet Store example defines `Error`, `Pet`, `Pets` and `NewPet`, so we do the same in Go: + ```go // Error defines model for Error. type Error struct { @@ -121,11 +120,12 @@ will be passed as arguments to your function, since they are mandatory. Remaining arguments can be passed in headers, query arguments or cookies. Those will be written to a `params` object. Look at the `FindPets` function above, it takes as input `FindPetsParams`, which is defined as follows: - ```go + +```go // Parameters object for FindPets type FindPetsParams struct { - Tags *[]string `json:"tags,omitempty"` - Limit *int32 `json:"limit,omitempty"` + Tags *[]string `json:"tags,omitempty"` + Limit *int32 `json:"limit,omitempty"` } ``` @@ -135,6 +135,7 @@ specified, the pointer will be non-`nil`, and you can read its value. If you changed the OpenAPI specification to make the parameter required, the `FindPetsParams` structure will contain the type by value: + ```go type FindPetsParams struct { Tags *[]string `json:"tags,omitempty"` @@ -143,6 +144,7 @@ type FindPetsParams struct { ``` ### Registering handlers + There are a few ways of registering your http handler based on the type of server generated i.e. `-generate server` or `-generate chi-server`
Echo @@ -152,6 +154,7 @@ Code generated using `-generate server`. The usage of `Echo` is out of scope of this doc, but once you have an echo instance, we generate a utility function to help you associate your handlers with this autogenerated code. For the pet store, it looks like this: + ```go func RegisterHandlers(router codegen.EchoRouter, si ServerInterface) { wrapper := ServerInterfaceWrapper{ @@ -168,6 +171,7 @@ The wrapper functions referenced above contain generated code which pulls parameters off the `Echo` request context, and unmarshals them into Go objects. You would register the generated handlers as follows: + ```go func SetupHandler() { var myApi PetStoreImpl // This implements the pet store interface @@ -196,6 +200,7 @@ func SetupHandler() { r.Mount("/", Handler(&myApi)) } ``` +
Gin @@ -205,6 +210,7 @@ Code generated using `-generate gin`. The usage of `gin` is out of scope of this doc, but once you have an gin instance, we generate a utility function to help you associate your handlers with this autogenerated code. For the pet store, it looks like this: + ```go // RegisterHandlersWithOptions creates http.Handler with additional options func RegisterHandlersWithOptions(router *gin.Engine, si ServerInterface, options GinServerOptions) *gin.Engine { @@ -241,6 +247,7 @@ func SetupHandler() { r = api.RegisterHandlers(r, petStore) } ``` +
net/http @@ -266,8 +273,8 @@ Alternatively, [Gorilla](https://github.com/gorilla/mux) is also 100% compatible #### Strict server generation -oapi-codegen also supports generating RPC inspired strict server, that will parse request bodies and encode responses. -The main points of this code is to automate some parsing, abstract user code from server specific code, +oapi-codegen also supports generating RPC inspired strict server, that will parse request bodies and encode responses. +The main points of this code is to automate some parsing, abstract user code from server specific code, and also to force user code to comply with the schema. It supports binding of `application/json` and `application/x-www-form-urlencoded` to a struct, for `multipart` requests it generates a `multipart.Reader`, which can be used to either manually iterating over parts or using `runtime.BindMultipart` @@ -279,6 +286,7 @@ Content-Type header, status code and will marshal the response data. You can als cause an `Internal Server Error` response. Short example: + ```go type PetStoreImpl struct {} func (*PetStoreImpl) GetPets(ctx context.Context, request GetPetsRequestObject) (GetPetsResponseObject, error) { @@ -287,10 +295,12 @@ func (*PetStoreImpl) GetPets(ctx context.Context, request GetPetsRequestObject) return GetPets200JSONResponse(result), nil } ``` -For a complete example see `/examples/petstore-expanded/strict`. + +For a complete example see [`examples/petstore-expanded/strict`](https://github.com/deepmap/oapi-codegen/tree/master/examples/petstore-expanded/strict). Code is generated with a configuration flag `generate: strict-server: true` along with any other server (echo, chi, gin and gorilla are supported). The generated strict wrapper can then be used as an implementation for `ServerInterface`. Setup example: + ```go func SetupHandler() { var myApi PetStoreImpl @@ -317,20 +327,22 @@ defaults to `false` and we don't generate this boilerplate. If you would like an object to accept `additionalProperties`, specify a schema for `additionalProperties`. Say we declared `NewPet` above like so: + ```yaml - NewPet: - required: - - name - properties: - name: - type: string - tag: - type: string - additionalProperties: - type: string +NewPet: + required: + - name + properties: + name: + type: string + tag: + type: string + additionalProperties: + type: string ``` The Go code for `NewPet` would now look like this: + ```go // NewPet defines model for NewPet. type NewPet struct { @@ -342,6 +354,7 @@ type NewPet struct { The additionalProperties, of type `string` become `map[string]string`, which maps field names to instances of the `additionalProperties` schema. + ```go // Getter for additional properties for NewPet. Returns the specified // element and whether it was found @@ -359,23 +372,25 @@ func (a NewPet) MarshalJSON() ([]byte, error) {...}w There are many special cases for `additionalProperties`, such as having to define types for inner fields which themselves support additionalProperties, and -all of them are tested via the `internal/test/components` schemas and tests. Please +all of them are tested via the [`internal/test/components`](https://github.com/deepmap/oapi-codegen/tree/master/internal/test/components) schemas and tests. Please look through those tests for more usage examples. #### oneOf/anyOf/allOf support - `oneOf` and `anyOf` are implemented using delayed parsing with the help of `json.RawMessage`. -The following schema will result in a type that has methods such as `AsCat`, `AsDog`, `FromCat`, `FromDog`, `MergeCat`, `MergeDog`. If the schema also includes a discriminator the generated code will also have methods such as `Discriminator`, `ValueByDiscriminator` and will force discriminator value in `From` methods. + The following schema will result in a type that has methods such as `AsCat`, `AsDog`, `FromCat`, `FromDog`, `MergeCat`, `MergeDog`. If the schema also includes a discriminator the generated code will also have methods such as `Discriminator`, `ValueByDiscriminator` and will force discriminator value in `From` methods. + ```yaml schema: oneOf: - $ref: '#/components/schemas/Cat' - $ref: '#/components/schemas/Dog' ``` + - `allOf` is supported, by taking the union of all the fields in all the - component schemas. This is the most useful of these operations, and is - commonly used to merge objects with an identifier, as in the - `petstore-expanded` example. + component schemas. This is the most useful of these operations, and is + commonly used to merge objects with an identifier, as in the + `petstore-expanded` example. ## Generated Client Boilerplate @@ -427,21 +442,21 @@ takes the same arguments. It's difficult to handle any arbitrary body that Swagger supports, so we've done some special casing for bodies, and you may get more than one function for an operation with a request body. -1) If you have more than one request body type, meaning more than one media - type, you will have a generic handler of this form: +1. If you have more than one request body type, meaning more than one media + type, you will have a generic handler of this form: - AddPet(ctx context.Context, contentType string, body io.Reader) + AddPet(ctx context.Context, contentType string, body io.Reader) -2) If you have only a JSON request body, you will get: +2. If you have only a JSON request body, you will get: - AddPet(ctx context.Context, body NewPet) + AddPet(ctx context.Context, body NewPet) -3) If you have multiple request body types, which include a JSON type you will - get two functions. We've chosen to give the JSON version a shorter name, as - we work with JSON and don't want to wear out our keyboards. +3. If you have multiple request body types, which include a JSON type you will + get two functions. We've chosen to give the JSON version a shorter name, as + we work with JSON and don't want to wear out our keyboards. - AddPet(ctx context.Context, body NewPet) - AddPetWithBody(ctx context.Context, contentType string, body io.Reader) + AddPet(ctx context.Context, body NewPet) + AddPetWithBody(ctx context.Context, contentType string, body io.Reader) The Client object above is fairly flexible, since you can pass in your own `http.Client` and a request editing callback. You can use that callback to add @@ -473,30 +488,30 @@ will correspond to your request schema. They map one-to-one to the functions on the client, except that we always generate the generic non-JSON body handler. There are some caveats to using this code. + - exploded, form style query arguments, which are the default argument format - in OpenAPI 3.0 are undecidable. Say that I have two objects, one composed of - the fields `(name=bob, id=5)` and another which has `(name=shoe, color=brown)`. - The first parameter is named `person` and the second is named `item`. The - default marshaling style for query args would result in - `/path/?name=bob,id=5&name=shoe,color=brown`. In order to tell what belongs - to which object, we'd have to look at all the parameters and try to deduce it, - but we're lazy, so we didn't. Don't use exploded form style arguments if - you're passing around objects which have similar field names. If you - used unexploded form parameters, you'd have - `/path/?person=name,bob,id,5&item=name,shoe,color,brown`, which an be - parsed unambiguously. + in OpenAPI 3.0 are undecidable. Say that I have two objects, one composed of + the fields `(name=bob, id=5)` and another which has `(name=shoe, color=brown)`. + The first parameter is named `person` and the second is named `item`. The + default marshaling style for query args would result in + `/path/?name=bob,id=5&name=shoe,color=brown`. In order to tell what belongs + to which object, we'd have to look at all the parameters and try to deduce it, + but we're lazy, so we didn't. Don't use exploded form style arguments if + you're passing around objects which have similar field names. If you + used unexploded form parameters, you'd have + `/path/?person=name,bob,id,5&item=name,shoe,color,brown`, which an be + parsed unambiguously. - Parameters can be defined via `schema` or via `content`. Use the `content` form - for anything other than trivial objects, they can marshal to arbitrary JSON - structures. When you send them as cookie (`in: cookie`) arguments, we will - URL encode them, since JSON delimiters aren't allowed in cookies. + for anything other than trivial objects, they can marshal to arbitrary JSON + structures. When you send them as cookie (`in: cookie`) arguments, we will + URL encode them, since JSON delimiters aren't allowed in cookies. ## Using SecurityProviders If you generate client-code, you can use some default-provided security providers which help you to use the various OpenAPI 3 Authentication mechanism. - ```go import ( "github.com/deepmap/oapi-codegen/pkg/securityprovider" @@ -563,51 +578,56 @@ which help you to use the various OpenAPI 3 Authentication mechanism. - `x-go-json-ignore`: sets tag to `-` to ignore the field in json completely. - `x-oapi-codegen-extra-tags`: adds extra Go field tags to the generated struct field. This is useful for interfacing with tag based ORM or validation libraries. The extra tags that - are added are in addition to the regular json tags that are generated. If you specify your - own `json` tag, you will override the default one. - - ```yaml - components: - schemas: - Object: - properties: - name: - type: string - x-oapi-codegen-extra-tags: - tag1: value1 - tag2: value2 - ``` - In the example above, field `name` will be declared as: - + are added are in addition to the regular json tags that are generated. If you specify your + own `json` tag, you will override the default one. + + ```yaml + components: + schemas: + Object: + properties: + name: + type: string + x-oapi-codegen-extra-tags: + tag1: value1 + tag2: value2 + ``` + + In the example above, field `name` will be declared as: + ``` Name string `json:"name" tag1:"value1" tag2:"value2"` ``` + - `x-go-type-import`: adds extra Go imports to your generated code. It can help you, when you want to - choose your own import package for `x-go-type`. + choose your own import package for `x-go-type`. ```yaml - schemas: - Pet: - properties: - age: - x-go-type: myuuid.UUID - x-go-type-import: - name: myuuid - path: github.com/google/uuid + schemas: + Pet: + properties: + age: + x-go-type: myuuid.UUID + x-go-type-import: + name: myuuid + path: github.com/google/uuid ``` + After code generation you will get this: + ```go import ( ... myuuid "github.com/google/uuid" ) - + //Pet defines model for Pet. type Pet struct { Age *myuuid.UUID `json:"age,omitempty"` } ``` + `name` is an optional parameter. Example: ```yaml @@ -627,44 +647,44 @@ which help you to use the various OpenAPI 3 Authentication mechanism. ```go import ( - "github.com/google/uuid" + "github.com/google/uuid" ) // Pet defines model for Pet. type Pet struct { - Age uuid.UUID `json:"age"` + Age uuid.UUID `json:"age"` } ``` - `x-enum-varnames`: supplies other enum names for the corresponding values. (alias: `x-enumNames`) - ```yaml - components: - schemas: - Object: - properties: - category: - type: integer - enum: [0, 1, 2] - x-enum-varnames: - - notice - - warning - - urgent - ``` - - After code generation you will get this result: - - ```go - // Defines values for ObjectCategory. - const ( - Notice ObjectCategory = 0 - Urgent ObjectCategory = 2 - Warning ObjectCategory = 1 - ) + ```yaml + components: + schemas: + Object: + properties: + category: + type: integer + enum: [0, 1, 2] + x-enum-varnames: + - notice + - warning + - urgent + ``` - // ObjectCategory defines model for Object.Category. - type ObjectCategory int - ``` + After code generation you will get this result: + + ```go + // Defines values for ObjectCategory. + const ( + Notice ObjectCategory = 0 + Urgent ObjectCategory = 2 + Warning ObjectCategory = 1 + ) + + // ObjectCategory defines model for Object.Category. + type ObjectCategory int + ``` ## Using `oapi-codegen` @@ -674,23 +694,23 @@ those via the `-generate` flag. It defaults to `types,client,server,spec`, but you can specify any combination of those. - `types`: generate all type definitions for all types in the OpenAPI spec. This - will be everything under `#components`, as well as request parameter, request - body, and response type objects. + will be everything under `#components`, as well as request parameter, request + body, and response type objects. - `server`: generate the Echo server boilerplate. `server` requires the types in the - same package to compile. + same package to compile. - `chi-server`: generate the Chi server boilerplate. This code is dependent on - that produced by the `types` target. + that produced by the `types` target. - `client`: generate the client boilerplate. It, too, requires the types to be - present in its package. + present in its package. - `spec`: embed the OpenAPI spec into the generated code as a gzipped blob. This is then usable with the `OapiRequestValidator`, or to be used by other methods that need access to the parsed OpenAPI specification - `skip-fmt`: skip running `goimports` on the generated code. This is useful for debugging - the generated file in case the spec contains weird strings. + the generated file in case the spec contains weird strings. - `skip-prune`: skip pruning unused components from the spec prior to generating - the code. + the code. - `import-mapping`: specifies a map of references external OpenAPI specs to go - Go include paths. Please see below. + Go include paths. Please see below. So, for example, if you would like to produce only the server code, you could run `oapi-codegen -generate types,server`. You could generate `types` and @@ -715,7 +735,7 @@ them pretty unwieldy, so you can specify all of the options in a configuration file via the `--config` option. Please see the test under [`/internal/test/externalref/`](https://github.com/deepmap/oapi-codegen/blob/master/internal/test/externalref/externalref.cfg.yaml) for an example. The structure of the file is as follows: - + ```yaml package: externalref generate: @@ -729,7 +749,7 @@ output-options: skip-prune: true ``` -Have a look at [`cmd/oapi-codegen/oapi-codegen.go`](https://github.com/deepmap/oapi-codegen/blob/master/cmd/oapi-codegen/oapi-codegen.go#L48) +Have a look at [`cmd/oapi-codegen/oapi-codegen.go`](https://github.com/deepmap/oapi-codegen/blob/master/cmd/oapi-codegen/oapi-codegen.go#L48) to see all the fields on the configuration structure. ### Import Mappings @@ -760,10 +780,9 @@ This code is still young, and not complete, since we're filling it in as we need it. We've not yet implemented several things: - `patternProperties` isn't yet supported and will exit with an error. Pattern - properties were defined in JSONSchema, and the `kin-openapi` Swagger object - knows how to parse them, but they're not part of OpenAPI 3.0, so we've left - them out, as support is very complicated. - + properties were defined in JSONSchema, and the `kin-openapi` Swagger object + knows how to parse them, but they're not part of OpenAPI 3.0, so we've left + them out, as support is very complicated. ## Making changes to code generation @@ -778,7 +797,7 @@ All this command does is inline the files ending in `.tmpl` into the specified Go file. Afterwards you should run `go generate ./...`, and the templates will be updated - accordingly. +accordingly. Alternatively, you can provide custom templates to override built-in ones using the `-templates` flag specifying a path to a directory containing templates @@ -807,7 +826,8 @@ HTTP request returns a non 200 response code, the generator will error. instead of a branch like `main`. Tracking a branch can lead to unexpected API drift, and loss of the ability to reproduce a build. -Examples: +Examples: + ```yaml output: api.gen.go package: api @@ -817,8 +837,8 @@ output-options: client-with-responses.tmpl: /home/username/workspace/templatesProject/my-client-with-responses.tmpl # The following are referencing a versuion of the default - # client-with-responses.tmpl file, but loaded in through - # github's raw.githubusercontent.com. The general form + # client-with-responses.tmpl file, but loaded in through + # github's raw.githubusercontent.com. The general form # to use raw.githubusercontent.com is as follows # https://raw.githubusercontent.com////path/to/template/template.tmpl @@ -840,7 +860,7 @@ output-options: ``` -Using the configuration file to load in templates **will** load in templates +Using the configuration file to load in templates **will** load in templates with names other than those defined by the built in templates. These user templates will not be called unless the user overrides a built in template to -call them however. \ No newline at end of file +call them however. From 9d9d659444df8810c4ab636ea4a64f5314aedaec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jun 2023 09:16:09 -0700 Subject: [PATCH 71/82] Bump github.com/getkin/kin-openapi from 0.116.0 to 0.117.0 (#1054) Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.116.0 to 0.117.0. - [Release notes](https://github.com/getkin/kin-openapi/releases) - [Commits](https://github.com/getkin/kin-openapi/compare/v0.116.0...v0.117.0) --- updated-dependencies: - dependency-name: github.com/getkin/kin-openapi dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 240683feca..8c42afc16b 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module github.com/deepmap/oapi-codegen require ( github.com/apapsch/go-jsonmerge/v2 v2.0.0 - github.com/getkin/kin-openapi v0.116.0 + github.com/getkin/kin-openapi v0.117.0 github.com/gin-gonic/gin v1.9.0 github.com/go-chi/chi/v5 v5.0.8 github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219 diff --git a/go.sum b/go.sum index f5edf9d5cc..ae2df9b7f4 100644 --- a/go.sum +++ b/go.sum @@ -16,8 +16,8 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= -github.com/getkin/kin-openapi v0.116.0 h1:o986hwgMzR972JzOG5j6+WTwWqllZLs1EJKMKCivs2E= -github.com/getkin/kin-openapi v0.116.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc= +github.com/getkin/kin-openapi v0.117.0 h1:QT2DyGujAL09F4NrKDHJGsUoIprlIcFVHWDVDcUFE8A= +github.com/getkin/kin-openapi v0.117.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8= From a251988c38080e56efc6ddf631a857747978bdb0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jun 2023 09:16:25 -0700 Subject: [PATCH 72/82] Bump github.com/stretchr/testify from 1.8.2 to 1.8.3 (#1053) Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.8.2 to 1.8.3. - [Release notes](https://github.com/stretchr/testify/releases) - [Commits](https://github.com/stretchr/testify/compare/v1.8.2...v1.8.3) --- updated-dependencies: - dependency-name: github.com/stretchr/testify dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 8c42afc16b..66738effd5 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/labstack/echo/v4 v4.10.2 github.com/lestrrat-go/jwx v1.2.25 github.com/matryer/moq v0.3.1 - github.com/stretchr/testify v1.8.2 + github.com/stretchr/testify v1.8.3 golang.org/x/text v0.9.0 golang.org/x/tools v0.8.0 gopkg.in/yaml.v2 v2.4.0 diff --git a/go.sum b/go.sum index ae2df9b7f4..c08cfc4f56 100644 --- a/go.sum +++ b/go.sum @@ -129,8 +129,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= From 704ee444e4df1278d63555d21becb42d2ac41790 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jun 2023 09:16:35 -0700 Subject: [PATCH 73/82] Bump golang.org/x/tools from 0.8.0 to 0.9.1 (#1049) Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.8.0 to 0.9.1. - [Release notes](https://github.com/golang/tools/releases) - [Commits](https://github.com/golang/tools/compare/v0.8.0...v0.9.1) --- updated-dependencies: - dependency-name: golang.org/x/tools dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index 66738effd5..7de2a16f53 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/matryer/moq v0.3.1 github.com/stretchr/testify v1.8.3 golang.org/x/text v0.9.0 - golang.org/x/tools v0.8.0 + golang.org/x/tools v0.9.1 gopkg.in/yaml.v2 v2.4.0 ) @@ -59,8 +59,8 @@ require ( golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect golang.org/x/crypto v0.6.0 // indirect golang.org/x/mod v0.10.0 // indirect - golang.org/x/net v0.9.0 // indirect - golang.org/x/sys v0.7.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sys v0.8.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect google.golang.org/protobuf v1.28.1 // indirect diff --git a/go.sum b/go.sum index c08cfc4f56..4fb0761406 100644 --- a/go.sum +++ b/go.sum @@ -150,9 +150,9 @@ golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58 golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= -golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -160,8 +160,8 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= @@ -169,8 +169,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y= -golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= +golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= +golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From f0f757918272cadef8ba1d2f4a04fccdd0b607c8 Mon Sep 17 00:00:00 2001 From: Oleksandr Redko Date: Thu, 1 Jun 2023 19:25:55 +0300 Subject: [PATCH 74/82] Fix typos in comments (#1050) --- examples/authenticated-api/echo/server/fake_jws.go | 2 +- pkg/chi-middleware/oapi_validate.go | 2 +- pkg/codegen/codegen_test.go | 6 +++--- pkg/codegen/utils.go | 2 +- pkg/runtime/bindstring.go | 2 +- pkg/util/inputmapping.go | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/authenticated-api/echo/server/fake_jws.go b/examples/authenticated-api/echo/server/fake_jws.go index 928b2dc048..0cf44e0d90 100644 --- a/examples/authenticated-api/echo/server/fake_jws.go +++ b/examples/authenticated-api/echo/server/fake_jws.go @@ -74,7 +74,7 @@ func (f *FakeAuthenticator) ValidateJWS(jwsString string) (jwt.Token, error) { jwt.WithAudience(FakeAudience), jwt.WithIssuer(FakeIssuer)) } -// SignToken takes a JWT and signs it with our priviate key, returning a JWS. +// SignToken takes a JWT and signs it with our private key, returning a JWS. func (f *FakeAuthenticator) SignToken(t jwt.Token) ([]byte, error) { hdr := jws.NewHeaders() if err := hdr.Set(jws.AlgorithmKey, jwa.ES256); err != nil { diff --git a/pkg/chi-middleware/oapi_validate.go b/pkg/chi-middleware/oapi_validate.go index c09c2f1e28..b654dc3cf6 100644 --- a/pkg/chi-middleware/oapi_validate.go +++ b/pkg/chi-middleware/oapi_validate.go @@ -1,6 +1,6 @@ // Package middleware implements middleware function for go-chi or net/http, // which validates incoming HTTP requests to make sure that they conform to the given OAPI 3.0 specification. -// When OAPI validation failes on the request, we return an HTTP/400. +// When OAPI validation fails on the request, we return an HTTP/400. package middleware import ( diff --git a/pkg/codegen/codegen_test.go b/pkg/codegen/codegen_test.go index 32b2466afa..a127bf0a28 100644 --- a/pkg/codegen/codegen_test.go +++ b/pkg/codegen/codegen_test.go @@ -109,7 +109,7 @@ func TestExamplePetStoreCodeGenerationWithUserTemplates(t *testing.T) { // Check that we have a package: assert.Contains(t, code, "package api") - // Check that the built-in template has been overriden + // Check that the built-in template has been overridden assert.Contains(t, code, "//blah") } @@ -145,7 +145,7 @@ func TestExamplePetStoreCodeGenerationWithFileUserTemplates(t *testing.T) { // Check that we have a package: assert.Contains(t, code, "package api") - // Check that the built-in template has been overriden + // Check that the built-in template has been overridden assert.Contains(t, code, "// Package api provides primitives to interact with the openapi") } @@ -194,7 +194,7 @@ func TestExamplePetStoreCodeGenerationWithHTTPUserTemplates(t *testing.T) { // Check that we have a package: assert.Contains(t, code, "package api") - // Check that the built-in template has been overriden + // Check that the built-in template has been overridden assert.Contains(t, code, "//blah") } diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index cfca21e74c..6fb031e49c 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -521,7 +521,7 @@ func IsGoKeyword(str string) bool { } // IsPredeclaredGoIdentifier returns whether the given string -// is a predefined go indentifier. +// is a predefined go identifier. // // See https://golang.org/ref/spec#Predeclared_identifiers func IsPredeclaredGoIdentifier(str string) bool { diff --git a/pkg/runtime/bindstring.go b/pkg/runtime/bindstring.go index 72f74dd1bf..efc98670fc 100644 --- a/pkg/runtime/bindstring.go +++ b/pkg/runtime/bindstring.go @@ -42,7 +42,7 @@ func BindStringToObject(src string, dst interface{}) error { t = v.Type() } - // For some optioinal args + // For some optional args if t.Kind() == reflect.Ptr { if v.IsNil() { v.Set(reflect.New(t.Elem())) diff --git a/pkg/util/inputmapping.go b/pkg/util/inputmapping.go index fb2ac756aa..7b475dbdd7 100644 --- a/pkg/util/inputmapping.go +++ b/pkg/util/inputmapping.go @@ -5,7 +5,7 @@ import ( "strings" ) -// The input mapping is experessed on the command line as `key1:value1,key2:value2,...` +// The input mapping is expressed on the command line as `key1:value1,key2:value2,...` // We parse it here, but need to keep in mind that keys or values may contain // commas and colons. We will allow escaping those using double quotes, so // when passing in "key1":"value1", we will not look inside the quoted sections. @@ -47,7 +47,7 @@ func ParseCommandLineList(input string) []string { return args } -// This function splits a string along the specifed separator, but it +// This function splits a string along the specified separator, but it // ignores anything between double quotes for splitting. We do simple // inside/outside quote counting. Quotes are not stripped from output. func splitString(s string, sep rune) []string { From f442b7bd9551cfbd0fe4c9b6dc977a6fa630bfdf Mon Sep 17 00:00:00 2001 From: Adam Weiss Date: Thu, 1 Jun 2023 12:26:08 -0400 Subject: [PATCH 75/82] fix: Avoid nil reference for gin wrapper (#1057) --- pkg/codegen/templates/gin/gin-wrappers.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/codegen/templates/gin/gin-wrappers.tmpl b/pkg/codegen/templates/gin/gin-wrappers.tmpl index c34a522873..e30e839f5d 100644 --- a/pkg/codegen/templates/gin/gin-wrappers.tmpl +++ b/pkg/codegen/templates/gin/gin-wrappers.tmpl @@ -69,7 +69,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { params.{{.GoName}} = {{if not .Required}}&{{end}}value {{end}} }{{if .Required}} else { - siw.ErrorHandler(c, fmt.Errorf("Query argument {{.ParamName}} is required, but not found: %s", err), http.StatusBadRequest) + siw.ErrorHandler(c, fmt.Errorf("Query argument {{.ParamName}} is required, but not found"), http.StatusBadRequest) return }{{end}} {{end}} @@ -118,7 +118,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { params.{{.GoName}} = {{if not .Required}}&{{end}}{{.GoName}} } {{if .Required}}else { - siw.ErrorHandler(c, fmt.Errorf("Header parameter {{.ParamName}} is required, but not found: %s", err), http.StatusBadRequest) + siw.ErrorHandler(c, fmt.Errorf("Header parameter {{.ParamName}} is required, but not found"), http.StatusBadRequest) return }{{end}} From 87dda379dfc021e2a877ce13477880c3c73bc3cb Mon Sep 17 00:00:00 2001 From: Yuri Tinyukov <31764980+yuoppp@users.noreply.github.com> Date: Thu, 1 Jun 2023 19:26:24 +0300 Subject: [PATCH 76/82] checking query params for nil value (#1064) Co-authored-by: Yury Tinyukov --- pkg/codegen/templates/client.tmpl | 58 ++++++++++++++++--------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/pkg/codegen/templates/client.tmpl b/pkg/codegen/templates/client.tmpl index 58df443c76..f3afe84288 100644 --- a/pkg/codegen/templates/client.tmpl +++ b/pkg/codegen/templates/client.tmpl @@ -194,36 +194,38 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr } {{if .QueryParams}} - queryValues := queryURL.Query() -{{range $paramIdx, $param := .QueryParams}} - {{if not .Required}} if params.{{.GoName}} != nil { {{end}} - {{if .IsPassThrough}} - queryValues.Add("{{.ParamName}}", {{if not .Required}}*{{end}}params.{{.GoName}}) - {{end}} - {{if .IsJson}} - if queryParamBuf, err := json.Marshal({{if not .Required}}*{{end}}params.{{.GoName}}); err != nil { - return nil, err - } else { - queryValues.Add("{{.ParamName}}", string(queryParamBuf)) - } + if params != nil { + queryValues := queryURL.Query() + {{range $paramIdx, $param := .QueryParams}} + {{if not .Required}} if params.{{.GoName}} != nil { {{end}} + {{if .IsPassThrough}} + queryValues.Add("{{.ParamName}}", {{if not .Required}}*{{end}}params.{{.GoName}}) + {{end}} + {{if .IsJson}} + if queryParamBuf, err := json.Marshal({{if not .Required}}*{{end}}params.{{.GoName}}); err != nil { + return nil, err + } else { + queryValues.Add("{{.ParamName}}", string(queryParamBuf)) + } - {{end}} - {{if .IsStyled}} - if queryFrag, err := runtime.StyleParamWithLocation("{{.Style}}", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationQuery, {{if not .Required}}*{{end}}params.{{.GoName}}); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } + {{end}} + {{if .IsStyled}} + if queryFrag, err := runtime.StyleParamWithLocation("{{.Style}}", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationQuery, {{if not .Required}}*{{end}}params.{{.GoName}}); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + {{end}} + {{if not .Required}}}{{end}} + {{end}} + queryURL.RawQuery = queryValues.Encode() } - {{end}} - {{if not .Required}}}{{end}} -{{end}} - queryURL.RawQuery = queryValues.Encode() {{end}}{{/* if .QueryParams */}} req, err := http.NewRequest("{{.Method}}", queryURL.String(), {{if .HasBody}}body{{else}}nil{{end}}) if err != nil { From 5ba8e44e450fe1a82d1b70531db8ec87f50bc08f Mon Sep 17 00:00:00 2001 From: marcinromaszewicz Date: Thu, 1 Jun 2023 09:28:41 -0700 Subject: [PATCH 77/82] Regenerate boilerplate --- .../petstore-expanded/petstore-client.gen.go | 54 ++-- internal/test/any_of/param/param.gen.go | 54 ++-- internal/test/parameters/parameters.gen.go | 246 +++++++++--------- internal/test/schemas/schemas.gen.go | 24 +- internal/test/strict-server/gin/server.gen.go | 2 +- 5 files changed, 196 insertions(+), 184 deletions(-) diff --git a/examples/petstore-expanded/petstore-client.gen.go b/examples/petstore-expanded/petstore-client.gen.go index 0929a64096..766135e380 100644 --- a/examples/petstore-expanded/petstore-client.gen.go +++ b/examples/petstore-expanded/petstore-client.gen.go @@ -225,42 +225,44 @@ func NewFindPetsRequest(server string, params *FindPetsParams) (*http.Request, e return nil, err } - queryValues := queryURL.Query() - - if params.Tags != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "tags", runtime.ParamLocationQuery, *params.Tags); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) + if params != nil { + queryValues := queryURL.Query() + + if params.Tags != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "tags", runtime.ParamLocationQuery, *params.Tags); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } } } - } - - } - if params.Limit != nil { + } - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "limit", runtime.ParamLocationQuery, *params.Limit); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) + if params.Limit != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "limit", runtime.ParamLocationQuery, *params.Limit); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } } } + } + queryURL.RawQuery = queryValues.Encode() } - queryURL.RawQuery = queryValues.Encode() - req, err := http.NewRequest("GET", queryURL.String(), nil) if err != nil { return nil, err diff --git a/internal/test/any_of/param/param.gen.go b/internal/test/any_of/param/param.gen.go index 07dd59bca2..650f1f3cc4 100644 --- a/internal/test/any_of/param/param.gen.go +++ b/internal/test/any_of/param/param.gen.go @@ -281,42 +281,44 @@ func NewGetTestRequest(server string, params *GetTestParams) (*http.Request, err return nil, err } - queryValues := queryURL.Query() - - if params.Test != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "test", runtime.ParamLocationQuery, *params.Test); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) + if params != nil { + queryValues := queryURL.Query() + + if params.Test != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "test", runtime.ParamLocationQuery, *params.Test); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } } } - } - - } - if params.Test2 != nil { + } - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "test2", runtime.ParamLocationQuery, *params.Test2); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) + if params.Test2 != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "test2", runtime.ParamLocationQuery, *params.Test2); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } } } + } + queryURL.RawQuery = queryValues.Encode() } - queryURL.RawQuery = queryValues.Encode() - req, err := http.NewRequest("GET", queryURL.String(), nil) if err != nil { return nil, err diff --git a/internal/test/parameters/parameters.gen.go b/internal/test/parameters/parameters.gen.go index 45d11b462c..1f2b4b840f 100644 --- a/internal/test/parameters/parameters.gen.go +++ b/internal/test/parameters/parameters.gen.go @@ -732,26 +732,28 @@ func NewEnumParamsRequest(server string, params *EnumParamsParams) (*http.Reques return nil, err } - queryValues := queryURL.Query() - - if params.EnumPathParam != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "enumPathParam", runtime.ParamLocationQuery, *params.EnumPathParam); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) + if params != nil { + queryValues := queryURL.Query() + + if params.EnumPathParam != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "enumPathParam", runtime.ParamLocationQuery, *params.EnumPathParam); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } } } + } + queryURL.RawQuery = queryValues.Encode() } - queryURL.RawQuery = queryValues.Encode() - req, err := http.NewRequest("GET", queryURL.String(), nil) if err != nil { return nil, err @@ -1199,21 +1201,23 @@ func NewGetDeepObjectRequest(server string, params *GetDeepObjectParams) (*http. return nil, err } - queryValues := queryURL.Query() + if params != nil { + queryValues := queryURL.Query() - if queryFrag, err := runtime.StyleParamWithLocation("deepObject", true, "deepObj", runtime.ParamLocationQuery, params.DeepObj); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) + if queryFrag, err := runtime.StyleParamWithLocation("deepObject", true, "deepObj", runtime.ParamLocationQuery, params.DeepObj); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } } } - } - queryURL.RawQuery = queryValues.Encode() + queryURL.RawQuery = queryValues.Encode() + } req, err := http.NewRequest("GET", queryURL.String(), nil) if err != nil { @@ -1242,148 +1246,150 @@ func NewGetQueryFormRequest(server string, params *GetQueryFormParams) (*http.Re return nil, err } - queryValues := queryURL.Query() + if params != nil { + queryValues := queryURL.Query() - if params.Ea != nil { + if params.Ea != nil { - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "ea", runtime.ParamLocationQuery, *params.Ea); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "ea", runtime.ParamLocationQuery, *params.Ea); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } } } - } - } + } - if params.A != nil { + if params.A != nil { - if queryFrag, err := runtime.StyleParamWithLocation("form", false, "a", runtime.ParamLocationQuery, *params.A); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) + if queryFrag, err := runtime.StyleParamWithLocation("form", false, "a", runtime.ParamLocationQuery, *params.A); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } } } - } - } + } - if params.Eo != nil { + if params.Eo != nil { - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "eo", runtime.ParamLocationQuery, *params.Eo); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "eo", runtime.ParamLocationQuery, *params.Eo); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } } } - } - } + } - if params.O != nil { + if params.O != nil { - if queryFrag, err := runtime.StyleParamWithLocation("form", false, "o", runtime.ParamLocationQuery, *params.O); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) + if queryFrag, err := runtime.StyleParamWithLocation("form", false, "o", runtime.ParamLocationQuery, *params.O); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } } } - } - } + } - if params.Ep != nil { + if params.Ep != nil { - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "ep", runtime.ParamLocationQuery, *params.Ep); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "ep", runtime.ParamLocationQuery, *params.Ep); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } } } - } - } + } - if params.P != nil { + if params.P != nil { - if queryFrag, err := runtime.StyleParamWithLocation("form", false, "p", runtime.ParamLocationQuery, *params.P); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) + if queryFrag, err := runtime.StyleParamWithLocation("form", false, "p", runtime.ParamLocationQuery, *params.P); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } } } - } - } + } - if params.Ps != nil { + if params.Ps != nil { - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "ps", runtime.ParamLocationQuery, *params.Ps); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "ps", runtime.ParamLocationQuery, *params.Ps); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } } } + } - } + if params.Co != nil { - if params.Co != nil { + if queryParamBuf, err := json.Marshal(*params.Co); err != nil { + return nil, err + } else { + queryValues.Add("co", string(queryParamBuf)) + } - if queryParamBuf, err := json.Marshal(*params.Co); err != nil { - return nil, err - } else { - queryValues.Add("co", string(queryParamBuf)) } - } + if params.N1s != nil { - if params.N1s != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "1s", runtime.ParamLocationQuery, *params.N1s); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "1s", runtime.ParamLocationQuery, *params.N1s); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } } } + } + queryURL.RawQuery = queryValues.Encode() } - queryURL.RawQuery = queryValues.Encode() - req, err := http.NewRequest("GET", queryURL.String(), nil) if err != nil { return nil, err diff --git a/internal/test/schemas/schemas.gen.go b/internal/test/schemas/schemas.gen.go index 4e2099840e..f701c28986 100644 --- a/internal/test/schemas/schemas.gen.go +++ b/internal/test/schemas/schemas.gen.go @@ -603,21 +603,23 @@ func NewIssue9RequestWithBody(server string, params *Issue9Params, contentType s return nil, err } - queryValues := queryURL.Query() + if params != nil { + queryValues := queryURL.Query() - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "foo", runtime.ParamLocationQuery, params.Foo); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "foo", runtime.ParamLocationQuery, params.Foo); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } } } - } - queryURL.RawQuery = queryValues.Encode() + queryURL.RawQuery = queryValues.Encode() + } req, err := http.NewRequest("GET", queryURL.String(), body) if err != nil { diff --git a/internal/test/strict-server/gin/server.gen.go b/internal/test/strict-server/gin/server.gen.go index dcac4155de..dd9839c23b 100644 --- a/internal/test/strict-server/gin/server.gen.go +++ b/internal/test/strict-server/gin/server.gen.go @@ -221,7 +221,7 @@ func (siw *ServerInterfaceWrapper) HeadersExample(c *gin.Context) { params.Header1 = Header1 } else { - siw.ErrorHandler(c, fmt.Errorf("Header parameter header1 is required, but not found: %s", err), http.StatusBadRequest) + siw.ErrorHandler(c, fmt.Errorf("Header parameter header1 is required, but not found"), http.StatusBadRequest) return } From d8fc4927900226da86eb2d87c37794794668be19 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jun 2023 09:29:27 -0700 Subject: [PATCH 78/82] Bump golang.org/x/tools from 0.9.1 to 0.9.2 (#1076) Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.9.1 to 0.9.2. - [Release notes](https://github.com/golang/tools/releases) - [Commits](https://github.com/golang/tools/compare/v0.9.1...v0.9.2) --- updated-dependencies: - dependency-name: golang.org/x/tools dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 7de2a16f53..acd41de250 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/matryer/moq v0.3.1 github.com/stretchr/testify v1.8.3 golang.org/x/text v0.9.0 - golang.org/x/tools v0.9.1 + golang.org/x/tools v0.9.2 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index 4fb0761406..7d2fc12751 100644 --- a/go.sum +++ b/go.sum @@ -169,8 +169,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= -golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= +golang.org/x/tools v0.9.2 h1:UXbndbirwCAx6TULftIfie/ygDNCwxEie+IiNP1IcNc= +golang.org/x/tools v0.9.2/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 228a383ebb79b73cc5fc8cdea1079e14f3e6ed86 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jun 2023 20:33:24 +0000 Subject: [PATCH 79/82] Bump github.com/gin-gonic/gin from 1.9.0 to 1.9.1 Bumps [github.com/gin-gonic/gin](https://github.com/gin-gonic/gin) from 1.9.0 to 1.9.1. - [Release notes](https://github.com/gin-gonic/gin/releases) - [Changelog](https://github.com/gin-gonic/gin/blob/master/CHANGELOG.md) - [Commits](https://github.com/gin-gonic/gin/compare/v1.9.0...v1.9.1) --- updated-dependencies: - dependency-name: github.com/gin-gonic/gin dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- go.mod | 25 +++++++++++++------------ go.sum | 56 +++++++++++++++++++++++++++++++------------------------- 2 files changed, 44 insertions(+), 37 deletions(-) diff --git a/go.mod b/go.mod index acd41de250..705e680304 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/deepmap/oapi-codegen require ( github.com/apapsch/go-jsonmerge/v2 v2.0.0 github.com/getkin/kin-openapi v0.117.0 - github.com/gin-gonic/gin v1.9.0 + github.com/gin-gonic/gin v1.9.1 github.com/go-chi/chi/v5 v5.0.8 github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219 github.com/google/uuid v1.3.0 @@ -18,24 +18,25 @@ require ( ) require ( - github.com/bytedance/sonic v1.8.0 // indirect + github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/swag v0.21.1 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.11.2 // indirect - github.com/goccy/go-json v0.10.0 // indirect + github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/invopop/yaml v0.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/cpuid/v2 v2.0.9 // indirect + github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/labstack/gommon v0.4.0 // indirect - github.com/leodido/go-urn v1.2.1 // indirect + github.com/leodido/go-urn v1.2.4 // indirect github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect github.com/lestrrat-go/blackmagic v1.0.0 // indirect github.com/lestrrat-go/httpcc v1.0.1 // indirect @@ -43,27 +44,27 @@ require ( github.com/lestrrat-go/option v1.0.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/pelletier/go-toml/v2 v2.0.6 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/perimeterx/marshmallow v1.1.4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/objx v0.5.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ugorji/go/codec v1.2.9 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect - golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect - golang.org/x/crypto v0.6.0 // indirect + golang.org/x/arch v0.3.0 // indirect + golang.org/x/crypto v0.9.0 // indirect golang.org/x/mod v0.10.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect - google.golang.org/protobuf v1.28.1 // indirect + google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 7d2fc12751..080bf51bb3 100644 --- a/go.sum +++ b/go.sum @@ -3,8 +3,8 @@ github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7D github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA= -github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= +github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= @@ -16,12 +16,14 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/getkin/kin-openapi v0.117.0 h1:QT2DyGujAL09F4NrKDHJGsUoIprlIcFVHWDVDcUFE8A= github.com/getkin/kin-openapi v0.117.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8= -github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0= github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= @@ -34,13 +36,13 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= -github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= +github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= +github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= -github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= 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/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= @@ -60,10 +62,10 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= -github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= +github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -72,8 +74,8 @@ github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k= github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= -github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= -github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A= github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= github.com/lestrrat-go/blackmagic v1.0.0 h1:XzdxDbuQTz0RZZEmdU7cnQxUtFUzgCSPq8RCz4BxIi4= @@ -98,8 +100,8 @@ github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxec github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -107,16 +109,16 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= -github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/perimeterx/marshmallow v1.1.4 h1:pZLDH9RjlLGGorbXhcaQLhfuV0pFMNfPO55FuFkxqLw= github.com/perimeterx/marshmallow v1.1.4/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -129,24 +131,26 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= -github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU= -github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -159,7 +163,9 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -175,12 +181,12 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= From 5dfa9e6189c3dba122393abf5de4f452c92a67f4 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Fri, 2 Jun 2023 15:24:41 +0100 Subject: [PATCH 80/82] Introduce content type into generated JSON types (#1078) * Introduce content type into generated JSON types As noted in #1051, we have cases where multiple uses of JSON types leads to a clash in generated type names. This is a slight breaking change for folks' generated code, but ensures that conflicts do not happen, and that we are more predictable with generated type names. Closes #1051. * Add gorilla/mux to the README --- README.md | 8 +- internal/test/schemas/schemas.gen.go | 169 +++++++++++++++++++++++---- internal/test/schemas/schemas.yaml | 15 ++- pkg/codegen/operations.go | 10 +- 4 files changed, 170 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 467ce1f187..f7013be870 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,10 @@ you can focus on implementing the business logic for your service. We have chosen to focus on [Echo](https://github.com/labstack/echo) as our default HTTP routing engine, due to its speed and simplicity for the generated -stubs, and [Chi](https://github.com/go-chi/chi), and [Gin](https://github.com/gin-gonic/gin) -have also been added by contributors as additional routers. We chose Echo because -the `Context` object is a mockable interface, and it allows for some advanced -testing. +stubs, and [Chi](https://github.com/go-chi/chi), [Gin](https://github.com/gin-gonic/gin), +and [gorilla/mux](https://github.com/gorilla/mux) have also been added by +contributors as additional routers. We chose Echo because the `Context` object +is a mockable interface, and it allows for some advanced testing. This package tries to be too simple rather than too generic, so we've made some design decisions in favor of simplicity, knowing that we can't generate strongly diff --git a/internal/test/schemas/schemas.gen.go b/internal/test/schemas/schemas.gen.go index f701c28986..91f73389c6 100644 --- a/internal/test/schemas/schemas.gen.go +++ b/internal/test/schemas/schemas.gen.go @@ -189,6 +189,9 @@ type ClientInterface interface { // EnsureEverythingIsReferenced request EnsureEverythingIsReferenced(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + // Issue1051 request + Issue1051(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + // Issue127 request Issue127(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -230,6 +233,18 @@ func (c *Client) EnsureEverythingIsReferenced(ctx context.Context, reqEditors .. return c.Client.Do(req) } +func (c *Client) Issue1051(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewIssue1051Request(c.Server) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + func (c *Client) Issue127(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { req, err := NewIssue127Request(c.Server) if err != nil { @@ -377,6 +392,33 @@ func NewEnsureEverythingIsReferencedRequest(server string) (*http.Request, error return req, nil } +// NewIssue1051Request generates requests for Issue1051 +func NewIssue1051Request(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/issues/1051") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + // NewIssue127Request generates requests for Issue127 func NewIssue127Request(server string) (*http.Request, error) { var err error @@ -704,6 +746,9 @@ type ClientWithResponsesInterface interface { // EnsureEverythingIsReferenced request EnsureEverythingIsReferencedWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*EnsureEverythingIsReferencedResponse, error) + // Issue1051 request + Issue1051WithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*Issue1051Response, error) + // Issue127 request Issue127WithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*Issue127Response, error) @@ -763,6 +808,29 @@ func (r EnsureEverythingIsReferencedResponse) StatusCode() int { return 0 } +type Issue1051Response struct { + Body []byte + HTTPResponse *http.Response + JSON200 *map[string]interface{} + ApplicationvndSomethingV1JSON200 *map[string]interface{} +} + +// Status returns HTTPResponse.Status +func (r Issue1051Response) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r Issue1051Response) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + type Issue127Response struct { Body []byte HTTPResponse *http.Response @@ -946,6 +1014,15 @@ func (c *ClientWithResponses) EnsureEverythingIsReferencedWithResponse(ctx conte return ParseEnsureEverythingIsReferencedResponse(rsp) } +// Issue1051WithResponse request returning *Issue1051Response +func (c *ClientWithResponses) Issue1051WithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*Issue1051Response, error) { + rsp, err := c.Issue1051(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseIssue1051Response(rsp) +} + // Issue127WithResponse request returning *Issue127Response func (c *ClientWithResponses) Issue127WithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*Issue127Response, error) { rsp, err := c.Issue127(ctx, reqEditors...) @@ -1068,6 +1145,32 @@ func ParseEnsureEverythingIsReferencedResponse(rsp *http.Response) (*EnsureEvery return response, nil } +// ParseIssue1051Response parses an HTTP response from a Issue1051WithResponse call +func ParseIssue1051Response(rsp *http.Response) (*Issue1051Response, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &Issue1051Response{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest map[string]interface{} + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.ApplicationvndSomethingV1JSON200 = &dest + + } + + return response, nil +} + // ParseIssue127Response parses an HTTP response from a Issue127WithResponse call func ParseIssue127Response(rsp *http.Response) (*Issue127Response, error) { bodyBytes, err := io.ReadAll(rsp.Body) @@ -1259,6 +1362,9 @@ type ServerInterface interface { // (GET /ensure-everything-is-referenced) EnsureEverythingIsReferenced(ctx echo.Context) error + // (GET /issues/1051) + Issue1051(ctx echo.Context) error + // (GET /issues/127) Issue127(ctx echo.Context) error @@ -1300,6 +1406,17 @@ func (w *ServerInterfaceWrapper) EnsureEverythingIsReferenced(ctx echo.Context) return err } +// Issue1051 converts echo context to params. +func (w *ServerInterfaceWrapper) Issue1051(ctx echo.Context) error { + var err error + + ctx.Set(Access_tokenScopes, []string{}) + + // Invoke the callback with all the unmarshalled arguments + err = w.Handler.Issue1051(ctx) + return err +} + // Issue127 converts echo context to params. func (w *ServerInterfaceWrapper) Issue127(ctx echo.Context) error { var err error @@ -1447,6 +1564,7 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL } router.GET(baseURL+"/ensure-everything-is-referenced", wrapper.EnsureEverythingIsReferenced) + router.GET(baseURL+"/issues/1051", wrapper.Issue1051) router.GET(baseURL+"/issues/127", wrapper.Issue127) router.GET(baseURL+"/issues/185", wrapper.Issue185) router.GET(baseURL+"/issues/209/$:str", wrapper.Issue209) @@ -1461,31 +1579,32 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", + "VhcdujoNJECWimwgFCn8PwEAAP//WUiKvIcUAAA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/schemas/schemas.yaml b/internal/test/schemas/schemas.yaml index c93e1f43ff..2e094de126 100644 --- a/internal/test/schemas/schemas.yaml +++ b/internal/test/schemas/schemas.yaml @@ -133,7 +133,20 @@ paths: application/json: schema: $ref: "#/components/schemas/DeprecatedProperty" - + /issues/1051: + get: + operationId: Issue1051 + description: | + Multiple media types contain JSON + responses: + '200': + content: + application/vnd.something.v1+json: + schema: + type: object + application/json: + schema: + type: object components: schemas: GenericObject: diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index ab09547d5a..c3d88e1ae2 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -293,12 +293,18 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]ResponseTypeDefini var typeName string switch { + // HAL+JSON: case StringInArray(contentTypeName, contentTypesHalJSON): typeName = fmt.Sprintf("HALJSON%s", ToCamelCase(responseName)) - // JSON: - case StringInArray(contentTypeName, contentTypesJSON) || util.IsMediaTypeJson(contentTypeName): + case "application/json" == contentTypeName: + // if it's the standard application/json typeName = fmt.Sprintf("JSON%s", ToCamelCase(responseName)) + // Vendored JSON + case StringInArray(contentTypeName, contentTypesJSON) || util.IsMediaTypeJson(contentTypeName): + baseTypeName := fmt.Sprintf("%s%s", ToCamelCase(contentTypeName), ToCamelCase(responseName)) + + typeName = strings.ReplaceAll(baseTypeName, "Json", "JSON") // YAML: case StringInArray(contentTypeName, contentTypesYAML): typeName = fmt.Sprintf("YAML%s", ToCamelCase(responseName)) From 22f5b9adc5c99af44f9b0f6e3c54b65eea11de98 Mon Sep 17 00:00:00 2001 From: Oleksandr Redko Date: Fri, 2 Jun 2023 19:03:46 +0300 Subject: [PATCH 81/82] Refactor to use `strings.ReplaceAll` (#1079) --- pkg/codegen/codegen.go | 2 +- pkg/codegen/utils.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 1cf431ed9c..d8ba40fca8 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -820,7 +820,7 @@ func GenerateUnionAndAdditionalProopertiesBoilerplate(t *template.Template, type func SanitizeCode(goCode string) string { // remove any byte-order-marks which break Go-Code // See: https://groups.google.com/forum/#!topic/golang-nuts/OToNIPdfkks - return strings.Replace(goCode, "\uFEFF", "", -1) + return strings.ReplaceAll(goCode, "\uFEFF", "") } // GetUserTemplateText attempts to retrieve the template text from a passed in URL or file diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index 6fb031e49c..cf8826e39f 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -728,8 +728,8 @@ func stringToGoCommentWithPrefix(in, prefix string) string { } // Normalize newlines from Windows/Mac to Linux - in = strings.Replace(in, "\r\n", "\n", -1) - in = strings.Replace(in, "\r", "\n", -1) + in = strings.ReplaceAll(in, "\r\n", "\n") + in = strings.ReplaceAll(in, "\r", "\n") // Add comment to each line var lines []string From 7aa85bb88223ee606c2aaeb3e536aa0ed93d4054 Mon Sep 17 00:00:00 2001 From: Jleagle Date: Fri, 2 Jun 2023 18:12:15 +0100 Subject: [PATCH 82/82] Feat: Add Fiber server support (#813) * Revert generated * Add to cmd * Add to codegen * Fiber * Fix imports * Templates * Split types and code * Rename aliases * Strict * tests * Validate middleware * Templates * Update petstore * Generate * Generate * Readme * Fix tests * Fix build * tweaks to get it running * fixed linter errors, even though other servers seem to just ignore these * Fix option yaml * Fix tests * Mod tidy * Remove extra space * Check errors * Update pkg/fiber-middleware/oapi_validate_test.go Co-authored-by: leonklingele * Update pkg/fiber-middleware/oapi_validate_test.go Co-authored-by: leonklingele * Update pkg/fiber-middleware/oapi_validate_test.go Co-authored-by: leonklingele * Update pkg/fiber-middleware/oapi_validate_test.go Co-authored-by: leonklingele * Update pkg/fiber-middleware/oapi_validate_test.go Co-authored-by: leonklingele * Separate oapi-codegen imports * Use t.Helper() * fixing comments * Sort imports * Use WriteString * Fix imports * Mods * Generate * Add missing config * Use new adaptor * Use new adaptor * Fix compilation and test issues - Update modules - Add missing test handler - Fix variable naming in strict server wrappers --------- Co-authored-by: Carl Bring <111354161+gnirb@users.noreply.github.com> Co-authored-by: leonklingele Co-authored-by: marcinromaszewicz --- README.md | 11 +- cmd/oapi-codegen/oapi-codegen.go | 6 +- .../fiber/api/petstore-server.gen.go | 246 ++++ .../fiber/api/petstore-types.gen.go | 46 + .../petstore-expanded/fiber/api/petstore.go | 132 ++ .../fiber/api/server.cfg.yaml | 5 + .../fiber/api/types.cfg.yaml | 4 + examples/petstore-expanded/fiber/petstore.go | 57 + .../petstore-expanded/fiber/petstore_test.go | 181 +++ go.mod | 11 + go.sum | 63 + .../issue.gen.go | 28 - .../issue.gen.go | 19 - .../test/strict-server/fiber/server.cfg.yaml | 6 + .../test/strict-server/fiber/server.gen.go | 1105 +++++++++++++++++ internal/test/strict-server/fiber/server.go | 106 ++ .../test/strict-server/fiber/types.cfg.yaml | 4 + .../test/strict-server/fiber/types.gen.go | 54 + internal/test/strict-server/strict_test.go | 61 +- pkg/codegen/codegen.go | 15 + pkg/codegen/configuration.go | 4 + pkg/codegen/operations.go | 20 +- pkg/codegen/template_helpers.go | 1 + .../templates/fiber/fiber-handler.tmpl | 25 + .../templates/fiber/fiber-interface.tmpl | 7 + .../templates/fiber/fiber-middleware.tmpl | 169 +++ pkg/codegen/templates/imports.tmpl | 1 + .../strict/strict-fiber-interface.tmpl | 137 ++ .../templates/strict/strict-fiber.tmpl | 80 ++ pkg/codegen/utils_test.go | 17 + pkg/fiber-middleware/oapi_validate.go | 196 +++ pkg/fiber-middleware/oapi_validate_test.go | 434 +++++++ pkg/fiber-middleware/test_spec.yaml | 103 ++ 33 files changed, 3272 insertions(+), 82 deletions(-) create mode 100644 examples/petstore-expanded/fiber/api/petstore-server.gen.go create mode 100644 examples/petstore-expanded/fiber/api/petstore-types.gen.go create mode 100644 examples/petstore-expanded/fiber/api/petstore.go create mode 100644 examples/petstore-expanded/fiber/api/server.cfg.yaml create mode 100644 examples/petstore-expanded/fiber/api/types.cfg.yaml create mode 100644 examples/petstore-expanded/fiber/petstore.go create mode 100644 examples/petstore-expanded/fiber/petstore_test.go create mode 100644 internal/test/strict-server/fiber/server.cfg.yaml create mode 100644 internal/test/strict-server/fiber/server.gen.go create mode 100644 internal/test/strict-server/fiber/server.go create mode 100644 internal/test/strict-server/fiber/types.cfg.yaml create mode 100644 internal/test/strict-server/fiber/types.gen.go create mode 100644 pkg/codegen/templates/fiber/fiber-handler.tmpl create mode 100644 pkg/codegen/templates/fiber/fiber-interface.tmpl create mode 100644 pkg/codegen/templates/fiber/fiber-middleware.tmpl create mode 100644 pkg/codegen/templates/strict/strict-fiber-interface.tmpl create mode 100644 pkg/codegen/templates/strict/strict-fiber.tmpl create mode 100644 pkg/fiber-middleware/oapi_validate.go create mode 100644 pkg/fiber-middleware/oapi_validate_test.go create mode 100644 pkg/fiber-middleware/test_spec.yaml diff --git a/README.md b/README.md index f7013be870..572c8b3458 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,11 @@ you can focus on implementing the business logic for your service. We have chosen to focus on [Echo](https://github.com/labstack/echo) as our default HTTP routing engine, due to its speed and simplicity for the generated -stubs, and [Chi](https://github.com/go-chi/chi), [Gin](https://github.com/gin-gonic/gin), -and [gorilla/mux](https://github.com/gorilla/mux) have also been added by -contributors as additional routers. We chose Echo because the `Context` object -is a mockable interface, and it allows for some advanced testing. +stubs. [Chi](https://github.com/go-chi/chi), [Gin](https://github.com/gin-gonic/gin), +[gorilla/mux](https://github.com/gorilla/mux), and [Fiber](https://github.com/gofiber/fiber) +have also been added by contributors as additional routers. We chose Echo because +the `Context` object is a mockable interface, and it allows for some advanced +testing. This package tries to be too simple rather than too generic, so we've made some design decisions in favor of simplicity, knowing that we can't generate strongly @@ -700,6 +701,8 @@ you can specify any combination of those. same package to compile. - `chi-server`: generate the Chi server boilerplate. This code is dependent on that produced by the `types` target. +- `fiber`: generate the Fiber server boilerplate. This code is dependent + on that produced by the `types` target. - `client`: generate the client boilerplate. It, too, requires the types to be present in its package. - `spec`: embed the OpenAPI spec into the generated code as a gzipped blob. diff --git a/cmd/oapi-codegen/oapi-codegen.go b/cmd/oapi-codegen/oapi-codegen.go index 09990d61c9..ae81acfca9 100644 --- a/cmd/oapi-codegen/oapi-codegen.go +++ b/cmd/oapi-codegen/oapi-codegen.go @@ -91,7 +91,7 @@ func main() { // All flags below are deprecated, and will be removed in a future release. Please do not // update their behavior. flag.StringVar(&flagGenerate, "generate", "types,client,server,spec", - `Comma-separated list of code to generate; valid options: "types", "client", "chi-server", "server", "gin", "gorilla", "spec", "skip-fmt", "skip-prune".`) + `Comma-separated list of code to generate; valid options: "types", "client", "chi-server", "server", "gin", "gorilla", "spec", "skip-fmt", "skip-prune", "fiber".`) flag.StringVar(&flagIncludeTags, "include-tags", "", "Only include operations with the given tags. Comma-separated list of tags.") flag.StringVar(&flagExcludeTags, "exclude-tags", "", "Exclude operations that are tagged with the given tags. Comma-separated list of tags.") flag.StringVar(&flagTemplatesDir, "templates", "", "Path to directory containing user templates.") @@ -293,7 +293,7 @@ func loadTemplateOverrides(templatesDir string) (map[string]string, error) { for _, f := range files { // Recursively load subdirectory files, using the path relative to the templates // directory as the key. This allows for overriding the files in the service-specific - // directories (e.g. echo, chi, etc.). + // directories (e.g. echo, chi, fiber, etc.). if f.IsDir() { subFiles, err := loadTemplateOverrides(path.Join(templatesDir, f.Name())) if err != nil { @@ -445,6 +445,8 @@ func generationTargets(cfg *codegen.Configuration, targets []string) error { switch opt { case "chi-server", "chi": opts.ChiServer = true + case "fiber-server", "fiber": + opts.FiberServer = true case "server", "echo-server", "echo": opts.EchoServer = true case "gin", "gin-server": diff --git a/examples/petstore-expanded/fiber/api/petstore-server.gen.go b/examples/petstore-expanded/fiber/api/petstore-server.gen.go new file mode 100644 index 0000000000..a55486c1da --- /dev/null +++ b/examples/petstore-expanded/fiber/api/petstore-server.gen.go @@ -0,0 +1,246 @@ +// Package api provides primitives to interact with the openapi HTTP API. +// +// Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT. +package api + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "fmt" + "net/url" + "path" + "strings" + + "github.com/deepmap/oapi-codegen/pkg/runtime" + "github.com/getkin/kin-openapi/openapi3" + "github.com/gofiber/fiber/v2" +) + +// ServerInterface represents all server handlers. +type ServerInterface interface { + // Returns all pets + // (GET /pets) + FindPets(c *fiber.Ctx, params FindPetsParams) error + // Creates a new pet + // (POST /pets) + AddPet(c *fiber.Ctx) error + // Deletes a pet by ID + // (DELETE /pets/{id}) + DeletePet(c *fiber.Ctx, id int64) error + // Returns a pet by ID + // (GET /pets/{id}) + FindPetByID(c *fiber.Ctx, id int64) error +} + +// ServerInterfaceWrapper converts contexts to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface +} + +type MiddlewareFunc fiber.Handler + +// FindPets operation middleware +func (siw *ServerInterfaceWrapper) FindPets(c *fiber.Ctx) error { + + var err error + + // Parameter object where we will unmarshal all parameters from the context + var params FindPetsParams + + var query url.Values + query, err = url.ParseQuery(string(c.Request().URI().QueryString())) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for query string: %w", err).Error()) + } + + // ------------- Optional query parameter "tags" ------------- + + err = runtime.BindQueryParameter("form", true, false, "tags", query, ¶ms.Tags) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter tags: %w", err).Error()) + } + + // ------------- Optional query parameter "limit" ------------- + + err = runtime.BindQueryParameter("form", true, false, "limit", query, ¶ms.Limit) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter limit: %w", err).Error()) + } + + return siw.Handler.FindPets(c, params) +} + +// AddPet operation middleware +func (siw *ServerInterfaceWrapper) AddPet(c *fiber.Ctx) error { + + return siw.Handler.AddPet(c) +} + +// DeletePet operation middleware +func (siw *ServerInterfaceWrapper) DeletePet(c *fiber.Ctx) error { + + var err error + + // ------------- Path parameter "id" ------------- + var id int64 + + err = runtime.BindStyledParameter("simple", false, "id", c.Params("id"), &id) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter id: %w", err).Error()) + } + + return siw.Handler.DeletePet(c, id) +} + +// FindPetByID operation middleware +func (siw *ServerInterfaceWrapper) FindPetByID(c *fiber.Ctx) error { + + var err error + + // ------------- Path parameter "id" ------------- + var id int64 + + err = runtime.BindStyledParameter("simple", false, "id", c.Params("id"), &id) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter id: %w", err).Error()) + } + + return siw.Handler.FindPetByID(c, id) +} + +// FiberServerOptions provides options for the Fiber server. +type FiberServerOptions struct { + BaseURL string + Middlewares []MiddlewareFunc +} + +// RegisterHandlers creates http.Handler with routing matching OpenAPI spec. +func RegisterHandlers(router fiber.Router, si ServerInterface) { + RegisterHandlersWithOptions(router, si, FiberServerOptions{}) +} + +// RegisterHandlersWithOptions creates http.Handler with additional options +func RegisterHandlersWithOptions(router fiber.Router, si ServerInterface, options FiberServerOptions) { + wrapper := ServerInterfaceWrapper{ + Handler: si, + } + + for _, m := range options.Middlewares { + router.Use(m) + } + + router.Get(options.BaseURL+"/pets", wrapper.FindPets) + + router.Post(options.BaseURL+"/pets", wrapper.AddPet) + + router.Delete(options.BaseURL+"/pets/:id", wrapper.DeletePet) + + router.Get(options.BaseURL+"/pets/:id", wrapper.FindPetByID) + +} + +// Base64 encoded, gzipped, json marshaled Swagger object +var swaggerSpec = []string{ + + "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", + "97cAAAD//ykDnxlaEgAA", +} + +// GetSwagger returns the content of the embedded swagger specification file +// or error if failed to decode +func decodeSpec() ([]byte, error) { + zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, "")) + if err != nil { + return nil, fmt.Errorf("error base64 decoding spec: %s", err) + } + zr, err := gzip.NewReader(bytes.NewReader(zipped)) + if err != nil { + return nil, fmt.Errorf("error decompressing spec: %s", err) + } + var buf bytes.Buffer + _, err = buf.ReadFrom(zr) + if err != nil { + return nil, fmt.Errorf("error decompressing spec: %s", err) + } + + return buf.Bytes(), nil +} + +var rawSpec = decodeSpecCached() + +// a naive cached of a decoded swagger spec +func decodeSpecCached() func() ([]byte, error) { + data, err := decodeSpec() + return func() ([]byte, error) { + return data, err + } +} + +// Constructs a synthetic filesystem for resolving external references when loading openapi specifications. +func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) { + var res = make(map[string]func() ([]byte, error)) + if len(pathToFile) > 0 { + res[pathToFile] = rawSpec + } + + return res +} + +// GetSwagger returns the Swagger specification corresponding to the generated code +// in this file. The external references of Swagger specification are resolved. +// The logic of resolving external references is tightly connected to "import-mapping" feature. +// Externally referenced files must be embedded in the corresponding golang packages. +// Urls can be supported but this task was out of the scope. +func GetSwagger() (swagger *openapi3.T, err error) { + var resolvePath = PathToRawSpec("") + + loader := openapi3.NewLoader() + loader.IsExternalRefsAllowed = true + loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) { + var pathToFile = url.String() + pathToFile = path.Clean(pathToFile) + getSpec, ok := resolvePath[pathToFile] + if !ok { + err1 := fmt.Errorf("path not found: %s", pathToFile) + return nil, err1 + } + return getSpec() + } + var specData []byte + specData, err = rawSpec() + if err != nil { + return + } + swagger, err = loader.LoadFromData(specData) + if err != nil { + return + } + return +} diff --git a/examples/petstore-expanded/fiber/api/petstore-types.gen.go b/examples/petstore-expanded/fiber/api/petstore-types.gen.go new file mode 100644 index 0000000000..16bbe200cf --- /dev/null +++ b/examples/petstore-expanded/fiber/api/petstore-types.gen.go @@ -0,0 +1,46 @@ +// Package api provides primitives to interact with the openapi HTTP API. +// +// Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT. +package api + +// Error defines model for Error. +type Error struct { + // Code Error code + Code int32 `json:"code"` + + // Message Error message + Message string `json:"message"` +} + +// NewPet defines model for NewPet. +type NewPet struct { + // Name Name of the pet + Name string `json:"name"` + + // Tag Type of the pet + Tag *string `json:"tag,omitempty"` +} + +// Pet defines model for Pet. +type Pet struct { + // Id Unique id of the pet + Id int64 `json:"id"` + + // Name Name of the pet + Name string `json:"name"` + + // Tag Type of the pet + Tag *string `json:"tag,omitempty"` +} + +// FindPetsParams defines parameters for FindPets. +type FindPetsParams struct { + // Tags tags to filter by + Tags *[]string `form:"tags,omitempty" json:"tags,omitempty"` + + // Limit maximum number of results to return + Limit *int32 `form:"limit,omitempty" json:"limit,omitempty"` +} + +// AddPetJSONRequestBody defines body for AddPet for application/json ContentType. +type AddPetJSONRequestBody = NewPet diff --git a/examples/petstore-expanded/fiber/api/petstore.go b/examples/petstore-expanded/fiber/api/petstore.go new file mode 100644 index 0000000000..60ecd58ff0 --- /dev/null +++ b/examples/petstore-expanded/fiber/api/petstore.go @@ -0,0 +1,132 @@ +//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=types.cfg.yaml ../../petstore-expanded.yaml +//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=server.cfg.yaml ../../petstore-expanded.yaml + +package api + +import ( + "fmt" + "net/http" + "sync" + + "github.com/gofiber/fiber/v2" +) + +type PetStore struct { + Pets map[int64]Pet + NextId int64 + Lock sync.Mutex +} + +// Make sure we conform to ServerInterface + +var _ ServerInterface = (*PetStore)(nil) + +func NewPetStore() *PetStore { + + return &PetStore{ + Pets: make(map[int64]Pet), + NextId: 1000, + } +} + +// This function wraps sending of an error in the Error format, and +// handling the failure to marshal that. +func sendPetStoreError(c *fiber.Ctx, code int, message string) error { + + petErr := Error{ + Code: int32(code), + Message: message, + } + + return c.Status(code).JSON(petErr) +} + +// FindPets implements all the handlers in the ServerInterface +func (p *PetStore) FindPets(c *fiber.Ctx, params FindPetsParams) error { + + p.Lock.Lock() + defer p.Lock.Unlock() + + var result []Pet + + for _, pet := range p.Pets { + if params.Tags != nil { + // If we have tags, filter pets by tag + for _, t := range *params.Tags { + if pet.Tag != nil && (*pet.Tag == t) { + result = append(result, pet) + } + } + } else { + // Add all pets if we're not filtering + result = append(result, pet) + } + + if params.Limit != nil { + l := int(*params.Limit) + if len(result) >= l { + // We're at the limit + break + } + } + } + + return c.Status(http.StatusOK).JSON(result) +} + +func (p *PetStore) AddPet(c *fiber.Ctx) error { + + // We expect a NewPet object in the request body. + var newPet NewPet + + if err := c.BodyParser(&newPet); err != nil { + return sendPetStoreError(c, http.StatusBadRequest, "Invalid format for NewPet") + } + + // We now have a pet, let's add it to our "database". + + // We're always asynchronous, so lock unsafe operations below + p.Lock.Lock() + defer p.Lock.Unlock() + + // We handle pets, not NewPets, which have an additional ID field + var pet Pet + pet.Name = newPet.Name + pet.Tag = newPet.Tag + pet.Id = p.NextId + p.NextId = p.NextId + 1 + + // Insert into map + p.Pets[pet.Id] = pet + + // Now, we have to return the NewPet + return c.Status(http.StatusCreated).JSON(pet) +} + +func (p *PetStore) FindPetByID(c *fiber.Ctx, id int64) error { + + p.Lock.Lock() + defer p.Lock.Unlock() + + pet, found := p.Pets[id] + if !found { + return sendPetStoreError(c, http.StatusNotFound, fmt.Sprintf("Could not find pet with ID %d", id)) + } + + return c.Status(http.StatusOK).JSON(pet) +} + +func (p *PetStore) DeletePet(c *fiber.Ctx, id int64) error { + + p.Lock.Lock() + defer p.Lock.Unlock() + + _, found := p.Pets[id] + if !found { + return sendPetStoreError(c, http.StatusNotFound, fmt.Sprintf("Could not find pet with ID %d", id)) + } + delete(p.Pets, id) + + c.Status(http.StatusNoContent) + return nil +} diff --git a/examples/petstore-expanded/fiber/api/server.cfg.yaml b/examples/petstore-expanded/fiber/api/server.cfg.yaml new file mode 100644 index 0000000000..91ef1331d2 --- /dev/null +++ b/examples/petstore-expanded/fiber/api/server.cfg.yaml @@ -0,0 +1,5 @@ +package: api +generate: + fiber-server: true + embedded-spec: true +output: petstore-server.gen.go diff --git a/examples/petstore-expanded/fiber/api/types.cfg.yaml b/examples/petstore-expanded/fiber/api/types.cfg.yaml new file mode 100644 index 0000000000..9ac30e11e9 --- /dev/null +++ b/examples/petstore-expanded/fiber/api/types.cfg.yaml @@ -0,0 +1,4 @@ +package: api +generate: + models: true +output: petstore-types.gen.go diff --git a/examples/petstore-expanded/fiber/petstore.go b/examples/petstore-expanded/fiber/petstore.go new file mode 100644 index 0000000000..344752bbbc --- /dev/null +++ b/examples/petstore-expanded/fiber/petstore.go @@ -0,0 +1,57 @@ +// This is an example of implementing the Pet Store from the OpenAPI documentation +// found at: +// https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml + +package main + +import ( + "flag" + "fmt" + "log" + "os" + + "github.com/gofiber/fiber/v2" + + "github.com/deepmap/oapi-codegen/examples/petstore-expanded/fiber/api" + middleware "github.com/deepmap/oapi-codegen/pkg/fiber-middleware" +) + +func main() { + + var port = flag.Int("port", 8080, "Port for test HTTP server") + + flag.Parse() + + // Create an instance of our handler which satisfies the generated interface + petStore := api.NewPetStore() + + s := NewFiberPetServer(petStore) + + // And we serve HTTP until the world ends. + log.Fatal(s.Listen(fmt.Sprintf("localhost:%d", *port))) +} + +func NewFiberPetServer(petStore *api.PetStore) *fiber.App { + + swagger, err := api.GetSwagger() + if err != nil { + fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err) + os.Exit(1) + } + + // Clear out the servers array in the swagger spec, that skips validating + // that server names match. We don't know how this thing will be run. + swagger.Servers = nil + + // This is how you set up a basic fiber router + app := fiber.New() + + // Use our validation middleware to check all requests against the + // OpenAPI schema. + app.Use(middleware.OapiRequestValidator(swagger)) + + // We now register our petStore above as the handler for the interface + api.RegisterHandlers(app, petStore) + + return app +} diff --git a/examples/petstore-expanded/fiber/petstore_test.go b/examples/petstore-expanded/fiber/petstore_test.go new file mode 100644 index 0000000000..e6a103ace9 --- /dev/null +++ b/examples/petstore-expanded/fiber/petstore_test.go @@ -0,0 +1,181 @@ +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "net/url" + "testing" + + "github.com/gofiber/fiber/v2" + "github.com/stretchr/testify/assert" + + "github.com/deepmap/oapi-codegen/examples/petstore-expanded/fiber/api" +) + +func doGet(t *testing.T, app *fiber.App, rawURL string) (*http.Response, error) { + + u, err := url.Parse(rawURL) + if err != nil { + t.Fatalf("Invalid url: %s", rawURL) + } + + req := httptest.NewRequest("GET", u.RequestURI(), nil) + req.Header.Add("Accept", "application/json") + req.Host = u.Host + + return app.Test(req) +} + +func doPost(t *testing.T, app *fiber.App, rawURL string, jsonBody interface{}) (*http.Response, error) { + u, err := url.Parse(rawURL) + if err != nil { + t.Fatalf("Invalid url: %s", rawURL) + } + + buf, err := json.Marshal(jsonBody) + if err != nil { + return nil, err + } + req := httptest.NewRequest("POST", u.RequestURI(), bytes.NewReader(buf)) + req.Header.Add("Accept", "application/json") + req.Header.Add("Content-Type", "application/json") + req.Host = u.Host + return app.Test(req) +} + +func doDelete(t *testing.T, app *fiber.App, rawURL string) (*http.Response, error) { + u, err := url.Parse(rawURL) + if err != nil { + t.Fatalf("Invalid url: %s", rawURL) + } + + req := httptest.NewRequest("DELETE", u.RequestURI(), nil) + req.Header.Add("Accept", "application/json") + req.Host = u.Host + return app.Test(req) +} + +func TestPetStore(t *testing.T) { + var err error + store := api.NewPetStore() + fiberPetServer := NewFiberPetServer(store) + + t.Run("Add pet", func(t *testing.T) { + tag := "TagOfSpot" + newPet := api.NewPet{ + Name: "Spot", + Tag: &tag, + } + + rr, _ := doPost(t, fiberPetServer, "/pets", newPet) + assert.Equal(t, http.StatusCreated, rr.StatusCode) + + var resultPet api.Pet + err = json.NewDecoder(rr.Body).Decode(&resultPet) + assert.NoError(t, err, "error unmarshaling response") + assert.Equal(t, newPet.Name, resultPet.Name) + assert.Equal(t, *newPet.Tag, *resultPet.Tag) + }) + + t.Run("Find pet by ID", func(t *testing.T) { + pet := api.Pet{ + Id: 100, + } + + store.Pets[pet.Id] = pet + rr, _ := doGet(t, fiberPetServer, fmt.Sprintf("/pets/%d", pet.Id)) + assert.Equal(t, http.StatusOK, rr.StatusCode) + + var resultPet api.Pet + err = json.NewDecoder(rr.Body).Decode(&resultPet) + assert.NoError(t, err, "error getting pet") + assert.Equal(t, pet, resultPet) + }) + + t.Run("Pet not found", func(t *testing.T) { + rr, _ := doGet(t, fiberPetServer, "/pets/27179095781") + assert.Equal(t, http.StatusNotFound, rr.StatusCode) + + var petError api.Error + err = json.NewDecoder(rr.Body).Decode(&petError) + assert.NoError(t, err, "error getting response", err) + assert.Equal(t, int32(http.StatusNotFound), petError.Code) + }) + + t.Run("List all pets", func(t *testing.T) { + store.Pets = map[int64]api.Pet{1: {}, 2: {}} + + // Now, list all pets, we should have two + rr, _ := doGet(t, fiberPetServer, "/pets") + assert.Equal(t, http.StatusOK, rr.StatusCode) + + var petList []api.Pet + err = json.NewDecoder(rr.Body).Decode(&petList) + assert.NoError(t, err, "error getting response", err) + assert.Equal(t, 2, len(petList)) + }) + + t.Run("Filter pets by tag", func(t *testing.T) { + tag := "TagOfFido" + + store.Pets = map[int64]api.Pet{ + 1: { + Tag: &tag, + }, + 2: {}, + } + + // Filter pets by tag, we should have 1 + rr, _ := doGet(t, fiberPetServer, "/pets?tags=TagOfFido") + assert.Equal(t, http.StatusOK, rr.StatusCode) + + var petList []api.Pet + err = json.NewDecoder(rr.Body).Decode(&petList) + assert.NoError(t, err, "error getting response", err) + assert.Equal(t, 1, len(petList)) + }) + + t.Run("Filter pets by tag", func(t *testing.T) { + store.Pets = map[int64]api.Pet{1: {}, 2: {}} + + // Filter pets by non existent tag, we should have 0 + rr, _ := doGet(t, fiberPetServer, "/pets?tags=NotExists") + assert.Equal(t, http.StatusOK, rr.StatusCode) + + var petList []api.Pet + err = json.NewDecoder(rr.Body).Decode(&petList) + assert.NoError(t, err, "error getting response", err) + assert.Equal(t, 0, len(petList)) + }) + + t.Run("Delete pets", func(t *testing.T) { + store.Pets = map[int64]api.Pet{1: {}, 2: {}} + + // Let's delete non-existent pet + rr, _ := doDelete(t, fiberPetServer, "/pets/7") + assert.Equal(t, http.StatusNotFound, rr.StatusCode) + + var petError api.Error + err = json.NewDecoder(rr.Body).Decode(&petError) + assert.NoError(t, err, "error unmarshaling PetError") + assert.Equal(t, int32(http.StatusNotFound), petError.Code) + + // Now, delete both real pets + rr, _ = doDelete(t, fiberPetServer, "/pets/1") + assert.Equal(t, http.StatusNoContent, rr.StatusCode) + + rr, _ = doDelete(t, fiberPetServer, "/pets/2") + assert.Equal(t, http.StatusNoContent, rr.StatusCode) + + // Should have no pets left. + var petList []api.Pet + rr, _ = doGet(t, fiberPetServer, "/pets") + assert.Equal(t, http.StatusOK, rr.StatusCode) + err = json.NewDecoder(rr.Body).Decode(&petList) + assert.NoError(t, err, "error getting response", err) + assert.Equal(t, 0, len(petList)) + }) +} diff --git a/go.mod b/go.mod index 705e680304..aeff31dfb4 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ require ( github.com/getkin/kin-openapi v0.117.0 github.com/gin-gonic/gin v1.9.1 github.com/go-chi/chi/v5 v5.0.8 + github.com/gofiber/fiber/v2 v2.46.0 github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219 github.com/google/uuid v1.3.0 github.com/gorilla/mux v1.8.0 @@ -18,6 +19,7 @@ require ( ) require ( + github.com/andybalholm/brotli v1.0.5 // indirect github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/davecgh/go-spew v1.1.1 // indirect @@ -34,6 +36,7 @@ require ( github.com/invopop/yaml v0.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.16.3 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/labstack/gommon v0.4.0 // indirect github.com/leodido/go-urn v1.2.4 // indirect @@ -45,18 +48,26 @@ require ( github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-runewidth v0.0.14 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/perimeterx/marshmallow v1.1.4 // indirect + github.com/philhofer/fwd v1.1.2 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 // indirect + github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect github.com/stretchr/objx v0.5.0 // indirect + github.com/tinylib/msgp v1.1.8 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.47.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.9.0 // indirect golang.org/x/mod v0.10.0 // indirect diff --git a/go.sum b/go.sum index 080bf51bb3..f11b87036d 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,6 @@ github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= +github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= +github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= @@ -43,6 +45,8 @@ github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncV github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/gofiber/fiber/v2 v2.46.0 h1:wkkWotblsGVlLjXj2dpgKQAYHtXumsK/HyFugQM68Ns= +github.com/gofiber/fiber/v2 v2.46.0/go.mod h1:DNl0/c37WLe0g92U6lx1VMQuxGUQY5V7EIaVoEsUffc= 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/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= @@ -62,6 +66,8 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= +github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY= +github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= @@ -102,6 +108,8 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= +github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -115,10 +123,20 @@ github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZ github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/perimeterx/marshmallow v1.1.4 h1:pZLDH9RjlLGGorbXhcaQLhfuV0pFMNfPO55FuFkxqLw= github.com/perimeterx/marshmallow v1.1.4/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= +github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= +github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= +github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 h1:rmMl4fXJhKMNWl+K+r/fq4FbbKI+Ia2m9hYBLm2h4G4= +github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94/go.mod h1:90zrgN3D/WJsDd1iXHT96alCoN2KJo6/4x1DZC3wZs8= +github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4= +github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk= +github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -134,6 +152,9 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw= +github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0= +github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= @@ -142,42 +163,84 @@ github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4d github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.47.0 h1:y7moDoxYzMooFpT5aHgNgVOQDrS3qlkfiP9mDtGGK9c= +github.com/valyala/fasthttp v1.47.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/tools v0.9.2 h1:UXbndbirwCAx6TULftIfie/ygDNCwxEie+IiNP1IcNc= golang.org/x/tools v0.9.2/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= diff --git a/internal/test/issues/issue-head-digit-of-httpheader/issue.gen.go b/internal/test/issues/issue-head-digit-of-httpheader/issue.gen.go index 703c262af6..6e5994e2bf 100644 --- a/internal/test/issues/issue-head-digit-of-httpheader/issue.gen.go +++ b/internal/test/issues/issue-head-digit-of-httpheader/issue.gen.go @@ -3,37 +3,9 @@ // Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT. package headdigitofhttpheader -import ( - "context" - "fmt" - "net/http" -) - type N200ResponseHeaders struct { N000Foo string } type N200Response struct { Headers N200ResponseHeaders } - -type GetFooRequestObject struct { -} - -type GetFooResponseObject interface { - VisitGetFooResponse(w http.ResponseWriter) error -} - -type GetFoo200Response = N200Response - -func (response GetFoo200Response) VisitGetFooResponse(w http.ResponseWriter) error { - w.Header().Set("000-foo", fmt.Sprint(response.Headers.N000Foo)) - w.WriteHeader(200) - return nil -} - -// StrictServerInterface represents all server handlers. -type StrictServerInterface interface { - - // (GET /foo) - GetFoo(ctx context.Context, request GetFooRequestObject) (GetFooResponseObject, error) -} diff --git a/internal/test/issues/issue-head-digit-of-operation-id/issue.gen.go b/internal/test/issues/issue-head-digit-of-operation-id/issue.gen.go index 17607466a4..4a5d3e86f6 100644 --- a/internal/test/issues/issue-head-digit-of-operation-id/issue.gen.go +++ b/internal/test/issues/issue-head-digit-of-operation-id/issue.gen.go @@ -2,22 +2,3 @@ // // Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT. package head_digit_of_operation_id - -import ( - "context" - "net/http" -) - -type N3GPPFooRequestObject struct { -} - -type N3GPPFooResponseObject interface { - VisitN3GPPFooResponse(w http.ResponseWriter) error -} - -// StrictServerInterface represents all server handlers. -type StrictServerInterface interface { - - // (GET /3gpp/foo) - N3GPPFoo(ctx context.Context, request N3GPPFooRequestObject) (N3GPPFooResponseObject, error) -} diff --git a/internal/test/strict-server/fiber/server.cfg.yaml b/internal/test/strict-server/fiber/server.cfg.yaml new file mode 100644 index 0000000000..3a6471261f --- /dev/null +++ b/internal/test/strict-server/fiber/server.cfg.yaml @@ -0,0 +1,6 @@ +package: api +generate: + fiber-server: true + strict-server: true + embedded-spec: true +output: server.gen.go diff --git a/internal/test/strict-server/fiber/server.gen.go b/internal/test/strict-server/fiber/server.gen.go new file mode 100644 index 0000000000..84671503d0 --- /dev/null +++ b/internal/test/strict-server/fiber/server.gen.go @@ -0,0 +1,1105 @@ +// Package api provides primitives to interact with the openapi HTTP API. +// +// Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT. +package api + +import ( + "bytes" + "compress/gzip" + "context" + "encoding/base64" + "fmt" + "io" + "mime/multipart" + "net/http" + "net/url" + "path" + "strings" + + "github.com/deepmap/oapi-codegen/pkg/runtime" + "github.com/getkin/kin-openapi/openapi3" + "github.com/gofiber/fiber/v2" +) + +// ServerInterface represents all server handlers. +type ServerInterface interface { + + // (POST /json) + JSONExample(c *fiber.Ctx) error + + // (POST /multipart) + MultipartExample(c *fiber.Ctx) error + + // (POST /multiple) + MultipleRequestAndResponseTypes(c *fiber.Ctx) error + + // (GET /reserved-go-keyword-parameters/{type}) + ReservedGoKeywordParameters(c *fiber.Ctx, pType string) error + + // (POST /reusable-responses) + ReusableResponses(c *fiber.Ctx) error + + // (POST /text) + TextExample(c *fiber.Ctx) error + + // (POST /unknown) + UnknownExample(c *fiber.Ctx) error + + // (POST /unspecified-content-type) + UnspecifiedContentType(c *fiber.Ctx) error + + // (POST /urlencoded) + URLEncodedExample(c *fiber.Ctx) error + + // (POST /with-headers) + HeadersExample(c *fiber.Ctx, params HeadersExampleParams) error +} + +// ServerInterfaceWrapper converts contexts to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface +} + +type MiddlewareFunc fiber.Handler + +// JSONExample operation middleware +func (siw *ServerInterfaceWrapper) JSONExample(c *fiber.Ctx) error { + + return siw.Handler.JSONExample(c) +} + +// MultipartExample operation middleware +func (siw *ServerInterfaceWrapper) MultipartExample(c *fiber.Ctx) error { + + return siw.Handler.MultipartExample(c) +} + +// MultipleRequestAndResponseTypes operation middleware +func (siw *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(c *fiber.Ctx) error { + + return siw.Handler.MultipleRequestAndResponseTypes(c) +} + +// ReservedGoKeywordParameters operation middleware +func (siw *ServerInterfaceWrapper) ReservedGoKeywordParameters(c *fiber.Ctx) error { + + var err error + + // ------------- Path parameter "type" ------------- + var pType string + + err = runtime.BindStyledParameter("simple", false, "type", c.Params("type"), &pType) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter type: %w", err).Error()) + } + + return siw.Handler.ReservedGoKeywordParameters(c, pType) +} + +// ReusableResponses operation middleware +func (siw *ServerInterfaceWrapper) ReusableResponses(c *fiber.Ctx) error { + + return siw.Handler.ReusableResponses(c) +} + +// TextExample operation middleware +func (siw *ServerInterfaceWrapper) TextExample(c *fiber.Ctx) error { + + return siw.Handler.TextExample(c) +} + +// UnknownExample operation middleware +func (siw *ServerInterfaceWrapper) UnknownExample(c *fiber.Ctx) error { + + return siw.Handler.UnknownExample(c) +} + +// UnspecifiedContentType operation middleware +func (siw *ServerInterfaceWrapper) UnspecifiedContentType(c *fiber.Ctx) error { + + return siw.Handler.UnspecifiedContentType(c) +} + +// URLEncodedExample operation middleware +func (siw *ServerInterfaceWrapper) URLEncodedExample(c *fiber.Ctx) error { + + return siw.Handler.URLEncodedExample(c) +} + +// HeadersExample operation middleware +func (siw *ServerInterfaceWrapper) HeadersExample(c *fiber.Ctx) error { + + var err error + + // Parameter object where we will unmarshal all parameters from the context + var params HeadersExampleParams + + headers := c.GetReqHeaders() + + // ------------- Required header parameter "header1" ------------- + if value, found := headers[http.CanonicalHeaderKey("header1")]; found { + var Header1 string + + err = runtime.BindStyledParameterWithLocation("simple", false, "header1", runtime.ParamLocationHeader, value, &Header1) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter header1: %w", err).Error()) + } + + params.Header1 = Header1 + + } else { + err = fmt.Errorf("Header parameter header1 is required, but not found: %w", err) + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + + // ------------- Optional header parameter "header2" ------------- + if value, found := headers[http.CanonicalHeaderKey("header2")]; found { + var Header2 int + + err = runtime.BindStyledParameterWithLocation("simple", false, "header2", runtime.ParamLocationHeader, value, &Header2) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter header2: %w", err).Error()) + } + + params.Header2 = &Header2 + + } + + return siw.Handler.HeadersExample(c, params) +} + +// FiberServerOptions provides options for the Fiber server. +type FiberServerOptions struct { + BaseURL string + Middlewares []MiddlewareFunc +} + +// RegisterHandlers creates http.Handler with routing matching OpenAPI spec. +func RegisterHandlers(router fiber.Router, si ServerInterface) { + RegisterHandlersWithOptions(router, si, FiberServerOptions{}) +} + +// RegisterHandlersWithOptions creates http.Handler with additional options +func RegisterHandlersWithOptions(router fiber.Router, si ServerInterface, options FiberServerOptions) { + wrapper := ServerInterfaceWrapper{ + Handler: si, + } + + for _, m := range options.Middlewares { + router.Use(m) + } + + router.Post(options.BaseURL+"/json", wrapper.JSONExample) + + router.Post(options.BaseURL+"/multipart", wrapper.MultipartExample) + + router.Post(options.BaseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes) + + router.Get(options.BaseURL+"/reserved-go-keyword-parameters/:type", wrapper.ReservedGoKeywordParameters) + + router.Post(options.BaseURL+"/reusable-responses", wrapper.ReusableResponses) + + router.Post(options.BaseURL+"/text", wrapper.TextExample) + + router.Post(options.BaseURL+"/unknown", wrapper.UnknownExample) + + router.Post(options.BaseURL+"/unspecified-content-type", wrapper.UnspecifiedContentType) + + router.Post(options.BaseURL+"/urlencoded", wrapper.URLEncodedExample) + + router.Post(options.BaseURL+"/with-headers", wrapper.HeadersExample) + +} + +type BadrequestResponse struct { +} + +type ReusableresponseResponseHeaders struct { + Header1 string + Header2 int +} +type ReusableresponseJSONResponse struct { + Body Example + + Headers ReusableresponseResponseHeaders +} + +type JSONExampleRequestObject struct { + Body *JSONExampleJSONRequestBody +} + +type JSONExampleResponseObject interface { + VisitJSONExampleResponse(ctx *fiber.Ctx) error +} + +type JSONExample200JSONResponse Example + +func (response JSONExample200JSONResponse) VisitJSONExampleResponse(ctx *fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type JSONExample400Response = BadrequestResponse + +func (response JSONExample400Response) VisitJSONExampleResponse(ctx *fiber.Ctx) error { + ctx.Status(400) + return nil +} + +type JSONExampledefaultResponse struct { + StatusCode int +} + +func (response JSONExampledefaultResponse) VisitJSONExampleResponse(ctx *fiber.Ctx) error { + ctx.Status(response.StatusCode) + return nil +} + +type MultipartExampleRequestObject struct { + Body *multipart.Reader +} + +type MultipartExampleResponseObject interface { + VisitMultipartExampleResponse(ctx *fiber.Ctx) error +} + +type MultipartExample200MultipartResponse func(writer *multipart.Writer) error + +func (response MultipartExample200MultipartResponse) VisitMultipartExampleResponse(ctx *fiber.Ctx) error { + writer := multipart.NewWriter(ctx.Response().BodyWriter()) + ctx.Response().Header.Set("Content-Type", writer.FormDataContentType()) + ctx.Status(200) + + defer writer.Close() + return response(writer) +} + +type MultipartExample400Response = BadrequestResponse + +func (response MultipartExample400Response) VisitMultipartExampleResponse(ctx *fiber.Ctx) error { + ctx.Status(400) + return nil +} + +type MultipartExampledefaultResponse struct { + StatusCode int +} + +func (response MultipartExampledefaultResponse) VisitMultipartExampleResponse(ctx *fiber.Ctx) error { + ctx.Status(response.StatusCode) + return nil +} + +type MultipleRequestAndResponseTypesRequestObject struct { + JSONBody *MultipleRequestAndResponseTypesJSONRequestBody + FormdataBody *MultipleRequestAndResponseTypesFormdataRequestBody + Body io.Reader + MultipartBody *multipart.Reader + TextBody *MultipleRequestAndResponseTypesTextRequestBody +} + +type MultipleRequestAndResponseTypesResponseObject interface { + VisitMultipleRequestAndResponseTypesResponse(ctx *fiber.Ctx) error +} + +type MultipleRequestAndResponseTypes200JSONResponse Example + +func (response MultipleRequestAndResponseTypes200JSONResponse) VisitMultipleRequestAndResponseTypesResponse(ctx *fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type MultipleRequestAndResponseTypes200FormdataResponse Example + +func (response MultipleRequestAndResponseTypes200FormdataResponse) VisitMultipleRequestAndResponseTypesResponse(ctx *fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/x-www-form-urlencoded") + ctx.Status(200) + + if form, err := runtime.MarshalForm(response, nil); err != nil { + return err + } else { + _, err := ctx.WriteString(form.Encode()) + return err + } +} + +type MultipleRequestAndResponseTypes200ImagepngResponse struct { + Body io.Reader + ContentLength int64 +} + +func (response MultipleRequestAndResponseTypes200ImagepngResponse) VisitMultipleRequestAndResponseTypesResponse(ctx *fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "image/png") + if response.ContentLength != 0 { + ctx.Response().Header.Set("Content-Length", fmt.Sprint(response.ContentLength)) + } + ctx.Status(200) + + if closer, ok := response.Body.(io.ReadCloser); ok { + defer closer.Close() + } + _, err := io.Copy(ctx.Response().BodyWriter(), response.Body) + return err +} + +type MultipleRequestAndResponseTypes200MultipartResponse func(writer *multipart.Writer) error + +func (response MultipleRequestAndResponseTypes200MultipartResponse) VisitMultipleRequestAndResponseTypesResponse(ctx *fiber.Ctx) error { + writer := multipart.NewWriter(ctx.Response().BodyWriter()) + ctx.Response().Header.Set("Content-Type", writer.FormDataContentType()) + ctx.Status(200) + + defer writer.Close() + return response(writer) +} + +type MultipleRequestAndResponseTypes200TextResponse string + +func (response MultipleRequestAndResponseTypes200TextResponse) VisitMultipleRequestAndResponseTypesResponse(ctx *fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "text/plain") + ctx.Status(200) + + _, err := ctx.WriteString(string(response)) + return err +} + +type MultipleRequestAndResponseTypes400Response = BadrequestResponse + +func (response MultipleRequestAndResponseTypes400Response) VisitMultipleRequestAndResponseTypesResponse(ctx *fiber.Ctx) error { + ctx.Status(400) + return nil +} + +type ReservedGoKeywordParametersRequestObject struct { + Type string `json:"type"` +} + +type ReservedGoKeywordParametersResponseObject interface { + VisitReservedGoKeywordParametersResponse(ctx *fiber.Ctx) error +} + +type ReservedGoKeywordParameters200TextResponse string + +func (response ReservedGoKeywordParameters200TextResponse) VisitReservedGoKeywordParametersResponse(ctx *fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "text/plain") + ctx.Status(200) + + _, err := ctx.WriteString(string(response)) + return err +} + +type ReusableResponsesRequestObject struct { + Body *ReusableResponsesJSONRequestBody +} + +type ReusableResponsesResponseObject interface { + VisitReusableResponsesResponse(ctx *fiber.Ctx) error +} + +type ReusableResponses200JSONResponse struct{ ReusableresponseJSONResponse } + +func (response ReusableResponses200JSONResponse) VisitReusableResponsesResponse(ctx *fiber.Ctx) error { + ctx.Response().Header.Set("header1", fmt.Sprint(response.Headers.Header1)) + ctx.Response().Header.Set("header2", fmt.Sprint(response.Headers.Header2)) + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response.Body) +} + +type ReusableResponses400Response = BadrequestResponse + +func (response ReusableResponses400Response) VisitReusableResponsesResponse(ctx *fiber.Ctx) error { + ctx.Status(400) + return nil +} + +type ReusableResponsesdefaultResponse struct { + StatusCode int +} + +func (response ReusableResponsesdefaultResponse) VisitReusableResponsesResponse(ctx *fiber.Ctx) error { + ctx.Status(response.StatusCode) + return nil +} + +type TextExampleRequestObject struct { + Body *TextExampleTextRequestBody +} + +type TextExampleResponseObject interface { + VisitTextExampleResponse(ctx *fiber.Ctx) error +} + +type TextExample200TextResponse string + +func (response TextExample200TextResponse) VisitTextExampleResponse(ctx *fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "text/plain") + ctx.Status(200) + + _, err := ctx.WriteString(string(response)) + return err +} + +type TextExample400Response = BadrequestResponse + +func (response TextExample400Response) VisitTextExampleResponse(ctx *fiber.Ctx) error { + ctx.Status(400) + return nil +} + +type TextExampledefaultResponse struct { + StatusCode int +} + +func (response TextExampledefaultResponse) VisitTextExampleResponse(ctx *fiber.Ctx) error { + ctx.Status(response.StatusCode) + return nil +} + +type UnknownExampleRequestObject struct { + Body io.Reader +} + +type UnknownExampleResponseObject interface { + VisitUnknownExampleResponse(ctx *fiber.Ctx) error +} + +type UnknownExample200Videomp4Response struct { + Body io.Reader + ContentLength int64 +} + +func (response UnknownExample200Videomp4Response) VisitUnknownExampleResponse(ctx *fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "video/mp4") + if response.ContentLength != 0 { + ctx.Response().Header.Set("Content-Length", fmt.Sprint(response.ContentLength)) + } + ctx.Status(200) + + if closer, ok := response.Body.(io.ReadCloser); ok { + defer closer.Close() + } + _, err := io.Copy(ctx.Response().BodyWriter(), response.Body) + return err +} + +type UnknownExample400Response = BadrequestResponse + +func (response UnknownExample400Response) VisitUnknownExampleResponse(ctx *fiber.Ctx) error { + ctx.Status(400) + return nil +} + +type UnknownExampledefaultResponse struct { + StatusCode int +} + +func (response UnknownExampledefaultResponse) VisitUnknownExampleResponse(ctx *fiber.Ctx) error { + ctx.Status(response.StatusCode) + return nil +} + +type UnspecifiedContentTypeRequestObject struct { + ContentType string + Body io.Reader +} + +type UnspecifiedContentTypeResponseObject interface { + VisitUnspecifiedContentTypeResponse(ctx *fiber.Ctx) error +} + +type UnspecifiedContentType200VideoResponse struct { + Body io.Reader + ContentType string + ContentLength int64 +} + +func (response UnspecifiedContentType200VideoResponse) VisitUnspecifiedContentTypeResponse(ctx *fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", response.ContentType) + if response.ContentLength != 0 { + ctx.Response().Header.Set("Content-Length", fmt.Sprint(response.ContentLength)) + } + ctx.Status(200) + + if closer, ok := response.Body.(io.ReadCloser); ok { + defer closer.Close() + } + _, err := io.Copy(ctx.Response().BodyWriter(), response.Body) + return err +} + +type UnspecifiedContentType400Response = BadrequestResponse + +func (response UnspecifiedContentType400Response) VisitUnspecifiedContentTypeResponse(ctx *fiber.Ctx) error { + ctx.Status(400) + return nil +} + +type UnspecifiedContentType401Response struct { +} + +func (response UnspecifiedContentType401Response) VisitUnspecifiedContentTypeResponse(ctx *fiber.Ctx) error { + ctx.Status(401) + return nil +} + +type UnspecifiedContentType403Response struct { +} + +func (response UnspecifiedContentType403Response) VisitUnspecifiedContentTypeResponse(ctx *fiber.Ctx) error { + ctx.Status(403) + return nil +} + +type UnspecifiedContentTypedefaultResponse struct { + StatusCode int +} + +func (response UnspecifiedContentTypedefaultResponse) VisitUnspecifiedContentTypeResponse(ctx *fiber.Ctx) error { + ctx.Status(response.StatusCode) + return nil +} + +type URLEncodedExampleRequestObject struct { + Body *URLEncodedExampleFormdataRequestBody +} + +type URLEncodedExampleResponseObject interface { + VisitURLEncodedExampleResponse(ctx *fiber.Ctx) error +} + +type URLEncodedExample200FormdataResponse Example + +func (response URLEncodedExample200FormdataResponse) VisitURLEncodedExampleResponse(ctx *fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/x-www-form-urlencoded") + ctx.Status(200) + + if form, err := runtime.MarshalForm(response, nil); err != nil { + return err + } else { + _, err := ctx.WriteString(form.Encode()) + return err + } +} + +type URLEncodedExample400Response = BadrequestResponse + +func (response URLEncodedExample400Response) VisitURLEncodedExampleResponse(ctx *fiber.Ctx) error { + ctx.Status(400) + return nil +} + +type URLEncodedExampledefaultResponse struct { + StatusCode int +} + +func (response URLEncodedExampledefaultResponse) VisitURLEncodedExampleResponse(ctx *fiber.Ctx) error { + ctx.Status(response.StatusCode) + return nil +} + +type HeadersExampleRequestObject struct { + Params HeadersExampleParams + Body *HeadersExampleJSONRequestBody +} + +type HeadersExampleResponseObject interface { + VisitHeadersExampleResponse(ctx *fiber.Ctx) error +} + +type HeadersExample200ResponseHeaders struct { + Header1 string + Header2 int +} + +type HeadersExample200JSONResponse struct { + Body Example + Headers HeadersExample200ResponseHeaders +} + +func (response HeadersExample200JSONResponse) VisitHeadersExampleResponse(ctx *fiber.Ctx) error { + ctx.Response().Header.Set("header1", fmt.Sprint(response.Headers.Header1)) + ctx.Response().Header.Set("header2", fmt.Sprint(response.Headers.Header2)) + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response.Body) +} + +type HeadersExample400Response = BadrequestResponse + +func (response HeadersExample400Response) VisitHeadersExampleResponse(ctx *fiber.Ctx) error { + ctx.Status(400) + return nil +} + +type HeadersExampledefaultResponse struct { + StatusCode int +} + +func (response HeadersExampledefaultResponse) VisitHeadersExampleResponse(ctx *fiber.Ctx) error { + ctx.Status(response.StatusCode) + return nil +} + +// StrictServerInterface represents all server handlers. +type StrictServerInterface interface { + + // (POST /json) + JSONExample(ctx context.Context, request JSONExampleRequestObject) (JSONExampleResponseObject, error) + + // (POST /multipart) + MultipartExample(ctx context.Context, request MultipartExampleRequestObject) (MultipartExampleResponseObject, error) + + // (POST /multiple) + MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, error) + + // (GET /reserved-go-keyword-parameters/{type}) + ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) + + // (POST /reusable-responses) + ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error) + + // (POST /text) + TextExample(ctx context.Context, request TextExampleRequestObject) (TextExampleResponseObject, error) + + // (POST /unknown) + UnknownExample(ctx context.Context, request UnknownExampleRequestObject) (UnknownExampleResponseObject, error) + + // (POST /unspecified-content-type) + UnspecifiedContentType(ctx context.Context, request UnspecifiedContentTypeRequestObject) (UnspecifiedContentTypeResponseObject, error) + + // (POST /urlencoded) + URLEncodedExample(ctx context.Context, request URLEncodedExampleRequestObject) (URLEncodedExampleResponseObject, error) + + // (POST /with-headers) + HeadersExample(ctx context.Context, request HeadersExampleRequestObject) (HeadersExampleResponseObject, error) +} + +type StrictHandlerFunc func(ctx *fiber.Ctx, args interface{}) (interface{}, error) + +type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc + +func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface { + return &strictHandler{ssi: ssi, middlewares: middlewares} +} + +type strictHandler struct { + ssi StrictServerInterface + middlewares []StrictMiddlewareFunc +} + +// JSONExample operation middleware +func (sh *strictHandler) JSONExample(ctx *fiber.Ctx) error { + var request JSONExampleRequestObject + + var body JSONExampleJSONRequestBody + if err := ctx.BodyParser(&body); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + request.Body = &body + + handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.JSONExample(ctx.UserContext(), request.(JSONExampleRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "JSONExample") + } + + response, err := handler(ctx, request) + + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } else if validResponse, ok := response.(JSONExampleResponseObject); ok { + if err := validResponse.VisitJSONExampleResponse(ctx); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + } else if response != nil { + return fmt.Errorf("Unexpected response type: %T", response) + } + return nil +} + +// MultipartExample operation middleware +func (sh *strictHandler) MultipartExample(ctx *fiber.Ctx) error { + var request MultipartExampleRequestObject + + request.Body = multipart.NewReader(bytes.NewReader(ctx.Request().Body()), string(ctx.Request().Header.MultipartFormBoundary())) + + handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.MultipartExample(ctx.UserContext(), request.(MultipartExampleRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "MultipartExample") + } + + response, err := handler(ctx, request) + + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } else if validResponse, ok := response.(MultipartExampleResponseObject); ok { + if err := validResponse.VisitMultipartExampleResponse(ctx); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + } else if response != nil { + return fmt.Errorf("Unexpected response type: %T", response) + } + return nil +} + +// MultipleRequestAndResponseTypes operation middleware +func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx *fiber.Ctx) error { + var request MultipleRequestAndResponseTypesRequestObject + + if strings.HasPrefix(string(ctx.Request().Header.ContentType()), "application/json") { + var body MultipleRequestAndResponseTypesJSONRequestBody + if err := ctx.BodyParser(&body); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + request.JSONBody = &body + } + if strings.HasPrefix(string(ctx.Request().Header.ContentType()), "application/x-www-form-urlencoded") { + var body MultipleRequestAndResponseTypesFormdataRequestBody + if err := ctx.BodyParser(&body); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + request.FormdataBody = &body + } + if strings.HasPrefix(string(ctx.Request().Header.ContentType()), "image/png") { + request.Body = bytes.NewReader(ctx.Request().Body()) + } + if strings.HasPrefix(string(ctx.Request().Header.ContentType()), "multipart/form-data") { + request.MultipartBody = multipart.NewReader(bytes.NewReader(ctx.Request().Body()), string(ctx.Request().Header.MultipartFormBoundary())) + } + if strings.HasPrefix(string(ctx.Request().Header.ContentType()), "text/plain") { + data := ctx.Request().Body() + body := MultipleRequestAndResponseTypesTextRequestBody(data) + request.TextBody = &body + } + + handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.MultipleRequestAndResponseTypes(ctx.UserContext(), request.(MultipleRequestAndResponseTypesRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "MultipleRequestAndResponseTypes") + } + + response, err := handler(ctx, request) + + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } else if validResponse, ok := response.(MultipleRequestAndResponseTypesResponseObject); ok { + if err := validResponse.VisitMultipleRequestAndResponseTypesResponse(ctx); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + } else if response != nil { + return fmt.Errorf("Unexpected response type: %T", response) + } + return nil +} + +// ReservedGoKeywordParameters operation middleware +func (sh *strictHandler) ReservedGoKeywordParameters(ctx *fiber.Ctx, pType string) error { + var request ReservedGoKeywordParametersRequestObject + + request.Type = pType + + handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.ReservedGoKeywordParameters(ctx.UserContext(), request.(ReservedGoKeywordParametersRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "ReservedGoKeywordParameters") + } + + response, err := handler(ctx, request) + + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } else if validResponse, ok := response.(ReservedGoKeywordParametersResponseObject); ok { + if err := validResponse.VisitReservedGoKeywordParametersResponse(ctx); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + } else if response != nil { + return fmt.Errorf("Unexpected response type: %T", response) + } + return nil +} + +// ReusableResponses operation middleware +func (sh *strictHandler) ReusableResponses(ctx *fiber.Ctx) error { + var request ReusableResponsesRequestObject + + var body ReusableResponsesJSONRequestBody + if err := ctx.BodyParser(&body); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + request.Body = &body + + handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.ReusableResponses(ctx.UserContext(), request.(ReusableResponsesRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "ReusableResponses") + } + + response, err := handler(ctx, request) + + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } else if validResponse, ok := response.(ReusableResponsesResponseObject); ok { + if err := validResponse.VisitReusableResponsesResponse(ctx); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + } else if response != nil { + return fmt.Errorf("Unexpected response type: %T", response) + } + return nil +} + +// TextExample operation middleware +func (sh *strictHandler) TextExample(ctx *fiber.Ctx) error { + var request TextExampleRequestObject + + data := ctx.Request().Body() + body := TextExampleTextRequestBody(data) + request.Body = &body + + handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.TextExample(ctx.UserContext(), request.(TextExampleRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "TextExample") + } + + response, err := handler(ctx, request) + + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } else if validResponse, ok := response.(TextExampleResponseObject); ok { + if err := validResponse.VisitTextExampleResponse(ctx); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + } else if response != nil { + return fmt.Errorf("Unexpected response type: %T", response) + } + return nil +} + +// UnknownExample operation middleware +func (sh *strictHandler) UnknownExample(ctx *fiber.Ctx) error { + var request UnknownExampleRequestObject + + request.Body = bytes.NewReader(ctx.Request().Body()) + + handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.UnknownExample(ctx.UserContext(), request.(UnknownExampleRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "UnknownExample") + } + + response, err := handler(ctx, request) + + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } else if validResponse, ok := response.(UnknownExampleResponseObject); ok { + if err := validResponse.VisitUnknownExampleResponse(ctx); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + } else if response != nil { + return fmt.Errorf("Unexpected response type: %T", response) + } + return nil +} + +// UnspecifiedContentType operation middleware +func (sh *strictHandler) UnspecifiedContentType(ctx *fiber.Ctx) error { + var request UnspecifiedContentTypeRequestObject + + request.ContentType = string(ctx.Request().Header.ContentType()) + + request.Body = bytes.NewReader(ctx.Request().Body()) + + handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.UnspecifiedContentType(ctx.UserContext(), request.(UnspecifiedContentTypeRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "UnspecifiedContentType") + } + + response, err := handler(ctx, request) + + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } else if validResponse, ok := response.(UnspecifiedContentTypeResponseObject); ok { + if err := validResponse.VisitUnspecifiedContentTypeResponse(ctx); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + } else if response != nil { + return fmt.Errorf("Unexpected response type: %T", response) + } + return nil +} + +// URLEncodedExample operation middleware +func (sh *strictHandler) URLEncodedExample(ctx *fiber.Ctx) error { + var request URLEncodedExampleRequestObject + + var body URLEncodedExampleFormdataRequestBody + if err := ctx.BodyParser(&body); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + request.Body = &body + + handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.URLEncodedExample(ctx.UserContext(), request.(URLEncodedExampleRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "URLEncodedExample") + } + + response, err := handler(ctx, request) + + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } else if validResponse, ok := response.(URLEncodedExampleResponseObject); ok { + if err := validResponse.VisitURLEncodedExampleResponse(ctx); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + } else if response != nil { + return fmt.Errorf("Unexpected response type: %T", response) + } + return nil +} + +// HeadersExample operation middleware +func (sh *strictHandler) HeadersExample(ctx *fiber.Ctx, params HeadersExampleParams) error { + var request HeadersExampleRequestObject + + request.Params = params + + var body HeadersExampleJSONRequestBody + if err := ctx.BodyParser(&body); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + request.Body = &body + + handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.HeadersExample(ctx.UserContext(), request.(HeadersExampleRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "HeadersExample") + } + + response, err := handler(ctx, request) + + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } else if validResponse, ok := response.(HeadersExampleResponseObject); ok { + if err := validResponse.VisitHeadersExampleResponse(ctx); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + } else if response != nil { + return fmt.Errorf("Unexpected response type: %T", response) + } + return nil +} + +// Base64 encoded, gzipped, json marshaled Swagger object +var swaggerSpec = []string{ + + "H4sIAAAAAAAC/+xYX2/bNhD/KgS3p0KynDRPeluDotu6rYOTPg15oMWzzFYiuePJimHouw8UJf+pFS/O", + "7BgY+mbRd787/u4Pj1zxzJTWaNDkeLriCM4a7aD9mAqJ8HcFjvyXBJehsqSM5il/J+Sk+6+JOELlxLSA", + "Xt3LZ0YT6FZVWFuoTHjV5Ivz+ivusjmUwv/6EWHGU/5DsnElCf+6BB5FaQvgTdNE33jw6SOP+ByEBGy9", + "DT+vdrFpaYGn3BEqnXMPEsSuB8WUJsgBvTUv2jnhBXo/0hW3aCwgqcDRQhQVDFvqVsz0C2QUdqD0zOxz", + "eWs0CaUdk2o2AwRNrCOPeQzHXGWtQQLJpkvmLWTEHOACkEecFHnH+N32OuscdjziC0AXDF2NxqOxj5ex", + "oIVVPOVv26WIW0HzdkPrAFkzFPdf7z79wZRjoiJTClKZKIolKwW6uSgKkExpMt7HKiM34q0pbCP/i+zU", + "33dc+rRpM+idkctzZEybmFv5fD0ev1JiNhG/CcaGMNZOJVsV1sLMRFUMkP5Zf9Wm1gwQDXY7S8qqIGUF", + "0nawdtn+vRd5DuVrvGRmsIylIHEm1k9l6aLEd81gsEju5qZ2bG5qRoZJEAWrFc1Zr/hNdSvNBHNK5wWw", + "3qloMJIFdD33Jy0n3V7uPcbZaynaQXmM67qO2+BVWIDOjAT5MlhVihwSq/NddY8tiKd8uiSftvvd9URJ", + "FHGCR0psIZQ+fHS8Ujv5zvTJCjuUK0J7JMo4N/FXWNYGZWwFihII0CUrb73xwDkMlPKfa0mWCc2mwLQo", + "QTIxI0D2wbAO0u2V7KSz+8F8DCIbqPa8XX+kf624p6Q9g3nEvQGeBlZCXSv0QSesIDpA28O/5ud/CkDP", + "Zpj04h1Tw22wb1Fr6hBmzrfEocgN8BcsTbYkLjMwHM64vdn3Nc4gH8mnz/17eHzWkX/C1vfatX0sYVVY", + "fJqzTus5tL2wkz6DxYWSYJLS3hyJfDFSnYVMzRTIuNtFHHx7qiXcGp0h0O4I5O8T2hBbg/lrDs2BBQYi", + "5gyrgZWVI2aFc0xR20UKFa5KEvaax+eNZ7fB0v2mnR6K6pszxfTNpSJ6M746XuXtmfNmZ5R5oh4nv70P", + "MsfeF082Mx058Z3O7oXK2V9S4q0XleES/jkIbM70DNTCT0RaMgSqUINkCyX6R4C92uwANmEdmoWCG5tp", + "qH/dOWYgig5iXfPo0AvQw//4eeKc72bnztMm4uGJKyRLhYWPKJFNkyQ8jY1cLfIccKRMIqzizUPzTwAA", + "AP//O0NNuucUAAA=", +} + +// GetSwagger returns the content of the embedded swagger specification file +// or error if failed to decode +func decodeSpec() ([]byte, error) { + zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, "")) + if err != nil { + return nil, fmt.Errorf("error base64 decoding spec: %s", err) + } + zr, err := gzip.NewReader(bytes.NewReader(zipped)) + if err != nil { + return nil, fmt.Errorf("error decompressing spec: %s", err) + } + var buf bytes.Buffer + _, err = buf.ReadFrom(zr) + if err != nil { + return nil, fmt.Errorf("error decompressing spec: %s", err) + } + + return buf.Bytes(), nil +} + +var rawSpec = decodeSpecCached() + +// a naive cached of a decoded swagger spec +func decodeSpecCached() func() ([]byte, error) { + data, err := decodeSpec() + return func() ([]byte, error) { + return data, err + } +} + +// Constructs a synthetic filesystem for resolving external references when loading openapi specifications. +func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) { + var res = make(map[string]func() ([]byte, error)) + if len(pathToFile) > 0 { + res[pathToFile] = rawSpec + } + + return res +} + +// GetSwagger returns the Swagger specification corresponding to the generated code +// in this file. The external references of Swagger specification are resolved. +// The logic of resolving external references is tightly connected to "import-mapping" feature. +// Externally referenced files must be embedded in the corresponding golang packages. +// Urls can be supported but this task was out of the scope. +func GetSwagger() (swagger *openapi3.T, err error) { + var resolvePath = PathToRawSpec("") + + loader := openapi3.NewLoader() + loader.IsExternalRefsAllowed = true + loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) { + var pathToFile = url.String() + pathToFile = path.Clean(pathToFile) + getSpec, ok := resolvePath[pathToFile] + if !ok { + err1 := fmt.Errorf("path not found: %s", pathToFile) + return nil, err1 + } + return getSpec() + } + var specData []byte + specData, err = rawSpec() + if err != nil { + return + } + swagger, err = loader.LoadFromData(specData) + if err != nil { + return + } + return +} diff --git a/internal/test/strict-server/fiber/server.go b/internal/test/strict-server/fiber/server.go new file mode 100644 index 0000000000..b0724db19f --- /dev/null +++ b/internal/test/strict-server/fiber/server.go @@ -0,0 +1,106 @@ +//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=server.cfg.yaml ../strict-schema.yaml +//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=types.cfg.yaml ../strict-schema.yaml + +package api + +import ( + "context" + "io" + "mime/multipart" +) + +type StrictServer struct { +} + +func (s StrictServer) JSONExample(ctx context.Context, request JSONExampleRequestObject) (JSONExampleResponseObject, error) { + return JSONExample200JSONResponse(*request.Body), nil +} + +func (s StrictServer) MultipartExample(ctx context.Context, request MultipartExampleRequestObject) (MultipartExampleResponseObject, error) { + return MultipartExample200MultipartResponse(func(writer *multipart.Writer) error { + for { + part, err := request.Body.NextPart() + if err == io.EOF { + return nil + } else if err != nil { + return err + } + w, err := writer.CreatePart(part.Header) + if err != nil { + return err + } + _, err = io.Copy(w, part) + if err != nil { + return err + } + if err = part.Close(); err != nil { + return err + } + } + }), nil +} + +func (s StrictServer) MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, error) { + switch { + case request.Body != nil: + return MultipleRequestAndResponseTypes200ImagepngResponse{Body: request.Body}, nil + case request.JSONBody != nil: + return MultipleRequestAndResponseTypes200JSONResponse(*request.JSONBody), nil + case request.FormdataBody != nil: + return MultipleRequestAndResponseTypes200FormdataResponse(*request.FormdataBody), nil + case request.TextBody != nil: + return MultipleRequestAndResponseTypes200TextResponse(*request.TextBody), nil + case request.MultipartBody != nil: + return MultipleRequestAndResponseTypes200MultipartResponse(func(writer *multipart.Writer) error { + for { + part, err := request.MultipartBody.NextPart() + if err == io.EOF { + return nil + } else if err != nil { + return err + } + w, err := writer.CreatePart(part.Header) + if err != nil { + return err + } + _, err = io.Copy(w, part) + if err != nil { + return err + } + if err = part.Close(); err != nil { + return err + } + } + }), nil + default: + return MultipleRequestAndResponseTypes400Response{}, nil + } +} + +func (s StrictServer) TextExample(ctx context.Context, request TextExampleRequestObject) (TextExampleResponseObject, error) { + return TextExample200TextResponse(*request.Body), nil +} + +func (s StrictServer) UnknownExample(ctx context.Context, request UnknownExampleRequestObject) (UnknownExampleResponseObject, error) { + return UnknownExample200Videomp4Response{Body: request.Body}, nil +} + +func (s StrictServer) UnspecifiedContentType(ctx context.Context, request UnspecifiedContentTypeRequestObject) (UnspecifiedContentTypeResponseObject, error) { + return UnspecifiedContentType200VideoResponse{Body: request.Body, ContentType: request.ContentType}, nil +} + +func (s StrictServer) URLEncodedExample(ctx context.Context, request URLEncodedExampleRequestObject) (URLEncodedExampleResponseObject, error) { + return URLEncodedExample200FormdataResponse(*request.Body), nil +} + +func (s StrictServer) HeadersExample(ctx context.Context, request HeadersExampleRequestObject) (HeadersExampleResponseObject, error) { + return HeadersExample200JSONResponse{Body: *request.Body, Headers: HeadersExample200ResponseHeaders{Header1: request.Params.Header1, Header2: *request.Params.Header2}}, nil +} + +func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error) { + return ReusableResponses200JSONResponse{ReusableresponseJSONResponse: ReusableresponseJSONResponse{Body: *request.Body}}, nil +} + +func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) { + return ReservedGoKeywordParameters200TextResponse(""), nil +} diff --git a/internal/test/strict-server/fiber/types.cfg.yaml b/internal/test/strict-server/fiber/types.cfg.yaml new file mode 100644 index 0000000000..4ea1d8aa5b --- /dev/null +++ b/internal/test/strict-server/fiber/types.cfg.yaml @@ -0,0 +1,4 @@ +package: api +generate: + models: true +output: types.gen.go diff --git a/internal/test/strict-server/fiber/types.gen.go b/internal/test/strict-server/fiber/types.gen.go new file mode 100644 index 0000000000..33827cb7a4 --- /dev/null +++ b/internal/test/strict-server/fiber/types.gen.go @@ -0,0 +1,54 @@ +// Package api provides primitives to interact with the openapi HTTP API. +// +// Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT. +package api + +// Example defines model for example. +type Example struct { + Value *string `json:"value,omitempty"` +} + +// Reusableresponse defines model for reusableresponse. +type Reusableresponse = Example + +// MultipleRequestAndResponseTypesTextBody defines parameters for MultipleRequestAndResponseTypes. +type MultipleRequestAndResponseTypesTextBody = string + +// TextExampleTextBody defines parameters for TextExample. +type TextExampleTextBody = string + +// HeadersExampleParams defines parameters for HeadersExample. +type HeadersExampleParams struct { + Header1 string `json:"header1"` + Header2 *int `json:"header2,omitempty"` +} + +// JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType. +type JSONExampleJSONRequestBody = Example + +// MultipartExampleMultipartRequestBody defines body for MultipartExample for multipart/form-data ContentType. +type MultipartExampleMultipartRequestBody = Example + +// MultipleRequestAndResponseTypesJSONRequestBody defines body for MultipleRequestAndResponseTypes for application/json ContentType. +type MultipleRequestAndResponseTypesJSONRequestBody = Example + +// MultipleRequestAndResponseTypesFormdataRequestBody defines body for MultipleRequestAndResponseTypes for application/x-www-form-urlencoded ContentType. +type MultipleRequestAndResponseTypesFormdataRequestBody = Example + +// MultipleRequestAndResponseTypesMultipartRequestBody defines body for MultipleRequestAndResponseTypes for multipart/form-data ContentType. +type MultipleRequestAndResponseTypesMultipartRequestBody = Example + +// MultipleRequestAndResponseTypesTextRequestBody defines body for MultipleRequestAndResponseTypes for text/plain ContentType. +type MultipleRequestAndResponseTypesTextRequestBody = MultipleRequestAndResponseTypesTextBody + +// ReusableResponsesJSONRequestBody defines body for ReusableResponses for application/json ContentType. +type ReusableResponsesJSONRequestBody = Example + +// TextExampleTextRequestBody defines body for TextExample for text/plain ContentType. +type TextExampleTextRequestBody = TextExampleTextBody + +// URLEncodedExampleFormdataRequestBody defines body for URLEncodedExample for application/x-www-form-urlencoded ContentType. +type URLEncodedExampleFormdataRequestBody = Example + +// HeadersExampleJSONRequestBody defines body for HeadersExample for application/json ContentType. +type HeadersExampleJSONRequestBody = Example diff --git a/internal/test/strict-server/strict_test.go b/internal/test/strict-server/strict_test.go index 860cc4cb8d..bfbb9bc2ab 100644 --- a/internal/test/strict-server/strict_test.go +++ b/internal/test/strict-server/strict_test.go @@ -13,57 +13,68 @@ import ( "github.com/gin-gonic/gin" "github.com/go-chi/chi/v5" + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/adaptor" "github.com/labstack/echo/v4" "github.com/stretchr/testify/assert" - "github.com/deepmap/oapi-codegen/internal/test/strict-server/chi" - api3 "github.com/deepmap/oapi-codegen/internal/test/strict-server/client" - api4 "github.com/deepmap/oapi-codegen/internal/test/strict-server/echo" - api2 "github.com/deepmap/oapi-codegen/internal/test/strict-server/gin" + chiAPI "github.com/deepmap/oapi-codegen/internal/test/strict-server/chi" + clientAPI "github.com/deepmap/oapi-codegen/internal/test/strict-server/client" + echoAPI "github.com/deepmap/oapi-codegen/internal/test/strict-server/echo" + fiberAPI "github.com/deepmap/oapi-codegen/internal/test/strict-server/fiber" + ginAPI "github.com/deepmap/oapi-codegen/internal/test/strict-server/gin" "github.com/deepmap/oapi-codegen/pkg/runtime" "github.com/deepmap/oapi-codegen/pkg/testutil" ) func TestChiServer(t *testing.T) { - server := api.StrictServer{} - strictHandler := api.NewStrictHandler(server, nil) + server := chiAPI.StrictServer{} + strictHandler := chiAPI.NewStrictHandler(server, nil) r := chi.NewRouter() - handler := api.HandlerFromMux(strictHandler, r) + handler := chiAPI.HandlerFromMux(strictHandler, r) testImpl(t, handler) } func TestEchoServer(t *testing.T) { - server := api4.StrictServer{} - strictHandler := api4.NewStrictHandler(server, nil) + server := echoAPI.StrictServer{} + strictHandler := echoAPI.NewStrictHandler(server, nil) e := echo.New() - api4.RegisterHandlers(e, strictHandler) + echoAPI.RegisterHandlers(e, strictHandler) testImpl(t, e) } func TestGinServer(t *testing.T) { - server := api2.StrictServer{} - strictHandler := api2.NewStrictHandler(server, nil) + server := ginAPI.StrictServer{} + strictHandler := ginAPI.NewStrictHandler(server, nil) gin.SetMode(gin.ReleaseMode) r := gin.New() - api2.RegisterHandlers(r, strictHandler) + ginAPI.RegisterHandlers(r, strictHandler) testImpl(t, r) } +func TestFiberServer(t *testing.T) { + server := fiberAPI.StrictServer{} + strictHandler := fiberAPI.NewStrictHandler(server, nil) + r := fiber.New() + fiberAPI.RegisterHandlers(r, strictHandler) + testImpl(t, adaptor.FiberApp(r)) +} + func testImpl(t *testing.T, handler http.Handler) { t.Run("JSONExample", func(t *testing.T) { value := "123" - requestBody := api3.Example{Value: &value} + requestBody := clientAPI.Example{Value: &value} rr := testutil.NewRequest().Post("/json").WithJsonBody(requestBody).GoWithHTTPHandler(t, handler).Recorder assert.Equal(t, http.StatusOK, rr.Code) assert.True(t, strings.HasPrefix(rr.Header().Get("Content-Type"), "application/json")) - var responseBody api3.Example + var responseBody clientAPI.Example err := json.NewDecoder(rr.Body).Decode(&responseBody) assert.NoError(t, err) assert.Equal(t, requestBody, responseBody) }) t.Run("URLEncodedExample", func(t *testing.T) { value := "456" - requestBody := api3.Example{Value: &value} + requestBody := clientAPI.Example{Value: &value} requestBodyEncoded, err := runtime.MarshalForm(&requestBody, nil) assert.NoError(t, err) rr := testutil.NewRequest().Post("/urlencoded").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(requestBodyEncoded.Encode())).GoWithHTTPHandler(t, handler).Recorder @@ -71,7 +82,7 @@ func testImpl(t *testing.T, handler http.Handler) { assert.Equal(t, "application/x-www-form-urlencoded", rr.Header().Get("Content-Type")) values, err := url.ParseQuery(rr.Body.String()) assert.NoError(t, err) - var responseBody api3.Example + var responseBody clientAPI.Example err = runtime.BindForm(&responseBody, values, nil, nil) assert.NoError(t, err) assert.Equal(t, requestBody, responseBody) @@ -116,18 +127,18 @@ func testImpl(t *testing.T, handler http.Handler) { }) t.Run("MultipleRequestAndResponseTypesJSON", func(t *testing.T) { value := "123" - requestBody := api3.Example{Value: &value} + requestBody := clientAPI.Example{Value: &value} rr := testutil.NewRequest().Post("/multiple").WithJsonBody(requestBody).GoWithHTTPHandler(t, handler).Recorder assert.Equal(t, http.StatusOK, rr.Code) assert.True(t, strings.HasPrefix(rr.Header().Get("Content-Type"), "application/json")) - var responseBody api3.Example + var responseBody clientAPI.Example err := json.NewDecoder(rr.Body).Decode(&responseBody) assert.NoError(t, err) assert.Equal(t, requestBody, responseBody) }) t.Run("MultipleRequestAndResponseTypesFormdata", func(t *testing.T) { value := "456" - requestBody := api3.Example{Value: &value} + requestBody := clientAPI.Example{Value: &value} requestBodyEncoded, err := runtime.MarshalForm(&requestBody, nil) assert.NoError(t, err) rr := testutil.NewRequest().Post("/multiple").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(requestBodyEncoded.Encode())).GoWithHTTPHandler(t, handler).Recorder @@ -135,7 +146,7 @@ func testImpl(t *testing.T, handler http.Handler) { assert.Equal(t, "application/x-www-form-urlencoded", rr.Header().Get("Content-Type")) values, err := url.ParseQuery(rr.Body.String()) assert.NoError(t, err) - var responseBody api3.Example + var responseBody clientAPI.Example err = runtime.BindForm(&responseBody, values, nil, nil) assert.NoError(t, err) assert.Equal(t, requestBody, responseBody) @@ -182,11 +193,11 @@ func testImpl(t *testing.T, handler http.Handler) { header1 := "value1" header2 := "890" value := "asdf" - requestBody := api3.Example{Value: &value} + requestBody := clientAPI.Example{Value: &value} rr := testutil.NewRequest().Post("/with-headers").WithHeader("header1", header1).WithHeader("header2", header2).WithJsonBody(requestBody).GoWithHTTPHandler(t, handler).Recorder assert.Equal(t, http.StatusOK, rr.Code) assert.True(t, strings.HasPrefix(rr.Header().Get("Content-Type"), "application/json")) - var responseBody api3.Example + var responseBody clientAPI.Example err := json.NewDecoder(rr.Body).Decode(&responseBody) assert.NoError(t, err) assert.Equal(t, requestBody, responseBody) @@ -203,11 +214,11 @@ func testImpl(t *testing.T, handler http.Handler) { }) t.Run("ReusableResponses", func(t *testing.T) { value := "jkl;" - requestBody := api3.Example{Value: &value} + requestBody := clientAPI.Example{Value: &value} rr := testutil.NewRequest().Post("/reusable-responses").WithJsonBody(requestBody).GoWithHTTPHandler(t, handler).Recorder assert.Equal(t, http.StatusOK, rr.Code) assert.True(t, strings.HasPrefix(rr.Header().Get("Content-Type"), "application/json")) - var responseBody api3.Example + var responseBody clientAPI.Example err := json.NewDecoder(rr.Body).Decode(&responseBody) assert.NoError(t, err) assert.Equal(t, requestBody, responseBody) diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index d8ba40fca8..6cb5fec5ad 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -189,6 +189,14 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) { } } + var fiberServerOut string + if opts.Generate.FiberServer { + fiberServerOut, err = GenerateFiberServer(t, ops) + if err != nil { + return "", fmt.Errorf("error generating Go handlers for Paths: %w", err) + } + } + var ginServerOut string if opts.Generate.GinServer { ginServerOut, err = GenerateGinServer(t, ops) @@ -298,6 +306,13 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) { } } + if opts.Generate.FiberServer { + _, err = w.WriteString(fiberServerOut) + if err != nil { + return "", fmt.Errorf("error writing server path handlers: %w", err) + } + } + if opts.Generate.GinServer { _, err = w.WriteString(ginServerOut) if err != nil { diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index 8d7f2e6a16..9b64bfe25f 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -23,6 +23,7 @@ type Configuration struct { // GenerateOptions specifies which supported output formats to generate. type GenerateOptions struct { ChiServer bool `yaml:"chi-server,omitempty"` // ChiServer specifies whether to generate chi server boilerplate + FiberServer bool `yaml:"fiber-server,omitempty"` // FiberServer specifies whether to generate fiber server boilerplate EchoServer bool `yaml:"echo-server,omitempty"` // EchoServer specifies whether to generate echo server boilerplate GinServer bool `yaml:"gin-server,omitempty"` // GinServer specifies whether to generate gin server boilerplate GorillaServer bool `yaml:"gorilla-server,omitempty"` // GorillaServer specifies whether to generate Gorilla server boilerplate @@ -113,6 +114,9 @@ func (o Configuration) Validate() error { if o.Generate.ChiServer { nServers++ } + if o.Generate.FiberServer { + nServers++ + } if o.Generate.EchoServer { nServers++ } diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index c3d88e1ae2..55cc1bad51 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -919,6 +919,12 @@ func GenerateChiServer(t *template.Template, operations []OperationDefinition) ( return GenerateTemplates([]string{"chi/chi-interface.tmpl", "chi/chi-middleware.tmpl", "chi/chi-handler.tmpl"}, t, operations) } +// GenerateFiberServer This function generates all the go code for the ServerInterface as well as +// all the wrapper functions around our handlers. +func GenerateFiberServer(t *template.Template, operations []OperationDefinition) (string, error) { + return GenerateTemplates([]string{"fiber/fiber-interface.tmpl", "fiber/fiber-middleware.tmpl", "fiber/fiber-handler.tmpl"}, t, operations) +} + // GenerateEchoServer This function generates all the go code for the ServerInterface as well as // all the wrapper functions around our handlers. func GenerateEchoServer(t *template.Template, operations []OperationDefinition) (string, error) { @@ -938,16 +944,22 @@ func GenerateGorillaServer(t *template.Template, operations []OperationDefinitio } func GenerateStrictServer(t *template.Template, operations []OperationDefinition, opts Configuration) (string, error) { - templates := []string{"strict/strict-interface.tmpl"} + + var templates []string + if opts.Generate.ChiServer || opts.Generate.GorillaServer { - templates = append(templates, "strict/strict-http.tmpl") + templates = append(templates, "strict/strict-interface.tmpl", "strict/strict-http.tmpl") } if opts.Generate.EchoServer { - templates = append(templates, "strict/strict-echo.tmpl") + templates = append(templates, "strict/strict-interface.tmpl", "strict/strict-echo.tmpl") } if opts.Generate.GinServer { - templates = append(templates, "strict/strict-gin.tmpl") + templates = append(templates, "strict/strict-interface.tmpl", "strict/strict-gin.tmpl") + } + if opts.Generate.FiberServer { + templates = append(templates, "strict/strict-fiber-interface.tmpl", "strict/strict-fiber.tmpl") } + return GenerateTemplates(templates, t, operations) } diff --git a/pkg/codegen/template_helpers.go b/pkg/codegen/template_helpers.go index bae1e30ceb..d0c440f286 100644 --- a/pkg/codegen/template_helpers.go +++ b/pkg/codegen/template_helpers.go @@ -284,6 +284,7 @@ var TemplateFunctions = template.FuncMap{ "genParamNames": genParamNames, "genParamFmtString": ReplacePathParamsWithStr, "swaggerUriToEchoUri": SwaggerUriToEchoUri, + "swaggerUriToFiberUri": SwaggerUriToFiberUri, "swaggerUriToChiUri": SwaggerUriToChiUri, "swaggerUriToGinUri": SwaggerUriToGinUri, "swaggerUriToGorillaUri": SwaggerUriToGorillaUri, diff --git a/pkg/codegen/templates/fiber/fiber-handler.tmpl b/pkg/codegen/templates/fiber/fiber-handler.tmpl new file mode 100644 index 0000000000..4a55b3c512 --- /dev/null +++ b/pkg/codegen/templates/fiber/fiber-handler.tmpl @@ -0,0 +1,25 @@ +// FiberServerOptions provides options for the Fiber server. +type FiberServerOptions struct { + BaseURL string + Middlewares []MiddlewareFunc +} + +// RegisterHandlers creates http.Handler with routing matching OpenAPI spec. +func RegisterHandlers(router fiber.Router, si ServerInterface) { + RegisterHandlersWithOptions(router, si, FiberServerOptions{}) +} + +// RegisterHandlersWithOptions creates http.Handler with additional options +func RegisterHandlersWithOptions(router fiber.Router, si ServerInterface, options FiberServerOptions) { +{{if .}}wrapper := ServerInterfaceWrapper{ +Handler: si, +} + +for _, m := range options.Middlewares { + router.Use(m) +} +{{end}} +{{range .}} +router.{{.Method | lower | title }}(options.BaseURL+"{{.Path | swaggerUriToFiberUri}}", wrapper.{{.OperationId}}) +{{end}} +} diff --git a/pkg/codegen/templates/fiber/fiber-interface.tmpl b/pkg/codegen/templates/fiber/fiber-interface.tmpl new file mode 100644 index 0000000000..8ef90a851a --- /dev/null +++ b/pkg/codegen/templates/fiber/fiber-interface.tmpl @@ -0,0 +1,7 @@ +// ServerInterface represents all server handlers. +type ServerInterface interface { +{{range .}}{{.SummaryAsComment }} +// ({{.Method}} {{.Path}}) +{{.OperationId}}(c *fiber.Ctx{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params {{.OperationId}}Params{{end}}) error +{{end}} +} diff --git a/pkg/codegen/templates/fiber/fiber-middleware.tmpl b/pkg/codegen/templates/fiber/fiber-middleware.tmpl new file mode 100644 index 0000000000..fd8d00dc15 --- /dev/null +++ b/pkg/codegen/templates/fiber/fiber-middleware.tmpl @@ -0,0 +1,169 @@ +// ServerInterfaceWrapper converts contexts to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface +} + +type MiddlewareFunc fiber.Handler + +{{range .}}{{$opid := .OperationId}} + +// {{$opid}} operation middleware +func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error { + + {{if or .RequiresParamObject (gt (len .PathParams) 0) }} + var err error + {{end}} + + {{range .PathParams}}// ------------- Path parameter "{{.ParamName}}" ------------- + var {{$varName := .GoVariableName}}{{$varName}} {{.TypeDef}} + + {{if .IsPassThrough}} + {{$varName}} = c.Query("{{.ParamName}}") + {{end}} + {{if .IsJson}} + err = json.Unmarshal([]byte(c.Query("{{.ParamName}}")), &{{$varName}}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unmarshalling parameter '{{.ParamName}}' as JSON: %w", err).Error()) + } + {{end}} + {{if .IsStyled}} + err = runtime.BindStyledParameter("{{.Style}}",{{.Explode}}, "{{.ParamName}}", c.Params("{{.ParamName}}"), &{{$varName}}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %w", err).Error()) + } + {{end}} + + {{end}} + +{{range .SecurityDefinitions}} + c.Context().SetUserValue({{.ProviderName | ucFirst}}Scopes, {{toStringArray .Scopes}}) +{{end}} + + {{if .RequiresParamObject}} + // Parameter object where we will unmarshal all parameters from the context + var params {{.OperationId}}Params + + {{if .QueryParams}} + var query url.Values + query, err = url.ParseQuery(string(c.Request().URI().QueryString())) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for query string: %w", err).Error()) + } + {{end}} + + {{range $paramIdx, $param := .QueryParams}} + {{- if (or (or .Required .IsPassThrough) (or .IsJson .IsStyled)) -}} + // ------------- {{if .Required}}Required{{else}}Optional{{end}} query parameter "{{.ParamName}}" ------------- + {{ end }} + {{ if (or (or .Required .IsPassThrough) .IsJson) }} + if paramValue := c.Query("{{.ParamName}}"); paramValue != "" { + + {{if .IsPassThrough}} + params.{{.GoName}} = {{if not .Required}}&{{end}}paramValue + {{end}} + + {{if .IsJson}} + var value {{.TypeDef}} + err = json.Unmarshal([]byte(paramValue), &value) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unmarshalling parameter '{{.ParamName}}' as JSON: %w", err).Error()) + } + + params.{{.GoName}} = {{if not .Required}}&{{end}}value + {{end}} + }{{if .Required}} else { + err = fmt.Errorf("Query argument {{.ParamName}} is required, but not found") + c.Status(fiber.StatusBadRequest).JSON(err) + return err + }{{end}} + {{end}} + {{if .IsStyled}} + err = runtime.BindQueryParameter("{{.Style}}", {{.Explode}}, {{.Required}}, "{{.ParamName}}", query, ¶ms.{{.GoName}}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %w", err).Error()) + } + {{end}} + {{end}} + + {{if .HeaderParams}} + headers := c.GetReqHeaders() + + {{range .HeaderParams}}// ------------- {{if .Required}}Required{{else}}Optional{{end}} header parameter "{{.ParamName}}" ------------- + if value, found := headers[http.CanonicalHeaderKey("{{.ParamName}}")]; found { + var {{.GoName}} {{.TypeDef}} + + {{if .IsPassThrough}} + params.{{.GoName}} = {{if not .Required}}&{{end}}value + {{end}} + + {{if .IsJson}} + err = json.Unmarshal([]byte(value), &{{.GoName}}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unmarshalling parameter '{{.ParamName}}' as JSON: %w", err).Error()) + } + {{end}} + + {{if .IsStyled}} + err = runtime.BindStyledParameterWithLocation("{{.Style}}",{{.Explode}}, "{{.ParamName}}", runtime.ParamLocationHeader, value, &{{.GoName}}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %w", err).Error()) + } + {{end}} + + params.{{.GoName}} = {{if not .Required}}&{{end}}{{.GoName}} + + } {{if .Required}}else { + err = fmt.Errorf("Header parameter {{.ParamName}} is required, but not found: %w", err) + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + }{{end}} + + {{end}} + {{end}} + + {{range .CookieParams}} + var cookie string + + if cookie = c.Cookies("{{.ParamName}}"); cookie == "" { + + {{- if .IsPassThrough}} + params.{{.GoName}} = {{if not .Required}}&{{end}}cookie + {{end}} + + {{- if .IsJson}} + var value {{.TypeDef}} + var decoded string + decoded, err := url.QueryUnescape(cookie) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unescaping cookie parameter '{{.ParamName}}': %w", err).Error()) + } + + err = json.Unmarshal([]byte(decoded), &value) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unmarshalling parameter '{{.ParamName}}' as JSON: %w", err).Error()) + } + + params.{{.GoName}} = {{if not .Required}}&{{end}}value + {{end}} + + {{- if .IsStyled}} + var value {{.TypeDef}} + err = runtime.BindStyledParameter("simple",{{.Explode}}, "{{.ParamName}}", cookie, &value) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %w", err).Error()) + } + params.{{.GoName}} = {{if not .Required}}&{{end}}value + {{end}} + + } + + {{- if .Required}} else { + err = fmt.Errorf("Query argument {{.ParamName}} is required, but not found") + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + {{- end}} + {{end}} + {{end}} + + return siw.Handler.{{.OperationId}}(c{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}}) +} +{{end}} diff --git a/pkg/codegen/templates/imports.tmpl b/pkg/codegen/templates/imports.tmpl index ef43ef390f..f69a492038 100644 --- a/pkg/codegen/templates/imports.tmpl +++ b/pkg/codegen/templates/imports.tmpl @@ -27,6 +27,7 @@ import ( "github.com/go-chi/chi/v5" "github.com/labstack/echo/v4" "github.com/gin-gonic/gin" + "github.com/gofiber/fiber/v2" "github.com/gorilla/mux" {{- range .ExternalImports}} {{ . }} diff --git a/pkg/codegen/templates/strict/strict-fiber-interface.tmpl b/pkg/codegen/templates/strict/strict-fiber-interface.tmpl new file mode 100644 index 0000000000..6fdef0981f --- /dev/null +++ b/pkg/codegen/templates/strict/strict-fiber-interface.tmpl @@ -0,0 +1,137 @@ +{{range .}} + {{$opid := .OperationId -}} + type {{$opid | ucFirst}}RequestObject struct { + {{range .PathParams -}} + {{.GoName | ucFirst}} {{.TypeDef}} {{.JsonTag}} + {{end -}} + {{if .RequiresParamObject -}} + Params {{$opid}}Params + {{end -}} + {{if .HasMaskedRequestContentTypes -}} + ContentType string + {{end -}} + {{$multipleBodies := gt (len .Bodies) 1 -}} + {{range .Bodies -}} + {{if $multipleBodies}}{{.NameTag}}{{end}}Body {{if eq .NameTag "Multipart"}}*multipart.Reader{{else if ne .NameTag ""}}*{{$opid}}{{.NameTag}}RequestBody{{else}}io.Reader{{end}} + {{end -}} + } + + type {{$opid | ucFirst}}ResponseObject interface { + Visit{{$opid}}Response(ctx *fiber.Ctx) error + } + + {{range .Responses}} + {{$statusCode := .StatusCode -}} + {{$hasHeaders := ne 0 (len .Headers) -}} + {{$fixedStatusCode := .HasFixedStatusCode -}} + {{$isRef := .IsRef -}} + {{$ref := .Ref | ucFirst -}} + {{$headers := .Headers -}} + + {{if (and $hasHeaders (not $isRef)) -}} + type {{$opid}}{{$statusCode}}ResponseHeaders struct { + {{range .Headers -}} + {{.GoName}} {{.Schema.TypeDecl}} + {{end -}} + } + {{end}} + + {{range .Contents}} + {{$receiverTypeName := printf "%s%s%s%s" $opid $statusCode .NameTagOrContentType "Response"}} + {{if and $fixedStatusCode $isRef -}} + type {{$receiverTypeName}} struct{ {{$ref}}{{.NameTagOrContentType}}Response } + {{else if and (not $hasHeaders) ($fixedStatusCode) (.IsSupported) -}} + type {{$receiverTypeName}} {{if eq .NameTag "Multipart"}}func(writer *multipart.Writer)error{{else if .IsSupported}}{{if .Schema.IsRef}}={{end}} {{.Schema.TypeDecl}}{{else}}io.Reader{{end}} + {{else -}} + type {{$receiverTypeName}} struct { + Body {{if eq .NameTag "Multipart"}}func(writer *multipart.Writer)error{{else if .IsSupported}}{{.Schema.TypeDecl}}{{else}}io.Reader{{end}} + {{if $hasHeaders -}} + Headers {{if $isRef}}{{$ref}}{{else}}{{$opid}}{{$statusCode}}{{end}}ResponseHeaders + {{end -}} + + {{if not $fixedStatusCode -}} + StatusCode int + {{end -}} + + {{if not .HasFixedContentType -}} + ContentType string + {{end -}} + + {{if not .IsSupported -}} + ContentLength int64 + {{end -}} + } + {{end}} + + func (response {{$receiverTypeName}}) Visit{{$opid}}Response(ctx *fiber.Ctx) error { + {{range $headers -}} + ctx.Response().Header.Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}})) + {{end -}} + {{if eq .NameTag "Multipart" -}} + writer := multipart.NewWriter(ctx.Response().BodyWriter()) + {{end -}} + ctx.Response().Header.Set("Content-Type", {{if eq .NameTag "Multipart"}}writer.FormDataContentType(){{else if .HasFixedContentType }}"{{.ContentType}}"{{else}}response.ContentType{{end}}) + {{if not .IsSupported -}} + if response.ContentLength != 0 { + ctx.Response().Header.Set("Content-Length", fmt.Sprint(response.ContentLength)) + } + {{end -}} + ctx.Status({{if $fixedStatusCode}}{{$statusCode}}{{else}}response.StatusCode{{end}}) + {{$hasBodyVar := or ($hasHeaders) (not $fixedStatusCode) (not .IsSupported)}} + {{if eq .NameTag "JSON" -}} + return ctx.JSON(&{{if $hasBodyVar}}response.Body{{else}}response{{end}}) + {{else if eq .NameTag "Text" -}} + _, err := ctx.WriteString(string({{if $hasBodyVar}}response.Body{{else}}response{{end}})) + return err + {{else if eq .NameTag "Formdata" -}} + if form, err := runtime.MarshalForm({{if $hasBodyVar}}response.Body{{else}}response{{end}}, nil); err != nil { + return err + } else { + _, err := ctx.WriteString(form.Encode()) + return err + } + {{else if eq .NameTag "Multipart" -}} + defer writer.Close() + return {{if $hasBodyVar}}response.Body{{else}}response{{end}}(writer); + {{else -}} + if closer, ok := response.Body.(io.ReadCloser); ok { + defer closer.Close() + } + _, err := io.Copy(ctx.Response().BodyWriter(), response.Body) + return err + {{end}}{{/* if eq .NameTag "JSON" */ -}} + } + {{end}} + + {{if eq 0 (len .Contents) -}} + {{if and $fixedStatusCode $isRef -}} + type {{$opid}}{{$statusCode}}Response = {{$ref}}Response + {{else -}} + type {{$opid}}{{$statusCode}}Response struct { + {{if $hasHeaders -}} + Headers {{if $isRef}}{{$ref}}{{else}}{{$opid}}{{$statusCode}}{{end}}ResponseHeaders + {{end}} + {{if not $fixedStatusCode -}} + StatusCode int + {{end -}} + } + {{end -}} + func (response {{$opid}}{{$statusCode}}Response) Visit{{$opid}}Response(ctx *fiber.Ctx) error { + {{range $headers -}} + ctx.Response().Header.Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}})) + {{end -}} + ctx.Status({{if $fixedStatusCode}}{{$statusCode}}{{else}}response.StatusCode{{end}}) + return nil + } + {{end}} + {{end}} +{{end}} + +// StrictServerInterface represents all server handlers. +type StrictServerInterface interface { +{{range .}}{{.SummaryAsComment }} +// ({{.Method}} {{.Path}}) +{{$opid := .OperationId -}} +{{$opid}}(ctx context.Context, request {{$opid | ucFirst}}RequestObject) ({{$opid | ucFirst}}ResponseObject, error) +{{end}}{{/* range . */ -}} +} diff --git a/pkg/codegen/templates/strict/strict-fiber.tmpl b/pkg/codegen/templates/strict/strict-fiber.tmpl new file mode 100644 index 0000000000..38a819f71b --- /dev/null +++ b/pkg/codegen/templates/strict/strict-fiber.tmpl @@ -0,0 +1,80 @@ +type StrictHandlerFunc func(ctx *fiber.Ctx, args interface{}) (interface{}, error) + +type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc + +func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface { + return &strictHandler{ssi: ssi, middlewares: middlewares} +} + +type strictHandler struct { + ssi StrictServerInterface + middlewares []StrictMiddlewareFunc +} + +{{range .}} + {{$opid := .OperationId}} + // {{$opid}} operation middleware + func (sh *strictHandler) {{.OperationId}}(ctx *fiber.Ctx{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params {{.OperationId}}Params{{end}}) error { + var request {{$opid | ucFirst}}RequestObject + + {{range .PathParams -}} + {{$varName := .GoVariableName -}} + request.{{.GoName}} = {{.GoVariableName}} + {{end -}} + + {{if .RequiresParamObject -}} + request.Params = params + {{end -}} + + {{ if .HasMaskedRequestContentTypes -}} + request.ContentType = string(ctx.Request().Header.ContentType()) + {{end -}} + + {{$multipleBodies := gt (len .Bodies) 1 -}} + {{range .Bodies -}} + {{if $multipleBodies}}if strings.HasPrefix(string(ctx.Request().Header.ContentType()), "{{.ContentType}}") { {{end}} + {{if eq .NameTag "JSON" -}} + var body {{$opid}}{{.NameTag}}RequestBody + if err := ctx.BodyParser(&body); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body + {{else if eq .NameTag "Formdata" -}} + var body {{$opid}}{{.NameTag}}RequestBody + if err := ctx.BodyParser(&body); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body + {{else if eq .NameTag "Multipart" -}} + request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = multipart.NewReader(bytes.NewReader(ctx.Request().Body()), string(ctx.Request().Header.MultipartFormBoundary())) + {{else if eq .NameTag "Text" -}} + data := ctx.Request().Body() + body := {{$opid}}{{.NameTag}}RequestBody(data) + request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body + {{else -}} + request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = bytes.NewReader(ctx.Request().Body()) + {{end}}{{/* if eq .NameTag "JSON" */ -}} + {{if $multipleBodies}}}{{end}} + {{end}}{{/* range .Bodies */}} + + handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.{{.OperationId}}(ctx.UserContext(), request.({{$opid | ucFirst}}RequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "{{.OperationId}}") + } + + response, err := handler(ctx, request) + + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } else if validResponse, ok := response.({{$opid | ucFirst}}ResponseObject); ok { + if err := validResponse.Visit{{$opid}}Response(ctx); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + } else if response != nil { + return fmt.Errorf("Unexpected response type: %T", response) + } + return nil + } +{{end}} diff --git a/pkg/codegen/utils_test.go b/pkg/codegen/utils_test.go index 0da9dfbedb..67765264cc 100644 --- a/pkg/codegen/utils_test.go +++ b/pkg/codegen/utils_test.go @@ -280,6 +280,23 @@ func TestSwaggerUriToGorillaUri(t *testing.T) { // TODO assert.Equal(t, "/path/{arg}/foo", SwaggerUriToGorillaUri("/path/{?arg*}/foo")) } +func TestSwaggerUriToFiberUri(t *testing.T) { + assert.Equal(t, "/path", SwaggerUriToFiberUri("/path")) + assert.Equal(t, "/path/:arg", SwaggerUriToFiberUri("/path/{arg}")) + assert.Equal(t, "/path/:arg1/:arg2", SwaggerUriToFiberUri("/path/{arg1}/{arg2}")) + assert.Equal(t, "/path/:arg1/:arg2/foo", SwaggerUriToFiberUri("/path/{arg1}/{arg2}/foo")) + + // Make sure all the exploded and alternate formats match too + assert.Equal(t, "/path/:arg/foo", SwaggerUriToFiberUri("/path/{arg}/foo")) + assert.Equal(t, "/path/:arg/foo", SwaggerUriToFiberUri("/path/{arg*}/foo")) + assert.Equal(t, "/path/:arg/foo", SwaggerUriToFiberUri("/path/{.arg}/foo")) + assert.Equal(t, "/path/:arg/foo", SwaggerUriToFiberUri("/path/{.arg*}/foo")) + assert.Equal(t, "/path/:arg/foo", SwaggerUriToFiberUri("/path/{;arg}/foo")) + assert.Equal(t, "/path/:arg/foo", SwaggerUriToFiberUri("/path/{;arg*}/foo")) + assert.Equal(t, "/path/:arg/foo", SwaggerUriToFiberUri("/path/{?arg}/foo")) + assert.Equal(t, "/path/:arg/foo", SwaggerUriToFiberUri("/path/{?arg*}/foo")) +} + func TestOrderedParamsFromUri(t *testing.T) { result := OrderedParamsFromUri("/path/{param1}/{.param2}/{;param3*}/foo") assert.EqualValues(t, []string{"param1", "param2", "param3"}, result) diff --git a/pkg/fiber-middleware/oapi_validate.go b/pkg/fiber-middleware/oapi_validate.go new file mode 100644 index 0000000000..ef30dd8f75 --- /dev/null +++ b/pkg/fiber-middleware/oapi_validate.go @@ -0,0 +1,196 @@ +// Package middleware implements middleware function for server implementations, +// which validates incoming HTTP requests to make sure that they conform to the given OAPI 3.0 specification. +// When OAPI validation fails on the request, we return an HTTP/400. +package middleware + +import ( + "context" + "errors" + "fmt" + "net/http" + "os" + "strings" + + "github.com/getkin/kin-openapi/openapi3" + "github.com/getkin/kin-openapi/openapi3filter" + "github.com/getkin/kin-openapi/routers" + "github.com/getkin/kin-openapi/routers/gorillamux" + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/adaptor" +) + +type ctxKeyFiberContext struct{} +type ctxKeyUserData struct{} + +// OapiValidatorFromYamlFile creates a validator middleware from a YAML file path +func OapiValidatorFromYamlFile(path string) (fiber.Handler, error) { + + data, err := os.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("error reading %s: %s", path, err) + } + + swagger, err := openapi3.NewLoader().LoadFromData(data) + if err != nil { + return nil, fmt.Errorf("error parsing %s as Swagger YAML: %s", + path, err) + } + + return OapiRequestValidator(swagger), nil +} + +// OapiRequestValidator is a fiber middleware function which validates incoming HTTP requests +// to make sure that they conform to the given OAPI 3.0 specification. When +// OAPI validation fails on the request, we return an HTTP/400 with error message +func OapiRequestValidator(swagger *openapi3.T) fiber.Handler { + return OapiRequestValidatorWithOptions(swagger, nil) +} + +// ErrorHandler is called when there is an error in validation +type ErrorHandler func(c *fiber.Ctx, message string, statusCode int) + +// MultiErrorHandler is called when oapi returns a MultiError type +type MultiErrorHandler func(openapi3.MultiError) error + +// Options to customize request validation. These are passed through to +// openapi3filter. +type Options struct { + Options openapi3filter.Options + ErrorHandler ErrorHandler + ParamDecoder openapi3filter.ContentParameterDecoder + UserData interface{} + MultiErrorHandler MultiErrorHandler +} + +// OapiRequestValidatorWithOptions creates a validator from a swagger object, with validation options +func OapiRequestValidatorWithOptions(swagger *openapi3.T, options *Options) fiber.Handler { + + router, err := gorillamux.NewRouter(swagger) + if err != nil { + panic(err) + } + + return func(c *fiber.Ctx) error { + + err := ValidateRequestFromContext(c, router, options) + if err != nil { + if options != nil && options.ErrorHandler != nil { + options.ErrorHandler(c, err.Error(), http.StatusBadRequest) + // in case the handler didn't internally call Abort, stop the chain + return nil + } else { + // note: I am not sure if this is the best way to handle this + return fiber.NewError(http.StatusBadRequest, err.Error()) + } + } + return c.Next() + } +} + +// ValidateRequestFromContext is called from the middleware above and actually does the work +// of validating a request. +func ValidateRequestFromContext(c *fiber.Ctx, router routers.Router, options *Options) error { + + r, err := adaptor.ConvertRequest(c, false) + if err != nil { + return err + } + + route, pathParams, err := router.FindRoute(r) + + // We failed to find a matching route for the request. + if err != nil { + switch e := err.(type) { + case *routers.RouteError: + // We've got a bad request, the path requested doesn't match + // either server, or path, or something. + return errors.New(e.Reason) + default: + // This should never happen today, but if our upstream code changes, + // we don't want to crash the server, so handle the unexpected error. + return fmt.Errorf("error validating route: %s", err.Error()) + } + } + + // Validate request + requestValidationInput := &openapi3filter.RequestValidationInput{ + Request: r, + PathParams: pathParams, + Route: route, + } + + // Pass the fiber context into the request validator, so that any callbacks + // which it invokes make it available. + requestContext := context.WithValue(context.Background(), ctxKeyFiberContext{}, c) //nolint:staticcheck + + if options != nil { + requestValidationInput.Options = &options.Options + requestValidationInput.ParamDecoder = options.ParamDecoder + requestContext = context.WithValue(requestContext, ctxKeyUserData{}, options.UserData) //nolint:staticcheck + } + + err = openapi3filter.ValidateRequest(requestContext, requestValidationInput) + if err != nil { + me := openapi3.MultiError{} + if errors.As(err, &me) { + errFunc := getMultiErrorHandlerFromOptions(options) + return errFunc(me) + } + + switch e := err.(type) { + case *openapi3filter.RequestError: + // We've got a bad request + // Split up the verbose error by lines and return the first one + // openapi errors seem to be multi-line with a decent message on the first + errorLines := strings.Split(e.Error(), "\n") + return fmt.Errorf("error in openapi3filter.RequestError: %s", errorLines[0]) + case *openapi3filter.SecurityRequirementsError: + return fmt.Errorf("error in openapi3filter.SecurityRequirementsError: %s", e.Error()) + default: + // This should never happen today, but if our upstream code changes, + // we don't want to crash the server, so handle the unexpected error. + return fmt.Errorf("error validating request: %s", err) + } + } + return nil +} + +// GetFiberContext gets the fiber context from within requests. It returns +// nil if not found or wrong type. +func GetFiberContext(c context.Context) *fiber.Ctx { + iface := c.Value(ctxKeyFiberContext{}) + if iface == nil { + return nil + } + + fiberCtx, ok := iface.(*fiber.Ctx) + if ok { + return fiberCtx + } + return nil +} + +func GetUserData(c context.Context) interface{} { + return c.Value(ctxKeyUserData{}) +} + +// getMultiErrorHandlerFromOptions attempts to get the MultiErrorHandler from the options. If it is not set, +// return a default handler +func getMultiErrorHandlerFromOptions(options *Options) MultiErrorHandler { + if options == nil { + return defaultMultiErrorHandler + } + + if options.MultiErrorHandler == nil { + return defaultMultiErrorHandler + } + + return options.MultiErrorHandler +} + +// defaultMultiErrorHandler returns a StatusBadRequest (400) and a list +// of all the errors. This method is called if there are no other +// methods defined on the options. +func defaultMultiErrorHandler(me openapi3.MultiError) error { + return fmt.Errorf("multiple errors encountered: %s", me) +} diff --git a/pkg/fiber-middleware/oapi_validate_test.go b/pkg/fiber-middleware/oapi_validate_test.go new file mode 100644 index 0000000000..9201e13fb8 --- /dev/null +++ b/pkg/fiber-middleware/oapi_validate_test.go @@ -0,0 +1,434 @@ +package middleware + +import ( + "bytes" + "context" + _ "embed" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "net/http/httptest" + "net/url" + "testing" + + "github.com/getkin/kin-openapi/openapi3" + "github.com/getkin/kin-openapi/openapi3filter" + "github.com/gofiber/fiber/v2" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +//go:embed test_spec.yaml +var testSchema []byte + +func doGet(t *testing.T, app *fiber.App, rawURL string) *http.Response { + t.Helper() + + u, err := url.Parse(rawURL) + if err != nil { + t.Fatalf("invalid URL %q: %v", rawURL, err) + } + + req := httptest.NewRequest("GET", u.RequestURI(), nil) + req.Header.Add("Accept", "application/json") + req.Host = u.Host + + r, err := app.Test(req) + if err != nil { + t.Fatalf("Failed to test request, URL=%q: %v", rawURL, err) + } + + return r +} + +func doPost(t *testing.T, app *fiber.App, rawURL string, jsonBody interface{}) *http.Response { + t.Helper() + + u, err := url.Parse(rawURL) + if err != nil { + t.Fatalf("invalid url %q: %v", rawURL, err) + } + + buf, err := json.Marshal(jsonBody) + if err != nil { + t.Fatalf("failed to marshal: %v", err) + } + + req := httptest.NewRequest("POST", u.RequestURI(), bytes.NewReader(buf)) + req.Header.Add("Accept", "application/json") + req.Header.Add("Content-Type", "application/json") + req.Host = u.Host + + r, err := app.Test(req) + if err != nil { + t.Fatalf("Failed to test request, URL=%q: %v", rawURL, err) + } + + return r +} + +func TestOapiRequestValidator(t *testing.T) { + + swagger, err := openapi3.NewLoader().LoadFromData(testSchema) + require.NoError(t, err, "Error initializing swagger") + + // Create a new fiber router + app := fiber.New() + + // Set up an authenticator to check authenticated function. It will allow + // access to "someScope", but disallow others. + options := Options{ + ErrorHandler: func(c *fiber.Ctx, message string, statusCode int) { + _ = c.Status(statusCode).SendString("test: " + message) + }, + Options: openapi3filter.Options{ + AuthenticationFunc: func(c context.Context, input *openapi3filter.AuthenticationInput) error { + // The fiber context should be propagated into here. + gCtx := GetFiberContext(c) + assert.NotNil(t, gCtx) + // As should user data + assert.EqualValues(t, "hi!", GetUserData(c)) + + for _, s := range input.Scopes { + if s == "someScope" { + return nil + } + if s == "unauthorized" { + return errors.New("unauthorized") + } + } + return errors.New("forbidden") + }, + }, + UserData: "hi!", + } + + // Install our OpenApi based request validator + app.Use(OapiRequestValidatorWithOptions(swagger, &options)) + + called := false + + // Install a request handler for /resource. We want to make sure it doesn't + // get called. + app.Get("/resource", func(c *fiber.Ctx) error { + called = true + return nil + }) + // Let's send the request to the wrong server, this should fail validation + { + res := doGet(t, app, "https://not.deepmap.ai/resource") + assert.Equal(t, http.StatusBadRequest, res.StatusCode) + assert.False(t, called, "Handler should not have been called") + } + + // Let's send a good request, it should pass + { + res := doGet(t, app, "https://deepmap.ai/resource") + assert.Equal(t, http.StatusOK, res.StatusCode) + assert.True(t, called, "Handler should have been called") + called = false + } + + // Send an out-of-spec parameter + { + res := doGet(t, app, "https://deepmap.ai/resource?id=500") + assert.Equal(t, http.StatusBadRequest, res.StatusCode) + assert.False(t, called, "Handler should not have been called") + called = false + } + + // Send a bad parameter type + { + res := doGet(t, app, "https://deepmap.ai/resource?id=foo") + assert.Equal(t, http.StatusBadRequest, res.StatusCode) + assert.False(t, called, "Handler should not have been called") + called = false + } + + // Add a handler for the POST message + app.Post("/resource", func(c *fiber.Ctx) error { + called = true + return c.SendStatus(http.StatusNoContent) + }) + + called = false + // Send a good request body + { + body := struct { + Name string `json:"name"` + }{ + Name: "Marcin", + } + res := doPost(t, app, "https://deepmap.ai/resource", body) + assert.Equal(t, http.StatusNoContent, res.StatusCode) + assert.True(t, called, "Handler should have been called") + called = false + } + + // Send a malformed body + { + body := struct { + Name int `json:"name"` + }{ + Name: 7, + } + res := doPost(t, app, "https://deepmap.ai/resource", body) + assert.Equal(t, http.StatusBadRequest, res.StatusCode) + assert.False(t, called, "Handler should not have been called") + called = false + } + + app.Get("/protected_resource", func(c *fiber.Ctx) error { + called = true + return c.SendStatus(http.StatusNoContent) + }) + + // Call a protected function to which we have access + { + res := doGet(t, app, "https://deepmap.ai/protected_resource") + assert.Equal(t, http.StatusNoContent, res.StatusCode) + assert.True(t, called, "Handler should have been called") + called = false + } + + app.Get("/protected_resource2", func(c *fiber.Ctx) error { + called = true + return c.SendStatus(http.StatusNoContent) + }) + // Call a protected function to which we don't have access + { + res := doGet(t, app, "https://deepmap.ai/protected_resource2") + assert.Equal(t, http.StatusBadRequest, res.StatusCode) + assert.False(t, called, "Handler should not have been called") + called = false + } + + app.Get("/protected_resource_401", func(c *fiber.Ctx) error { + called = true + return c.SendStatus(http.StatusNoContent) + }) + // Call a protected function without credentials + { + res := doGet(t, app, "https://deepmap.ai/protected_resource_401") + assert.Equal(t, http.StatusBadRequest, res.StatusCode) + body, err := io.ReadAll(res.Body) + if assert.NoError(t, err) { + assert.Equal(t, "test: error in openapi3filter.SecurityRequirementsError: security requirements failed: unauthorized", string(body)) + } + assert.False(t, called, "Handler should not have been called") + called = false + } +} + +func TestOapiRequestValidatorWithOptionsMultiError(t *testing.T) { + swagger, err := openapi3.NewLoader().LoadFromData(testSchema) + require.NoError(t, err, "Error initializing swagger") + + app := fiber.New() + + // Set up an authenticator to check authenticated function. It will allow + // access to "someScope", but disallow others. + options := Options{ + Options: openapi3filter.Options{ + ExcludeRequestBody: false, + ExcludeResponseBody: false, + IncludeResponseStatus: true, + MultiError: true, + }, + } + + // register middleware + app.Use(OapiRequestValidatorWithOptions(swagger, &options)) + + called := false + + // Install a request handler for /resource. We want to make sure it doesn't + // get called. + app.Get("/multiparamresource", func(c *fiber.Ctx) error { + called = true + return nil + }) + + // Let's send a good request, it should pass + { + res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=50&id2=50") + assert.Equal(t, http.StatusOK, res.StatusCode) + assert.True(t, called, "Handler should have been called") + called = false + } + + // Let's send a request with a missing parameter, it should return + // a bad status + { + res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=50") + assert.Equal(t, http.StatusBadRequest, res.StatusCode) + body, err := io.ReadAll(res.Body) + if assert.NoError(t, err) { + assert.Contains(t, string(body), "multiple errors encountered") + assert.Contains(t, string(body), "parameter \"id2\"") + assert.Contains(t, string(body), "value is required but missing") + } + assert.False(t, called, "Handler should not have been called") + called = false + } + + // Let's send a request with a 2 missing parameters, it should return + // a bad status + { + res := doGet(t, app, "https://deepmap.ai/multiparamresource") + assert.Equal(t, http.StatusBadRequest, res.StatusCode) + body, err := io.ReadAll(res.Body) + if assert.NoError(t, err) { + assert.Contains(t, string(body), "multiple errors encountered") + assert.Contains(t, string(body), "parameter \"id\"") + assert.Contains(t, string(body), "value is required but missing") + assert.Contains(t, string(body), "parameter \"id2\"") + assert.Contains(t, string(body), "value is required but missing") + } + assert.False(t, called, "Handler should not have been called") + called = false + } + + // Let's send a request with a 1 missing parameter, and another outside + // or the parameters. It should return a bad status + { + res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=500") + assert.Equal(t, http.StatusBadRequest, res.StatusCode) + body, err := io.ReadAll(res.Body) + if assert.NoError(t, err) { + assert.Contains(t, string(body), "multiple errors encountered") + assert.Contains(t, string(body), "parameter \"id\"") + assert.Contains(t, string(body), "number must be at most 100") + assert.Contains(t, string(body), "parameter \"id2\"") + assert.Contains(t, string(body), "value is required but missing") + } + assert.False(t, called, "Handler should not have been called") + called = false + } + + // Let's send a request with a parameters that do not meet spec. It should + // return a bad status + { + res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=abc&id2=1") + assert.Equal(t, http.StatusBadRequest, res.StatusCode) + body, err := io.ReadAll(res.Body) + if assert.NoError(t, err) { + assert.Contains(t, string(body), "multiple errors encountered") + assert.Contains(t, string(body), "parameter \"id\"") + assert.Contains(t, string(body), "value abc: an invalid integer: invalid syntax") + assert.Contains(t, string(body), "parameter \"id2\"") + assert.Contains(t, string(body), "number must be at least 10") + } + assert.False(t, called, "Handler should not have been called") + called = false + } +} + +func TestOapiRequestValidatorWithOptionsMultiErrorAndCustomHandler(t *testing.T) { + swagger, err := openapi3.NewLoader().LoadFromData(testSchema) + require.NoError(t, err, "Error initializing swagger") + + app := fiber.New() + + // Set up an authenticator to check authenticated function. It will allow + // access to "someScope", but disallow others. + options := Options{ + Options: openapi3filter.Options{ + ExcludeRequestBody: false, + ExcludeResponseBody: false, + IncludeResponseStatus: true, + MultiError: true, + }, + MultiErrorHandler: func(me openapi3.MultiError) error { + return fmt.Errorf("Bad stuff - %s", me.Error()) + }, + } + + // register middleware + app.Use(OapiRequestValidatorWithOptions(swagger, &options)) + + called := false + + // Install a request handler for /resource. We want to make sure it doesn't + // get called. + app.Get("/multiparamresource", func(c *fiber.Ctx) error { + called = true + return nil + }) + + // Let's send a good request, it should pass + { + res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=50&id2=50") + assert.Equal(t, http.StatusOK, res.StatusCode) + assert.True(t, called, "Handler should have been called") + called = false + } + + // Let's send a request with a missing parameter, it should return + // a bad status + { + res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=50") + assert.Equal(t, http.StatusBadRequest, res.StatusCode) + body, err := io.ReadAll(res.Body) + if assert.NoError(t, err) { + assert.Contains(t, string(body), "Bad stuff") + assert.Contains(t, string(body), "parameter \"id2\"") + assert.Contains(t, string(body), "value is required but missing") + } + assert.False(t, called, "Handler should not have been called") + called = false + } + + // Let's send a request with a 2 missing parameters, it should return + // a bad status + { + res := doGet(t, app, "https://deepmap.ai/multiparamresource") + assert.Equal(t, http.StatusBadRequest, res.StatusCode) + body, err := io.ReadAll(res.Body) + if assert.NoError(t, err) { + assert.Contains(t, string(body), "Bad stuff") + assert.Contains(t, string(body), "parameter \"id\"") + assert.Contains(t, string(body), "value is required but missing") + assert.Contains(t, string(body), "parameter \"id2\"") + assert.Contains(t, string(body), "value is required but missing") + } + assert.False(t, called, "Handler should not have been called") + called = false + } + + // Let's send a request with a 1 missing parameter, and another outside + // or the parameters. It should return a bad status + { + res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=500") + assert.Equal(t, http.StatusBadRequest, res.StatusCode) + body, err := io.ReadAll(res.Body) + if assert.NoError(t, err) { + assert.Contains(t, string(body), "Bad stuff") + assert.Contains(t, string(body), "parameter \"id\"") + assert.Contains(t, string(body), "number must be at most 100") + assert.Contains(t, string(body), "parameter \"id2\"") + assert.Contains(t, string(body), "value is required but missing") + } + assert.False(t, called, "Handler should not have been called") + called = false + } + + // Let's send a request with a parameters that do not meet spec. It should + // return a bad status + { + res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=abc&id2=1") + assert.Equal(t, http.StatusBadRequest, res.StatusCode) + body, err := io.ReadAll(res.Body) + if assert.NoError(t, err) { + assert.Contains(t, string(body), "Bad stuff") + assert.Contains(t, string(body), "parameter \"id\"") + assert.Contains(t, string(body), "value abc: an invalid integer: invalid syntax") + assert.Contains(t, string(body), "parameter \"id2\"") + assert.Contains(t, string(body), "number must be at least 10") + } + assert.False(t, called, "Handler should not have been called") + called = false + } +} diff --git a/pkg/fiber-middleware/test_spec.yaml b/pkg/fiber-middleware/test_spec.yaml new file mode 100644 index 0000000000..6e0a2415d2 --- /dev/null +++ b/pkg/fiber-middleware/test_spec.yaml @@ -0,0 +1,103 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: TestServer +servers: + - url: http://deepmap.ai/ +paths: + /resource: + get: + operationId: getResource + parameters: + - name: id + in: query + schema: + type: integer + minimum: 10 + maximum: 100 + responses: + '200': + description: success + content: + application/json: + schema: + properties: + name: + type: string + id: + type: integer + post: + operationId: createResource + responses: + '204': + description: No content + requestBody: + required: true + content: + application/json: + schema: + properties: + name: + type: string + /protected_resource: + get: + operationId: getProtectedResource + security: + - BearerAuth: + - someScope + responses: + '204': + description: no content + /protected_resource2: + get: + operationId: getProtectedResource + security: + - BearerAuth: + - otherScope + responses: + '204': + description: no content + /protected_resource_401: + get: + operationId: getProtectedResource + security: + - BearerAuth: + - unauthorized + responses: + '401': + description: no content + /multiparamresource: + get: + operationId: getResource + parameters: + - name: id + in: query + required: true + schema: + type: integer + minimum: 10 + maximum: 100 + - name: id2 + required: true + in: query + schema: + type: integer + minimum: 10 + maximum: 100 + responses: + '200': + description: success + content: + application/json: + schema: + properties: + name: + type: string + id: + type: integer +components: + securitySchemes: + BearerAuth: + type: http + scheme: bearer + bearerFormat: JWT