From ea3ecff1c557786bc52d71db65d7f9be026e4048 Mon Sep 17 00:00:00 2001 From: Robert Weber Date: Thu, 8 Aug 2019 15:39:37 -0600 Subject: [PATCH] Add support for external references External references will be encapsulated in a package as described by the --extrefs argument. Automatically adds import paths to appropriate generated files. Remove this commit Revert "Add support for external references" Revert "Revert "Add support for external references"" Insecure get of remote refs Gen code with external refs works Enable use of go-decode for "oneOf" structs that have discriptors For replies that don't have types via ref's don't use decode.Decodeable Added tests for the decodable oneOf stuff for both refs and non-refs Use the enum for the type that is the discriptor for the mapping between types. Remove the references to the hidden fork for now Remove the decodable type * use the *interface{} vs interface{} to determine if fields are decodable. * change the Discriminator() function to return the key in the map that is used for discrimination as it is useful to have. * In the case an enum is not specified use the PascalCase as the type value DO NOT MERGE THIS CHANGE UPSTREAM... Makes it work in gitlab only Added pre-loading of remote schemas to 'automatically' generate mappings of useful, common schemas to their go types and imports. Changed to parse out user specified package name Changed to parse out user specified package name Changed to parse out user specified package name in tpe import clean references to gitlab packages refactor typeMap to be a map of TypeImportSpec - a 3-tuple of type, package, import path templates are simple again Added a couple of tests removed replace statements added support for local(nested) oneOf - required adding mapping between a path and a discriminator added generation of implementaion of DecoderDesc interface defined in go-decode moved test strings to files in testdata directory added tests for nested oneOf Added to template context object - required due to support for local/nested oneOf Added to Decorator object for the same reasons Added utility function missed change from master Added pre-loading of remote schemas to 'automatically' generate mappings of useful, common schemas to their go types and imports. changed to use function factories added some missing checks to schema processing of oneOf Support multi-level inheritance of common refs Some spec files that have interitance may not have paths. Fix external refs that have external refs The remote load of the external ref needs to have allowRefs passed do it so that load doesn't bomb when it loads the ref. Fixed schema processing in case of reference types Now generating error if a oneOf is defined inside an anonymous schema added more complex schemas to ensure no regression Use local fork of kin-openapi -- DO NOT MERGE UPSTREAM Added pre-loading of remote schemas to 'automatically' generate mappings of useful, common schemas to their go types and imports. Changed to parse out user specified package name in tpe import rebase with master Use local fork of kin-openapi -- DO NOT MERGE UPSTREAM Fix for seg fault while processing oneOf bugfix/ind-3231: added code that detemines whether a discriminator property is defined as a required property and generates the correct constructor as a result Test found under internal/test/issues/issue-f5-3231 introduce context, change template functions to use context This is a first step on a bigger refactoring effort that will make use of the provided parse tree as it were updated to use our fork of kin-openapi in github feature: updated to use our fork of kin-openapi in github restored old TypeFactory to satisfy old decode.Decode calls fixed regression in go.mod - pointing to kin-openapi 0.2.2 fix: Update go.mod with a kin-openapi that merges remote refs Addresses bug https://nginxsoftware.atlassian.net/browse/IND-3824 fix: don't overwrite the mappings for import package refs import packages must be specified in most general -> least general for this to work Move to the Metadata build Parent struct generates child oneOf decorators changed to point to kin-openapi 0.2.5 and using the functionality there changed inline.tmpl to provide a function that returns the JSON schema as a string tests are incoming added code to generate struct tags containing property's default value when specified in schema re-added test to ensure defaults are not generated for array types fixed a bug related to resolved-spec - generating operation definitions is not necessary when doing that When processing a highly nested schema with oneOf this triggers a failure, but since there's no code being generated, this is not needed Fix Embedd spec arg restrictions * resolved-spec is the only case that generates and error when used with others * only disable operations when the spec is resolved fix: generate client with interface for HTTPClient fix: Update client interface helper function, update internal test code fix: add generate target According to https://github.com/deepmap/oapi-codegen, "When you update any of the files under the templates/ directory, you will need to regenerate the template inlines: go generate ./pkg/codegen/templates 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." Without running go generate twice, the files may not be updated, resulting in the unit tests running against generated files that don't contain the most recent changes. The code generation has been moved to a separate target that also runs goimports -w. .gitignore has been updated to include the test output files. fix: escape/unescape path and query params The runtime library has been updated to escape path and query parameters in the client code and unescape the parameters in the server code. Since these are the first changes made to the runtime library, the generator has been updated to use the forked copy of the runtime package instead of the original 1.3.0 tagged version. chore: repo-index fix Update CODEOWNERS.md --- .gitignore | 6 +- .golangci.yml | 11 + Makefile | 83 +- README.md | 4 +- cmd/oapi-codegen/oapi-codegen.go | 145 +- .../petstore-expanded/chi/api/petstore.gen.go | 18 +- .../echo/api/petstore-server.gen.go | 12 +- .../echo/api/petstore-types.gen.go | 16 +- examples/petstore-expanded/echo/petstore.go | 3 +- .../petstore-expanded/echo/petstore_test.go | 3 + examples/petstore-expanded/internal/doc.go | 5 +- .../petstore-expanded/petstore-client.gen.go | 19 +- go.mod | 17 +- go.sum | 51 +- internal/test/client/client.gen.go | 989 ------ internal/test/client/doc.go | 3 +- internal/test/components/components.gen.go | 1183 ------- internal/test/components/doc.go | 2 +- internal/test/issues/issue-52/issue.gen.go | 1 - internal/test/issues/issue-f5-3231/doc.go | 3 + .../test/issues/issue-f5-3231/issue.gen.go | 170 + .../test/issues/issue-f5-3231/issue_test.go | 31 + internal/test/issues/issue-f5-3231/spec.yaml | 41 + internal/test/parameters/doc.go | 2 +- internal/test/parameters/parameters.gen.go | 2869 ----------------- internal/test/parameters/parameters_test.go | 2 +- internal/test/schemas/doc.go | 2 +- internal/test/schemas/schemas.gen.go | 612 ---- internal/test/server/server.gen.go | 2 +- pkg/codegen/codegen.go | 271 +- pkg/codegen/codegen_test.go | 433 ++- pkg/codegen/inline.go | 2 +- pkg/codegen/operations.go | 109 +- pkg/codegen/operations_test.go | 44 +- pkg/codegen/schema.go | 192 +- pkg/codegen/template_helpers.go | 64 +- .../templates/additional-properties.tmpl | 70 + .../templates/client-with-responses.tmpl | 33 +- pkg/codegen/templates/client.tmpl | 35 +- pkg/codegen/templates/imports.tmpl | 4 +- pkg/codegen/templates/inline.tmpl | 29 +- pkg/codegen/templates/param-types.tmpl | 2 +- pkg/codegen/templates/register.tmpl | 2 +- pkg/codegen/templates/request-bodies.tmpl | 2 +- pkg/codegen/templates/templates.gen.go | 195 +- pkg/codegen/templates/typedef.tmpl | 2 +- pkg/codegen/templates/wrappers.tmpl | 14 +- .../testdata/failedOneOfAnonymousSchema.yaml | 90 + .../failedOneOfMissingDiscriminator.yaml | 152 + pkg/codegen/testdata/included.yaml | 19 + pkg/codegen/testdata/pets.golden | 784 +++++ pkg/codegen/testdata/pets.yaml | 343 ++ .../testdata/testOpenAPIDefinition.golden | 399 +++ .../testdata/testOpenAPIDefinition.yaml | 122 + ...tionWithOneOfDiscriminatorsAndEnums.golden | 627 ++++ ...nitionWithOneOfDiscriminatorsAndEnums.yaml | 184 ++ .../testdata/testResolvingSpec.json.golden | 114 + pkg/codegen/testdata/testResolvingSpec.yaml | 52 + pkg/codegen/utils.go | 66 +- pkg/codegen/utils_test.go | 124 +- pkg/middleware/oapi_validate.go | 4 +- pkg/middleware/oapi_validate_test.go | 2 +- pkg/runtime/bindparam.go | 44 +- pkg/runtime/bindparam_test.go | 93 + pkg/runtime/bindstring.go | 13 +- pkg/runtime/bindstring_test.go | 73 +- pkg/runtime/styleparam.go | 27 +- pkg/runtime/styleparam_test.go | 335 +- pkg/types/date_test.go | 4 +- pkg/util/loader.go | 67 +- 70 files changed, 5224 insertions(+), 6322 deletions(-) create mode 100644 .golangci.yml delete mode 100644 internal/test/client/client.gen.go delete mode 100644 internal/test/components/components.gen.go create mode 100644 internal/test/issues/issue-f5-3231/doc.go create mode 100644 internal/test/issues/issue-f5-3231/issue.gen.go create mode 100644 internal/test/issues/issue-f5-3231/issue_test.go create mode 100644 internal/test/issues/issue-f5-3231/spec.yaml delete mode 100644 internal/test/parameters/parameters.gen.go delete mode 100644 internal/test/schemas/schemas.gen.go create mode 100644 pkg/codegen/testdata/failedOneOfAnonymousSchema.yaml create mode 100644 pkg/codegen/testdata/failedOneOfMissingDiscriminator.yaml create mode 100644 pkg/codegen/testdata/included.yaml create mode 100644 pkg/codegen/testdata/pets.golden create mode 100644 pkg/codegen/testdata/pets.yaml create mode 100644 pkg/codegen/testdata/testOpenAPIDefinition.golden create mode 100644 pkg/codegen/testdata/testOpenAPIDefinition.yaml create mode 100644 pkg/codegen/testdata/testOpenAPIDefinitionWithOneOfDiscriminatorsAndEnums.golden create mode 100644 pkg/codegen/testdata/testOpenAPIDefinitionWithOneOfDiscriminatorsAndEnums.yaml create mode 100644 pkg/codegen/testdata/testResolvingSpec.json.golden create mode 100644 pkg/codegen/testdata/testResolvingSpec.yaml diff --git a/.gitignore b/.gitignore index f0b76c07e..c56fb65bb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ .idea .DS_Store -.vscode/ \ No newline at end of file +.vscode/ +coverage-all.out +coverage.out +test-coverage.html +test-results.out diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 000000000..b5f9e4abd --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,11 @@ +linters: + enable-all: false + presets: + - bugs + - complexity + - unused + disable-all: false + disable: + - gochecknoinits + - dupl + - gochecknoglobals diff --git a/Makefile b/Makefile index dde643ba9..41096c461 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,81 @@ -help: - @echo "This is a helper makefile for oapi-codegen" - @echo "Targets:" - @echo " generate: regenerate all generated files" - @echo " test: run all tests" +# +# Makefile to build the Blue Secrets Service (Certificate Manager) +# +.PHONY: all lint test +.PHONY: debug-build debug +.PHONY: semver clean deps +.PHONY: int-test +# +# Constants and runtime variables +# +PACKAGE = oapi-codegen +PACKAGE_PATH = gitswarm.f5net.com/indigo/product/controller-thirdparty +FULL_PACKAGE = $(PACKAGE_PATH)/$(PACKAGE) +GO_PKGS = $(shell go list ./... | grep -v test) +GO_PKGS_PATH = $(shell go list -f '{{.Dir}}' ./... | grep -v test) +DOCKER_TAG ?= latest +OUT_DIR ?= build +DEBUG_PACKAGE = $(PACKAGE)-debug + + +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +MKFILE_DIR := $(dir $(MKFILE_PATH)) +INTEGRATION_DIR = "$(MKFILE_DIR)/test/integration" + +TEST_TOOL_NAME = "test_tool.sh" +TEST_TOOL = "$(INTEGRATION_DIR)/$(TEST_TOOL_NAME)" + +# +# Targets used for local development +# +all: test lint + +export OUT_DIR + +clean: + rm -rf ./build_version coverage* test-coverage.html ./deploy test-results.out \ + unit_tests.xml full-lint-report.xml $(OUT_DIR) + +# +# Generate the template inline files and *.gen.go files +# generate: go generate ./pkg/... go generate ./... + goimports -w ./ + +# +# Run all tests and aggregate results into single coverage output. +# TODO: want to include -race flag with go test. +# +ifdef VERBOSE +test: generate + @echo "mode: set" > coverage-all.out + + @go test -v -timeout 30s -tags unit -coverprofile=coverage.out -race ./... | \ + tee -a test-results.out || exit 1 \ + tail -n +2 coverage.out >> coverage-all.out || exit 1 + @go tool cover -func=coverage-all.out && \ + go tool cover -html=coverage-all.out -o test-coverage.html +else +test: generate + @echo "mode: set" > coverage-all.out + + @go test -timeout 30s -tags unit -coverprofile=coverage.out -race ./... | \ + tee -a test-results.out || exit 1;\ + tail -n +2 coverage.out >> coverage-all.out || exit 1 + @go tool cover -html=coverage-all.out -o test-coverage.html +endif + +# +# Utilities targets +# +# run: +# $(OUT_DIR)/$(PACKAGE) +# +# Lint go code non-critical checks +# +lint: + echo "ignoring lint on this project" -test: - go test -cover ./... diff --git a/README.md b/README.md index a260248db..14261392b 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ write a lot of boilerplate code to perform all the marshalling and unmarshalling 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 get github.com/deepmap/oapi-codegen/cmd/oapi-codegen + go get github.com/weberr13/oapi-codegen/cmd/oapi-codegen oapi-codegen petstore-expanded.yaml > petstore.gen.go Let's go through that `petstore.gen.go` file to show you everything which was @@ -454,4 +454,4 @@ Go file. Afterwards you should run `go generate ./...`, and the templates will be updated accordingly. - +> diff --git a/cmd/oapi-codegen/oapi-codegen.go b/cmd/oapi-codegen/oapi-codegen.go index 1a1b080aa..d59947c16 100644 --- a/cmd/oapi-codegen/oapi-codegen.go +++ b/cmd/oapi-codegen/oapi-codegen.go @@ -17,12 +17,13 @@ import ( "flag" "fmt" "io/ioutil" + "net/url" "os" "path/filepath" "strings" - "github.com/deepmap/oapi-codegen/pkg/codegen" - "github.com/deepmap/oapi-codegen/pkg/util" + "github.com/weberr13/oapi-codegen/pkg/codegen" + "github.com/weberr13/oapi-codegen/pkg/util" ) func errExit(format string, args ...interface{}) { @@ -30,6 +31,38 @@ func errExit(format string, args ...interface{}) { os.Exit(1) } +func usageErr(format string, args ...interface{}) { + _, _ = fmt.Fprintf(os.Stderr, format, args...) + flag.PrintDefaults() + os.Exit(1) +} + +// TODO define a type to allow recording of Type -> Import Path as args +// TODO this is temporary until we sort the config question +type refImports []string + +func (ri *refImports) String() string { + return "Reference Import arg" +} + +func (ri *refImports) Set(r string) error { + *ri = append(*ri, r) + return nil +} + +// TODO define a type to allow recording of package -> Import Path as args +// TODO this is temporary until we sort the config question +type pkgImports []string + +func (pi *pkgImports) String() string { + return "Pkg Import arg" +} + +func (pi *pkgImports) Set(r string) error { + *pi = append(*pi, r) + return nil +} + func main() { var ( packageName string @@ -37,13 +70,21 @@ func main() { outputFile string includeTags string excludeTags string + refImports refImports + pkgImports pkgImports + allowRefs bool + insecure bool ) + flag.StringVar(&packageName, "package", "", "The package name for generated code") flag.StringVar(&generate, "generate", "types,client,server,spec", `Comma-separated list of code to generate; valid options: "types", "client", "chi-server", "server", "skip-fmt", "spec"`) flag.StringVar(&outputFile, "o", "", "Where to output generated code, stdout is default") flag.StringVar(&includeTags, "include-tags", "", "Only include operations with the given tags. Comma-separated list of tags.") - flag.StringVar(&excludeTags, "exclude-tags", "", "Exclude operations that are tagged with the given tags. Comma-separated list of tags.") + flag.Var(&refImports, "ri", "Repeated reference import statements of the form Type=<[package:]import path>") + flag.Var(&pkgImports, "pi", "Repeated package import statements of the form =<[package:]import path>") + flag.BoolVar(&allowRefs, "extrefs", false, "Allow resolving external references") + flag.BoolVar(&insecure, "insecure", false, "Allow resolving remote URL's that have bad SSL/TLS") flag.Parse() if flag.NArg() < 1 { @@ -76,10 +117,12 @@ func main() { opts.EmbedSpec = true case "skip-fmt": opts.SkipFmt = true + case "resolved-spec": + opts.ClearRefsSpec = true + opts.EmbedSpec = true default: - fmt.Printf("unknown generate option %s\n", g) - flag.PrintDefaults() - os.Exit(1) + // never returns + usageErr("unknown generate option %s\n", g) } } @@ -90,9 +133,21 @@ func main() { errExit("can not specify both server and chi-server targets simultaneously") } - swagger, err := util.LoadSwagger(flag.Arg(0)) + if opts.ClearRefsSpec && (opts.GenerateClient || opts.GenerateServer || opts.GenerateTypes) { + // never returns + usageErr("resolved-spec option is only valid when specified on its own") + } + + // Add user defined type -> import mapping + opts.ImportedTypes = importPackages(pkgImports, allowRefs, insecure) + // override with specific imports if so indicated + for k, v := range importTypes(refImports) { + opts.ImportedTypes[k] = v + } + + swagger, err := util.LoadSwagger(flag.Arg(0), allowRefs, insecure, opts.ClearRefsSpec) if err != nil { - errExit("error loading swagger spec\n: %s", err) + errExit("error loading swagger spec:\n%s\n", err) } code, err := codegen.Generate(swagger, packageName, opts) @@ -103,7 +158,7 @@ func main() { if outputFile != "" { err = ioutil.WriteFile(outputFile, []byte(code), 0644) if err != nil { - errExit("error writing generated code to file: %s", err) + errExit("error writing generated code to file: %s\n", err) } } else { fmt.Println(code) @@ -125,3 +180,75 @@ func splitCSVArg(input string) []string { } return args } + +func mapArgSlice(as []string, an string) map[string]string { + m := map[string]string{} + for _, ri := range as { + parts := strings.Split(ri, "=") + if len(parts) != 2 { + fmt.Printf("invalid %s arg. %s\n", an, ri) + flag.PrintDefaults() + os.Exit(1) + } + m[parts[0]] = parts[1] + } + return m +} + +func importPackages(imports pkgImports, allowRefs, insecure bool) map[string]codegen.TypeImportSpec { + importedTypes := map[string]codegen.TypeImportSpec{} + pi := mapArgSlice(imports, "package import") + + for sr, p := range pi { + var u *url.URL + var err error + + if u, err = url.Parse(sr); err != nil { + errExit("package import: specified schema ref is not a URL:\n%s\n", err) + } + swagger, err := util.LoadSwaggerFromURL(u, allowRefs, insecure) + if err != nil { + errExit("package import: error loading swagger spec:\n%s\n", err) + } + + // iterate over model to find schema names - extract only top level names + for n := range swagger.Components.Schemas { + if _, ok := importedTypes[n]; !ok { + importedTypes[n] = getImportedType(n, p) + } + } + } + return importedTypes +} + +func importTypes(typeImports refImports) map[string]codegen.TypeImportSpec { + importedTypes := map[string]codegen.TypeImportSpec{} + pi := mapArgSlice(typeImports, "type imports") + + for t, p := range pi { + importedTypes[t] = getImportedType(t, p) + } + return importedTypes +} + +func getImportedType(typeName, pkgImport string) codegen.TypeImportSpec { + var pkgName string + var impPath string + + // if a package name was specified in the form pkg:, use that, otherwise use last part of import path + parts := strings.Split(pkgImport, ":") + if len(parts) > 2 { + errExit("Parsing type import: too many fragments. At most one ':' expected (type:%s, import:%s)", typeName, pkgImport) + } + + if len(parts) == 2 { + pkgName = parts[0] + impPath = parts[1] + } else { + parts = strings.Split(pkgImport, "/") + pkgName = parts[len(parts)-1] + impPath = pkgImport + } + + return codegen.NewTypeImportSpec(typeName, pkgName, impPath) +} diff --git a/examples/petstore-expanded/chi/api/petstore.gen.go b/examples/petstore-expanded/chi/api/petstore.gen.go index 01b6d782b..a20881409 100644 --- a/examples/petstore-expanded/chi/api/petstore.gen.go +++ b/examples/petstore-expanded/chi/api/petstore.gen.go @@ -18,22 +18,14 @@ import ( // Error defines model for Error. type Error struct { - - // Error code - Code int32 `json:"code"` - - // Error message + Code int32 `json:"code"` Message string `json:"message"` } // NewPet defines model for NewPet. type NewPet struct { - - // Name of the pet - Name string `json:"name"` - - // Type of the pet - Tag *string `json:"tag,omitempty"` + Name string `json:"name"` + Tag *string `json:"tag,omitempty"` } // Pet defines model for Pet. @@ -41,8 +33,6 @@ type Pet struct { // Embedded struct due to allOf(#/components/schemas/NewPet) NewPet // Embedded fields due to inline allOf schema - - // Unique id of the pet Id int64 `json:"id"` } @@ -175,7 +165,7 @@ func Handler(si ServerInterface) http.Handler { } // HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux. -func HandlerFromMux(si ServerInterface, r chi.Router) http.Handler { +func HandlerFromMux(si ServerInterface, r *chi.Mux) http.Handler { r.Group(func(r chi.Router) { r.Use(FindPetsCtx) r.Get("/pets", si.FindPets) diff --git a/examples/petstore-expanded/echo/api/petstore-server.gen.go b/examples/petstore-expanded/echo/api/petstore-server.gen.go index 998cc552f..0ba521da7 100644 --- a/examples/petstore-expanded/echo/api/petstore-server.gen.go +++ b/examples/petstore-expanded/echo/api/petstore-server.gen.go @@ -17,17 +17,13 @@ import ( // ServerInterface represents all server handlers. type ServerInterface interface { - // Returns all pets - // (GET /pets) + // Returns all pets// (GET /pets) FindPets(ctx echo.Context, params FindPetsParams) error - // Creates a new pet - // (POST /pets) + // Creates a new pet// (POST /pets) AddPet(ctx echo.Context) error - // Deletes a pet by ID - // (DELETE /pets/{id}) + // Deletes a pet by ID// (DELETE /pets/{id}) DeletePet(ctx echo.Context, id int64) error - // Returns a pet by ID - // (GET /pets/{id}) + // Returns a pet by ID// (GET /pets/{id}) FindPetById(ctx echo.Context, id int64) error } diff --git a/examples/petstore-expanded/echo/api/petstore-types.gen.go b/examples/petstore-expanded/echo/api/petstore-types.gen.go index 652b41e34..79c6a2f25 100644 --- a/examples/petstore-expanded/echo/api/petstore-types.gen.go +++ b/examples/petstore-expanded/echo/api/petstore-types.gen.go @@ -5,22 +5,14 @@ package api // Error defines model for Error. type Error struct { - - // Error code - Code int32 `json:"code"` - - // Error message + Code int32 `json:"code"` Message string `json:"message"` } // NewPet defines model for NewPet. type NewPet struct { - - // Name of the pet - Name string `json:"name"` - - // Type of the pet - Tag *string `json:"tag,omitempty"` + Name string `json:"name"` + Tag *string `json:"tag,omitempty"` } // Pet defines model for Pet. @@ -28,8 +20,6 @@ type Pet struct { // Embedded struct due to allOf(#/components/schemas/NewPet) NewPet // Embedded fields due to inline allOf schema - - // Unique id of the pet Id int64 `json:"id"` } diff --git a/examples/petstore-expanded/echo/petstore.go b/examples/petstore-expanded/echo/petstore.go index af0ae8310..e41f3104f 100644 --- a/examples/petstore-expanded/echo/petstore.go +++ b/examples/petstore-expanded/echo/petstore.go @@ -11,9 +11,10 @@ import ( "os" "github.com/deepmap/oapi-codegen/examples/petstore-expanded/echo/api" - "github.com/deepmap/oapi-codegen/pkg/middleware" "github.com/labstack/echo/v4" echomiddleware "github.com/labstack/echo/v4/middleware" + "github.com/weberr13/oapi-codegen/examples/petstore-expanded/api" + "github.com/weberr13/oapi-codegen/pkg/middleware" ) func main() { diff --git a/examples/petstore-expanded/echo/petstore_test.go b/examples/petstore-expanded/echo/petstore_test.go index 17e6f3a20..bba72afc8 100644 --- a/examples/petstore-expanded/echo/petstore_test.go +++ b/examples/petstore-expanded/echo/petstore_test.go @@ -27,6 +27,9 @@ import ( "github.com/deepmap/oapi-codegen/examples/petstore-expanded/echo/api" "github.com/deepmap/oapi-codegen/pkg/middleware" "github.com/deepmap/oapi-codegen/pkg/testutil" + "github.com/weberr13/oapi-codegen/examples/petstore-expanded/api" + "github.com/weberr13/oapi-codegen/pkg/middleware" + "github.com/weberr13/oapi-codegen/pkg/testutil" ) func TestPetStore(t *testing.T) { diff --git a/examples/petstore-expanded/internal/doc.go b/examples/petstore-expanded/internal/doc.go index ac961b701..a7108816c 100644 --- a/examples/petstore-expanded/internal/doc.go +++ b/examples/petstore-expanded/internal/doc.go @@ -17,4 +17,7 @@ package internal // server. The file petstore.gen.go is automatically generated from the schema // Run oapi-codegen to regenerate the petstore boilerplate -//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --package=petstore --generate types,client -o ../petstore-client.gen.go ../petstore-expanded.yaml + +//go:generate go run github.com/weberr13/oapi-codegen/cmd/oapi-codegen --package=api --generate types -o ../petstore-types.gen.go ../petstore-expanded.yaml +//go:generate go run github.com/weberr13/oapi-codegen/cmd/oapi-codegen --package=api --generate server,spec -o ../petstore-server.gen.go ../petstore-expanded.yaml +//go:generate go run github.com/weberr13/oapi-codegen/cmd/oapi-codegen --package=api --generate client -o ../petstore-client.gen.go ../petstore-expanded.yaml diff --git a/examples/petstore-expanded/petstore-client.gen.go b/examples/petstore-expanded/petstore-client.gen.go index ea6050c1e..41bfa65bc 100644 --- a/examples/petstore-expanded/petstore-client.gen.go +++ b/examples/petstore-expanded/petstore-client.gen.go @@ -8,32 +8,25 @@ import ( "context" "encoding/json" "fmt" - "github.com/deepmap/oapi-codegen/pkg/runtime" "io" "io/ioutil" "net/http" "net/url" "strings" + + "github.com/deepmap/oapi-codegen/pkg/runtime" ) // Error defines model for Error. type Error struct { - - // Error code - Code int32 `json:"code"` - - // Error message + Code int32 `json:"code"` Message string `json:"message"` } // NewPet defines model for NewPet. type NewPet struct { - - // Name of the pet - Name string `json:"name"` - - // Type of the pet - Tag *string `json:"tag,omitempty"` + Name string `json:"name"` + Tag *string `json:"tag,omitempty"` } // Pet defines model for Pet. @@ -41,8 +34,6 @@ type Pet struct { // Embedded struct due to allOf(#/components/schemas/NewPet) NewPet // Embedded fields due to inline allOf schema - - // Unique id of the pet Id int64 `json:"id"` } diff --git a/go.mod b/go.mod index 9b3a89a3c..e3f81d694 100644 --- a/go.mod +++ b/go.mod @@ -1,23 +1,20 @@ -module github.com/deepmap/oapi-codegen +module github.com/weberr13/oapi-codegen require ( github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c + github.com/deepmap/oapi-codegen v1.3.4 github.com/getkin/kin-openapi v0.2.0 github.com/go-chi/chi v4.0.2+incompatible github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219 + github.com/iancoleman/strcase v0.0.0-20190422225806-e506e3ef7365 github.com/labstack/echo/v4 v4.1.11 github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd - github.com/mattn/go-colorable v0.1.4 // indirect - github.com/mattn/go-isatty v0.0.10 // indirect + github.com/onsi/gomega v1.7.0 github.com/pkg/errors v0.8.1 github.com/stretchr/testify v1.4.0 - github.com/valyala/fasttemplate v1.1.0 // indirect - golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708 // indirect - golang.org/x/net v0.0.0-20191112182307-2180aed22343 // indirect - golang.org/x/sys v0.0.0-20191115151921-52ab43148777 // indirect - golang.org/x/text v0.3.2 // indirect - golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f // indirect - gopkg.in/yaml.v2 v2.2.5 // indirect + golang.org/x/tools v0.0.0-20200203222849-174f5c63c9f5 // indirect ) go 1.13 + +replace github.com/getkin/kin-openapi => github.com/weberr13/kin-openapi v0.2.6 diff --git a/go.sum b/go.sum index eaf971195..72d622830 100644 --- a/go.sum +++ b/go.sum @@ -1,19 +1,27 @@ github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c h1:/ovYnF02fwL0kvspmy9AuyKg1JhdTRUgPw4nUxd9oZM= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deepmap/oapi-codegen v1.3.4 h1:T0wShRuw+Z4sdz5ETVojylZT9lEND/P28LZeps8xBac= +github.com/deepmap/oapi-codegen v1.3.4/go.mod h1:aBozjEveG+33xPiP55Iw/XbVkhtZHEGLq3nxlX0+hfU= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/getkin/kin-openapi v0.2.0 h1:PbHHtYZpjKwZtGlIyELgA2DploRrsaXztoNNx9HjwNY= -github.com/getkin/kin-openapi v0.2.0/go.mod h1:V1z9xl9oF5Wt7v32ne4FmiF1alpS4dM6mNzoywPOXlk= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-chi/chi v4.0.2+incompatible h1:maB6vn6FqCxrpz4FqWdh4+lwpyZIQS7YEAUcHlgXVRs= github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= +github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219 h1:utua3L2IbQJmauC5IXdEA547bcoU5dozgQAfc8Onsg4= github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/iancoleman/strcase v0.0.0-20190422225806-e506e3ef7365 h1:ECW73yc9MY7935nNYXUkK7Dz17YuSUI9yqRqYS8aBww= +github.com/iancoleman/strcase v0.0.0-20190422225806-e506e3ef7365/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= @@ -35,6 +43,15 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -56,33 +73,59 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49N golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708 h1:pXVtWnwHkrWD9ru3sDxY/qFK/bfc0egRovX91EjWjf4= golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +github.com/weberr13/kin-openapi v0.2.6 h1:8Oc6obWkJaWPe1fbWYtUGhQWjQw/Wfg3FlXt4GfebK0= +github.com/weberr13/kin-openapi v0.2.6/go.mod h1:V1z9xl9oF5Wt7v32ne4FmiF1alpS4dM6mNzoywPOXlk= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708 h1:pXVtWnwHkrWD9ru3sDxY/qFK/bfc0egRovX91EjWjf4= +golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191112182307-2180aed22343 h1:00ohfJ4K98s3m6BGUoBd8nyfp4Yl0GoIKvw5abItTjI= golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/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-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191115151921-52ab43148777 h1:wejkGHRTr38uaKRqECZlsCsJ1/TGxIyFbH32x5zUdu4= golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e h1:FDhOuMEY4JVRztM/gsbk+IKUQ8kj74bxZrgw87eMMVc= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f h1:kDxGY2VmgABOe55qheT/TFqUMtcTHnomIPS1iv3G4Ms= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +golang.org/x/tools v0.0.0-20200203222849-174f5c63c9f5 h1:b+tBIZFU87VKnTk6WXPq8InZqKyHmh/Q3dSYjCs7dhg= +golang.org/x/tools v0.0.0-20200203222849-174f5c63c9f5/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c= diff --git a/internal/test/client/client.gen.go b/internal/test/client/client.gen.go deleted file mode 100644 index 5965965b8..000000000 --- a/internal/test/client/client.gen.go +++ /dev/null @@ -1,989 +0,0 @@ -// Package client provides primitives to interact the openapi HTTP API. -// -// Code generated by github.com/deepmap/oapi-codegen DO NOT EDIT. -package client - -import ( - "bytes" - "compress/gzip" - "context" - "encoding/base64" - "encoding/json" - "fmt" - "github.com/getkin/kin-openapi/openapi3" - "github.com/labstack/echo/v4" - "io" - "io/ioutil" - "net/http" - "net/url" - "strings" -) - -// SchemaObject defines model for SchemaObject. -type SchemaObject struct { - FirstName string `json:"firstName"` - Role string `json:"role"` -} - -// PostBothJSONBody defines parameters for PostBoth. -type PostBothJSONBody SchemaObject - -// PostJsonJSONBody defines parameters for PostJson. -type PostJsonJSONBody SchemaObject - -// PostBothRequestBody defines body for PostBoth for application/json ContentType. -type PostBothJSONRequestBody PostBothJSONBody - -// PostJsonRequestBody defines body for PostJson for application/json ContentType. -type PostJsonJSONRequestBody PostJsonJSONBody - -// RequestEditorFn is the function signature for the RequestEditor callback function -type RequestEditorFn func(req *http.Request, ctx context.Context) 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. - Server string - - // Doer for performing requests, typically a *http.Client with any - // customized settings, such as certificate chains. - Client HttpRequestDoer - - // A callback for modifying requests which are generated before sending over - // the network. - RequestEditor 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 - } - } - // create httpClient, if not already present - if client.Client == nil { - client.Client = http.DefaultClient - } - 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.RequestEditor = fn - return nil - } -} - -// The interface specification for the client above. -type ClientInterface interface { - // PostBoth request with any body - PostBothWithBody(ctx context.Context, contentType string, body io.Reader) (*http.Response, error) - - PostBoth(ctx context.Context, body PostBothJSONRequestBody) (*http.Response, error) - - // GetBoth request - GetBoth(ctx context.Context) (*http.Response, error) - - // PostJson request with any body - PostJsonWithBody(ctx context.Context, contentType string, body io.Reader) (*http.Response, error) - - PostJson(ctx context.Context, body PostJsonJSONRequestBody) (*http.Response, error) - - // GetJson request - GetJson(ctx context.Context) (*http.Response, error) - - // PostOther request with any body - PostOtherWithBody(ctx context.Context, contentType string, body io.Reader) (*http.Response, error) - - // GetOther request - GetOther(ctx context.Context) (*http.Response, error) - - // GetJsonWithTrailingSlash request - GetJsonWithTrailingSlash(ctx context.Context) (*http.Response, error) -} - -func (c *Client) PostBothWithBody(ctx context.Context, contentType string, body io.Reader) (*http.Response, error) { - req, err := NewPostBothRequestWithBody(c.Server, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) PostBoth(ctx context.Context, body PostBothJSONRequestBody) (*http.Response, error) { - req, err := NewPostBothRequest(c.Server, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) GetBoth(ctx context.Context) (*http.Response, error) { - req, err := NewGetBothRequest(c.Server) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) PostJsonWithBody(ctx context.Context, contentType string, body io.Reader) (*http.Response, error) { - req, err := NewPostJsonRequestWithBody(c.Server, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) PostJson(ctx context.Context, body PostJsonJSONRequestBody) (*http.Response, error) { - req, err := NewPostJsonRequest(c.Server, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) GetJson(ctx context.Context) (*http.Response, error) { - req, err := NewGetJsonRequest(c.Server) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) PostOtherWithBody(ctx context.Context, contentType string, body io.Reader) (*http.Response, error) { - req, err := NewPostOtherRequestWithBody(c.Server, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) GetOther(ctx context.Context) (*http.Response, error) { - req, err := NewGetOtherRequest(c.Server) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) GetJsonWithTrailingSlash(ctx context.Context) (*http.Response, error) { - req, err := NewGetJsonWithTrailingSlashRequest(c.Server) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -// NewPostBothRequest calls the generic PostBoth builder with application/json body -func NewPostBothRequest(server string, body PostBothJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewPostBothRequestWithBody(server, "application/json", bodyReader) -} - -// NewPostBothRequestWithBody generates requests for PostBoth with any type of body -func NewPostBothRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { - var err error - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/with_both_bodies")) - 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 -} - -// NewGetBothRequest generates requests for GetBoth -func NewGetBothRequest(server string) (*http.Request, error) { - var err error - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/with_both_responses")) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryUrl.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewPostJsonRequest calls the generic PostJson builder with application/json body -func NewPostJsonRequest(server string, body PostJsonJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewPostJsonRequestWithBody(server, "application/json", bodyReader) -} - -// NewPostJsonRequestWithBody generates requests for PostJson with any type of body -func NewPostJsonRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { - var err error - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/with_json_body")) - 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 -} - -// NewGetJsonRequest generates requests for GetJson -func NewGetJsonRequest(server string) (*http.Request, error) { - var err error - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/with_json_response")) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryUrl.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewPostOtherRequestWithBody generates requests for PostOther with any type of body -func NewPostOtherRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { - var err error - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/with_other_body")) - 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 -} - -// NewGetOtherRequest generates requests for GetOther -func NewGetOtherRequest(server string) (*http.Request, error) { - var err error - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/with_other_response")) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryUrl.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetJsonWithTrailingSlashRequest generates requests for GetJsonWithTrailingSlash -func NewGetJsonWithTrailingSlashRequest(server string) (*http.Request, error) { - var err error - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/with_trailing_slash/")) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryUrl.String(), nil) - if err != nil { - return nil, err - } - - return req, 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 { - if !strings.HasSuffix(baseURL, "/") { - baseURL += "/" - } - newBaseURL, err := url.Parse(baseURL) - if err != nil { - return err - } - c.Server = newBaseURL.String() - return nil - } -} - -type postBothResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r postBothResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r postBothResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type getBothResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r getBothResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r getBothResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type postJsonResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r postJsonResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r postJsonResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type getJsonResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r getJsonResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r getJsonResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type postOtherResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r postOtherResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r postOtherResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type getOtherResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r getOtherResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r getOtherResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type getJsonWithTrailingSlashResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r getJsonWithTrailingSlashResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r getJsonWithTrailingSlashResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -// PostBothWithBodyWithResponse request with arbitrary body returning *PostBothResponse -func (c *ClientWithResponses) PostBothWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader) (*postBothResponse, error) { - rsp, err := c.PostBothWithBody(ctx, contentType, body) - if err != nil { - return nil, err - } - return ParsePostBothResponse(rsp) -} - -func (c *ClientWithResponses) PostBothWithResponse(ctx context.Context, body PostBothJSONRequestBody) (*postBothResponse, error) { - rsp, err := c.PostBoth(ctx, body) - if err != nil { - return nil, err - } - return ParsePostBothResponse(rsp) -} - -// GetBothWithResponse request returning *GetBothResponse -func (c *ClientWithResponses) GetBothWithResponse(ctx context.Context) (*getBothResponse, error) { - rsp, err := c.GetBoth(ctx) - if err != nil { - return nil, err - } - return ParseGetBothResponse(rsp) -} - -// PostJsonWithBodyWithResponse request with arbitrary body returning *PostJsonResponse -func (c *ClientWithResponses) PostJsonWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader) (*postJsonResponse, error) { - rsp, err := c.PostJsonWithBody(ctx, contentType, body) - if err != nil { - return nil, err - } - return ParsePostJsonResponse(rsp) -} - -func (c *ClientWithResponses) PostJsonWithResponse(ctx context.Context, body PostJsonJSONRequestBody) (*postJsonResponse, error) { - rsp, err := c.PostJson(ctx, body) - if err != nil { - return nil, err - } - return ParsePostJsonResponse(rsp) -} - -// GetJsonWithResponse request returning *GetJsonResponse -func (c *ClientWithResponses) GetJsonWithResponse(ctx context.Context) (*getJsonResponse, error) { - rsp, err := c.GetJson(ctx) - if err != nil { - return nil, err - } - return ParseGetJsonResponse(rsp) -} - -// PostOtherWithBodyWithResponse request with arbitrary body returning *PostOtherResponse -func (c *ClientWithResponses) PostOtherWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader) (*postOtherResponse, error) { - rsp, err := c.PostOtherWithBody(ctx, contentType, body) - if err != nil { - return nil, err - } - return ParsePostOtherResponse(rsp) -} - -// GetOtherWithResponse request returning *GetOtherResponse -func (c *ClientWithResponses) GetOtherWithResponse(ctx context.Context) (*getOtherResponse, error) { - rsp, err := c.GetOther(ctx) - if err != nil { - return nil, err - } - return ParseGetOtherResponse(rsp) -} - -// GetJsonWithTrailingSlashWithResponse request returning *GetJsonWithTrailingSlashResponse -func (c *ClientWithResponses) GetJsonWithTrailingSlashWithResponse(ctx context.Context) (*getJsonWithTrailingSlashResponse, error) { - rsp, err := c.GetJsonWithTrailingSlash(ctx) - if err != nil { - return nil, err - } - return ParseGetJsonWithTrailingSlashResponse(rsp) -} - -// ParsePostBothResponse parses an HTTP response from a PostBothWithResponse call -func ParsePostBothResponse(rsp *http.Response) (*postBothResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &postBothResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ParseGetBothResponse parses an HTTP response from a GetBothWithResponse call -func ParseGetBothResponse(rsp *http.Response) (*getBothResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &getBothResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ParsePostJsonResponse parses an HTTP response from a PostJsonWithResponse call -func ParsePostJsonResponse(rsp *http.Response) (*postJsonResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &postJsonResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ParseGetJsonResponse parses an HTTP response from a GetJsonWithResponse call -func ParseGetJsonResponse(rsp *http.Response) (*getJsonResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &getJsonResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ParsePostOtherResponse parses an HTTP response from a PostOtherWithResponse call -func ParsePostOtherResponse(rsp *http.Response) (*postOtherResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &postOtherResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ParseGetOtherResponse parses an HTTP response from a GetOtherWithResponse call -func ParseGetOtherResponse(rsp *http.Response) (*getOtherResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &getOtherResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ParseGetJsonWithTrailingSlashResponse parses an HTTP response from a GetJsonWithTrailingSlashWithResponse call -func ParseGetJsonWithTrailingSlashResponse(rsp *http.Response) (*getJsonWithTrailingSlashResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &getJsonWithTrailingSlashResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ServerInterface represents all server handlers. -type ServerInterface interface { - - // (POST /with_both_bodies) - PostBoth(ctx echo.Context) error - - // (GET /with_both_responses) - GetBoth(ctx echo.Context) error - - // (POST /with_json_body) - PostJson(ctx echo.Context) error - - // (GET /with_json_response) - GetJson(ctx echo.Context) error - - // (POST /with_other_body) - PostOther(ctx echo.Context) error - - // (GET /with_other_response) - GetOther(ctx echo.Context) error - - // (GET /with_trailing_slash/) - GetJsonWithTrailingSlash(ctx echo.Context) error -} - -// ServerInterfaceWrapper converts echo contexts to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface -} - -// PostBoth converts echo context to params. -func (w *ServerInterfaceWrapper) PostBoth(ctx echo.Context) error { - var err error - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.PostBoth(ctx) - return err -} - -// GetBoth converts echo context to params. -func (w *ServerInterfaceWrapper) GetBoth(ctx echo.Context) error { - var err error - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.GetBoth(ctx) - return err -} - -// PostJson converts echo context to params. -func (w *ServerInterfaceWrapper) PostJson(ctx echo.Context) error { - var err error - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.PostJson(ctx) - return err -} - -// GetJson converts echo context to params. -func (w *ServerInterfaceWrapper) GetJson(ctx echo.Context) error { - var err error - - ctx.Set("OpenId.Scopes", []string{"json.read", "json.admin"}) - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.GetJson(ctx) - return err -} - -// PostOther converts echo context to params. -func (w *ServerInterfaceWrapper) PostOther(ctx echo.Context) error { - var err error - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.PostOther(ctx) - return err -} - -// GetOther converts echo context to params. -func (w *ServerInterfaceWrapper) GetOther(ctx echo.Context) error { - var err error - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.GetOther(ctx) - return err -} - -// GetJsonWithTrailingSlash converts echo context to params. -func (w *ServerInterfaceWrapper) GetJsonWithTrailingSlash(ctx echo.Context) error { - var err error - - ctx.Set("OpenId.Scopes", []string{"json.read", "json.admin"}) - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.GetJsonWithTrailingSlash(ctx) - return err -} - -// RegisterHandlers adds each server route to the EchoRouter. -func RegisterHandlers(router interface { - CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route -}, si ServerInterface) { - - wrapper := ServerInterfaceWrapper{ - Handler: si, - } - - router.POST("/with_both_bodies", wrapper.PostBoth) - router.GET("/with_both_responses", wrapper.GetBoth) - router.POST("/with_json_body", wrapper.PostJson) - router.GET("/with_json_response", wrapper.GetJson) - router.POST("/with_other_body", wrapper.PostOther) - router.GET("/with_other_response", wrapper.GetOther) - router.GET("/with_trailing_slash/", wrapper.GetJsonWithTrailingSlash) - -} - -// Base64 encoded, gzipped, json marshaled Swagger object -var swaggerSpec = []string{ - - "H4sIAAAAAAAC/8xUzY4SQRB+lUnpcWRYvc1RD2ZNFCMkHpBsmp6C7s1Md1tV7GZCeHdTDcgQN8jBNXsh", - "1fRXle+nerZgY5diwCAM9RbYOuxMLqe5nCzv0YqeE8WEJB7z7coTyxfToR6kTwg1sJAPa9iVQLF96kJv", - "8OfGEzZQz/eocjBqsVOID6uozQ2yJZ/ExwA1zJznQpCFi0eH4pAKcVh8aD0GKUxoDuV3L+4bcoqBkQtD", - "WKwxIBnBprCRCK20/Y8AJbTeYuDMM2Qh8Pl2puzFi9KHGbIUU6QHJCjhAYn3VG5G49FYgTFhMMlDDe9G", - "49ENlJCMuOxP9ejF3S1j/mkOpqXI2Uo10qiu2wZq+BpZ3kdxsHcH9dT0irMxCIbcYlJqvc1N1T0rjWNY", - "Wr0mXEENr6pTmtUhyuosR/V3OCpaQXnDQmi685GrSJ0RqGHpg6Eeyj/CPEtTaIP5r4FwOsag89b4hPSP", - "eFI+wL4dj1+q5oFGpaTh9pej/aTM/0u0lwLJZI8mX8rjN91nzENpMdoNeemhnm9hkjATmIPOHRGaBsp9", - "bZrOB1jsFictUV//Fc5PFHe19c/1FPZsr7H+xPey9/9qgYWMb31Y33Fr2FV/2wr9ss4OLVPteKFrstv9", - "CgAA//91LTf11gYAAA==", -} - -// GetSwagger returns the Swagger specification corresponding to the generated code -// in this file. -func GetSwagger() (*openapi3.Swagger, 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) - } - - swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(buf.Bytes()) - if err != nil { - return nil, fmt.Errorf("error loading Swagger: %s", err) - } - return swagger, nil -} diff --git a/internal/test/client/doc.go b/internal/test/client/doc.go index 4a3bcfc8f..58d26feaf 100644 --- a/internal/test/client/doc.go +++ b/internal/test/client/doc.go @@ -1,4 +1,3 @@ package client -//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --package=client -o client.gen.go client.yaml - +//go:generate go run github.com/weberr13/oapi-codegen/cmd/oapi-codegen --package=client -o client.gen.go client.yaml diff --git a/internal/test/components/components.gen.go b/internal/test/components/components.gen.go deleted file mode 100644 index a49fad16f..000000000 --- a/internal/test/components/components.gen.go +++ /dev/null @@ -1,1183 +0,0 @@ -// Package components provides primitives to interact the openapi HTTP API. -// -// Code generated by github.com/deepmap/oapi-codegen DO NOT EDIT. -package components - -import ( - "bytes" - "compress/gzip" - "context" - "encoding/base64" - "encoding/json" - "fmt" - "github.com/deepmap/oapi-codegen/pkg/runtime" - "github.com/getkin/kin-openapi/openapi3" - "github.com/labstack/echo/v4" - "github.com/pkg/errors" - "io" - "io/ioutil" - "net/http" - "net/url" - "strings" -) - -// AdditionalPropertiesObject1 defines model for AdditionalPropertiesObject1. -type AdditionalPropertiesObject1 struct { - Id int `json:"id"` - Name string `json:"name"` - Optional *string `json:"optional,omitempty"` - AdditionalProperties map[string]int `json:"-"` -} - -// AdditionalPropertiesObject2 defines model for AdditionalPropertiesObject2. -type AdditionalPropertiesObject2 struct { - Id int `json:"id"` - Name string `json:"name"` -} - -// AdditionalPropertiesObject3 defines model for AdditionalPropertiesObject3. -type AdditionalPropertiesObject3 struct { - Name string `json:"name"` - AdditionalProperties map[string]interface{} `json:"-"` -} - -// AdditionalPropertiesObject4 defines model for AdditionalPropertiesObject4. -type AdditionalPropertiesObject4 struct { - Inner AdditionalPropertiesObject4_Inner `json:"inner"` - Name string `json:"name"` - AdditionalProperties map[string]interface{} `json:"-"` -} - -// AdditionalPropertiesObject4_Inner defines model for AdditionalPropertiesObject4.Inner. -type AdditionalPropertiesObject4_Inner struct { - Name string `json:"name"` - AdditionalProperties map[string]interface{} `json:"-"` -} - -// AdditionalPropertiesObject5 defines model for AdditionalPropertiesObject5. -type AdditionalPropertiesObject5 struct { - AdditionalProperties map[string]SchemaObject `json:"-"` -} - -// ObjectWithJsonField defines model for ObjectWithJsonField. -type ObjectWithJsonField struct { - Name string `json:"name"` - Value1 json.RawMessage `json:"value1"` - Value2 json.RawMessage `json:"value2,omitempty"` -} - -// SchemaObject defines model for SchemaObject. -type SchemaObject struct { - FirstName string `json:"firstName"` - Role string `json:"role"` -} - -// ParameterObject defines model for ParameterObject. -type ParameterObject string - -// ResponseObject defines model for ResponseObject. -type ResponseObject struct { - Field SchemaObject `json:"Field"` -} - -// RequestBody defines model for RequestBody. -type RequestBody struct { - Field SchemaObject `json:"Field"` -} - -// ParamsWithAddPropsParams_P1 defines parameters for ParamsWithAddProps. -type ParamsWithAddPropsParams_P1 struct { - AdditionalProperties map[string]interface{} `json:"-"` -} - -// ParamsWithAddPropsParams defines parameters for ParamsWithAddProps. -type ParamsWithAddPropsParams struct { - - // This parameter has additional properties - P1 ParamsWithAddPropsParams_P1 `json:"p1"` - - // This parameter has an anonymous inner property which needs to be - // turned into a proper type for additionalProperties to work - P2 struct { - Inner ParamsWithAddPropsParams_P2_Inner `json:"inner"` - } `json:"p2"` -} - -// ParamsWithAddPropsParams_P2_Inner defines parameters for ParamsWithAddProps. -type ParamsWithAddPropsParams_P2_Inner struct { - AdditionalProperties map[string]string `json:"-"` -} - -// BodyWithAddPropsJSONBody defines parameters for BodyWithAddProps. -type BodyWithAddPropsJSONBody struct { - Inner BodyWithAddPropsJSONBody_Inner `json:"inner"` - Name string `json:"name"` - AdditionalProperties map[string]interface{} `json:"-"` -} - -// BodyWithAddPropsJSONBody_Inner defines parameters for BodyWithAddProps. -type BodyWithAddPropsJSONBody_Inner struct { - AdditionalProperties map[string]int `json:"-"` -} - -// BodyWithAddPropsRequestBody defines body for BodyWithAddProps for application/json ContentType. -type BodyWithAddPropsJSONRequestBody BodyWithAddPropsJSONBody - -// Getter for additional properties for ParamsWithAddPropsParams_P1. Returns the specified -// element and whether it was found -func (a ParamsWithAddPropsParams_P1) Get(fieldName string) (value interface{}, found bool) { - if a.AdditionalProperties != nil { - value, found = a.AdditionalProperties[fieldName] - } - return -} - -// Setter for additional properties for ParamsWithAddPropsParams_P1 -func (a *ParamsWithAddPropsParams_P1) Set(fieldName string, value interface{}) { - if a.AdditionalProperties == nil { - a.AdditionalProperties = make(map[string]interface{}) - } - a.AdditionalProperties[fieldName] = value -} - -// Override default JSON handling for ParamsWithAddPropsParams_P1 to handle AdditionalProperties -func (a *ParamsWithAddPropsParams_P1) UnmarshalJSON(b []byte) error { - object := make(map[string]json.RawMessage) - err := json.Unmarshal(b, &object) - if err != nil { - return err - } - - 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 errors.Wrap(err, fmt.Sprintf("error unmarshaling field %s", fieldName)) - } - a.AdditionalProperties[fieldName] = fieldVal - } - } - return nil -} - -// Override default JSON handling for ParamsWithAddPropsParams_P1 to handle AdditionalProperties -func (a ParamsWithAddPropsParams_P1) MarshalJSON() ([]byte, error) { - var err error - object := make(map[string]json.RawMessage) - - for fieldName, field := range a.AdditionalProperties { - object[fieldName], err = json.Marshal(field) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("error marshaling '%s'", fieldName)) - } - } - return json.Marshal(object) -} - -// Getter for additional properties for ParamsWithAddPropsParams_P2_Inner. Returns the specified -// element and whether it was found -func (a ParamsWithAddPropsParams_P2_Inner) Get(fieldName string) (value string, found bool) { - if a.AdditionalProperties != nil { - value, found = a.AdditionalProperties[fieldName] - } - return -} - -// Setter for additional properties for ParamsWithAddPropsParams_P2_Inner -func (a *ParamsWithAddPropsParams_P2_Inner) Set(fieldName string, value string) { - if a.AdditionalProperties == nil { - a.AdditionalProperties = make(map[string]string) - } - a.AdditionalProperties[fieldName] = value -} - -// Override default JSON handling for ParamsWithAddPropsParams_P2_Inner to handle AdditionalProperties -func (a *ParamsWithAddPropsParams_P2_Inner) UnmarshalJSON(b []byte) error { - object := make(map[string]json.RawMessage) - err := json.Unmarshal(b, &object) - if err != nil { - return err - } - - if len(object) != 0 { - a.AdditionalProperties = make(map[string]string) - for fieldName, fieldBuf := range object { - var fieldVal string - err := json.Unmarshal(fieldBuf, &fieldVal) - if err != nil { - return errors.Wrap(err, fmt.Sprintf("error unmarshaling field %s", fieldName)) - } - a.AdditionalProperties[fieldName] = fieldVal - } - } - return nil -} - -// Override default JSON handling for ParamsWithAddPropsParams_P2_Inner to handle AdditionalProperties -func (a ParamsWithAddPropsParams_P2_Inner) MarshalJSON() ([]byte, error) { - var err error - object := make(map[string]json.RawMessage) - - for fieldName, field := range a.AdditionalProperties { - object[fieldName], err = json.Marshal(field) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("error marshaling '%s'", fieldName)) - } - } - return json.Marshal(object) -} - -// Getter for additional properties for BodyWithAddPropsJSONBody. Returns the specified -// element and whether it was found -func (a BodyWithAddPropsJSONBody) Get(fieldName string) (value interface{}, found bool) { - if a.AdditionalProperties != nil { - value, found = a.AdditionalProperties[fieldName] - } - return -} - -// Setter for additional properties for BodyWithAddPropsJSONBody -func (a *BodyWithAddPropsJSONBody) Set(fieldName string, value interface{}) { - if a.AdditionalProperties == nil { - a.AdditionalProperties = make(map[string]interface{}) - } - a.AdditionalProperties[fieldName] = value -} - -// Override default JSON handling for BodyWithAddPropsJSONBody to handle AdditionalProperties -func (a *BodyWithAddPropsJSONBody) UnmarshalJSON(b []byte) error { - object := make(map[string]json.RawMessage) - err := json.Unmarshal(b, &object) - if err != nil { - return err - } - - if raw, found := object["inner"]; found { - err = json.Unmarshal(raw, &a.Inner) - if err != nil { - return errors.Wrap(err, "error reading 'inner'") - } - delete(object, "inner") - } - - if raw, found := object["name"]; found { - err = json.Unmarshal(raw, &a.Name) - if err != nil { - return errors.Wrap(err, "error reading 'name'") - } - delete(object, "name") - } - - 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 errors.Wrap(err, fmt.Sprintf("error unmarshaling field %s", fieldName)) - } - a.AdditionalProperties[fieldName] = fieldVal - } - } - return nil -} - -// Override default JSON handling for BodyWithAddPropsJSONBody to handle AdditionalProperties -func (a BodyWithAddPropsJSONBody) MarshalJSON() ([]byte, error) { - var err error - object := make(map[string]json.RawMessage) - - object["inner"], err = json.Marshal(a.Inner) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("error marshaling 'inner'")) - } - - object["name"], err = json.Marshal(a.Name) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("error marshaling 'name'")) - } - - for fieldName, field := range a.AdditionalProperties { - object[fieldName], err = json.Marshal(field) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("error marshaling '%s'", fieldName)) - } - } - return json.Marshal(object) -} - -// Getter for additional properties for BodyWithAddPropsJSONBody_Inner. Returns the specified -// element and whether it was found -func (a BodyWithAddPropsJSONBody_Inner) Get(fieldName string) (value int, found bool) { - if a.AdditionalProperties != nil { - value, found = a.AdditionalProperties[fieldName] - } - return -} - -// Setter for additional properties for BodyWithAddPropsJSONBody_Inner -func (a *BodyWithAddPropsJSONBody_Inner) Set(fieldName string, value int) { - if a.AdditionalProperties == nil { - a.AdditionalProperties = make(map[string]int) - } - a.AdditionalProperties[fieldName] = value -} - -// Override default JSON handling for BodyWithAddPropsJSONBody_Inner to handle AdditionalProperties -func (a *BodyWithAddPropsJSONBody_Inner) UnmarshalJSON(b []byte) error { - object := make(map[string]json.RawMessage) - err := json.Unmarshal(b, &object) - if err != nil { - return err - } - - if len(object) != 0 { - a.AdditionalProperties = make(map[string]int) - for fieldName, fieldBuf := range object { - var fieldVal int - err := json.Unmarshal(fieldBuf, &fieldVal) - if err != nil { - return errors.Wrap(err, fmt.Sprintf("error unmarshaling field %s", fieldName)) - } - a.AdditionalProperties[fieldName] = fieldVal - } - } - return nil -} - -// Override default JSON handling for BodyWithAddPropsJSONBody_Inner to handle AdditionalProperties -func (a BodyWithAddPropsJSONBody_Inner) MarshalJSON() ([]byte, error) { - var err error - object := make(map[string]json.RawMessage) - - for fieldName, field := range a.AdditionalProperties { - object[fieldName], err = json.Marshal(field) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("error marshaling '%s'", fieldName)) - } - } - return json.Marshal(object) -} - -// Getter for additional properties for AdditionalPropertiesObject1. Returns the specified -// element and whether it was found -func (a AdditionalPropertiesObject1) Get(fieldName string) (value int, found bool) { - if a.AdditionalProperties != nil { - value, found = a.AdditionalProperties[fieldName] - } - return -} - -// Setter for additional properties for AdditionalPropertiesObject1 -func (a *AdditionalPropertiesObject1) Set(fieldName string, value int) { - if a.AdditionalProperties == nil { - a.AdditionalProperties = make(map[string]int) - } - a.AdditionalProperties[fieldName] = value -} - -// Override default JSON handling for AdditionalPropertiesObject1 to handle AdditionalProperties -func (a *AdditionalPropertiesObject1) UnmarshalJSON(b []byte) error { - object := make(map[string]json.RawMessage) - err := json.Unmarshal(b, &object) - if err != nil { - return err - } - - if raw, found := object["id"]; found { - err = json.Unmarshal(raw, &a.Id) - if err != nil { - return errors.Wrap(err, "error reading 'id'") - } - delete(object, "id") - } - - if raw, found := object["name"]; found { - err = json.Unmarshal(raw, &a.Name) - if err != nil { - return errors.Wrap(err, "error reading 'name'") - } - delete(object, "name") - } - - if raw, found := object["optional"]; found { - err = json.Unmarshal(raw, &a.Optional) - if err != nil { - return errors.Wrap(err, "error reading 'optional'") - } - delete(object, "optional") - } - - if len(object) != 0 { - a.AdditionalProperties = make(map[string]int) - for fieldName, fieldBuf := range object { - var fieldVal int - err := json.Unmarshal(fieldBuf, &fieldVal) - if err != nil { - return errors.Wrap(err, fmt.Sprintf("error unmarshaling field %s", fieldName)) - } - a.AdditionalProperties[fieldName] = fieldVal - } - } - return nil -} - -// Override default JSON handling for AdditionalPropertiesObject1 to handle AdditionalProperties -func (a AdditionalPropertiesObject1) MarshalJSON() ([]byte, error) { - var err error - object := make(map[string]json.RawMessage) - - object["id"], err = json.Marshal(a.Id) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("error marshaling 'id'")) - } - - object["name"], err = json.Marshal(a.Name) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("error marshaling 'name'")) - } - - if a.Optional != nil { - object["optional"], err = json.Marshal(a.Optional) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("error marshaling 'optional'")) - } - } - - for fieldName, field := range a.AdditionalProperties { - object[fieldName], err = json.Marshal(field) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("error marshaling '%s'", fieldName)) - } - } - return json.Marshal(object) -} - -// Getter for additional properties for AdditionalPropertiesObject3. Returns the specified -// element and whether it was found -func (a AdditionalPropertiesObject3) Get(fieldName string) (value interface{}, found bool) { - if a.AdditionalProperties != nil { - value, found = a.AdditionalProperties[fieldName] - } - return -} - -// Setter for additional properties for AdditionalPropertiesObject3 -func (a *AdditionalPropertiesObject3) Set(fieldName string, value interface{}) { - if a.AdditionalProperties == nil { - a.AdditionalProperties = make(map[string]interface{}) - } - a.AdditionalProperties[fieldName] = value -} - -// Override default JSON handling for AdditionalPropertiesObject3 to handle AdditionalProperties -func (a *AdditionalPropertiesObject3) UnmarshalJSON(b []byte) error { - object := make(map[string]json.RawMessage) - err := json.Unmarshal(b, &object) - if err != nil { - return err - } - - if raw, found := object["name"]; found { - err = json.Unmarshal(raw, &a.Name) - if err != nil { - return errors.Wrap(err, "error reading 'name'") - } - delete(object, "name") - } - - 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 errors.Wrap(err, fmt.Sprintf("error unmarshaling field %s", fieldName)) - } - a.AdditionalProperties[fieldName] = fieldVal - } - } - return nil -} - -// Override default JSON handling for AdditionalPropertiesObject3 to handle AdditionalProperties -func (a AdditionalPropertiesObject3) MarshalJSON() ([]byte, error) { - var err error - object := make(map[string]json.RawMessage) - - object["name"], err = json.Marshal(a.Name) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("error marshaling 'name'")) - } - - for fieldName, field := range a.AdditionalProperties { - object[fieldName], err = json.Marshal(field) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("error marshaling '%s'", fieldName)) - } - } - return json.Marshal(object) -} - -// Getter for additional properties for AdditionalPropertiesObject4. Returns the specified -// element and whether it was found -func (a AdditionalPropertiesObject4) Get(fieldName string) (value interface{}, found bool) { - if a.AdditionalProperties != nil { - value, found = a.AdditionalProperties[fieldName] - } - return -} - -// Setter for additional properties for AdditionalPropertiesObject4 -func (a *AdditionalPropertiesObject4) Set(fieldName string, value interface{}) { - if a.AdditionalProperties == nil { - a.AdditionalProperties = make(map[string]interface{}) - } - a.AdditionalProperties[fieldName] = value -} - -// Override default JSON handling for AdditionalPropertiesObject4 to handle AdditionalProperties -func (a *AdditionalPropertiesObject4) UnmarshalJSON(b []byte) error { - object := make(map[string]json.RawMessage) - err := json.Unmarshal(b, &object) - if err != nil { - return err - } - - if raw, found := object["inner"]; found { - err = json.Unmarshal(raw, &a.Inner) - if err != nil { - return errors.Wrap(err, "error reading 'inner'") - } - delete(object, "inner") - } - - if raw, found := object["name"]; found { - err = json.Unmarshal(raw, &a.Name) - if err != nil { - return errors.Wrap(err, "error reading 'name'") - } - delete(object, "name") - } - - 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 errors.Wrap(err, fmt.Sprintf("error unmarshaling field %s", fieldName)) - } - a.AdditionalProperties[fieldName] = fieldVal - } - } - return nil -} - -// Override default JSON handling for AdditionalPropertiesObject4 to handle AdditionalProperties -func (a AdditionalPropertiesObject4) MarshalJSON() ([]byte, error) { - var err error - object := make(map[string]json.RawMessage) - - object["inner"], err = json.Marshal(a.Inner) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("error marshaling 'inner'")) - } - - object["name"], err = json.Marshal(a.Name) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("error marshaling 'name'")) - } - - for fieldName, field := range a.AdditionalProperties { - object[fieldName], err = json.Marshal(field) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("error marshaling '%s'", fieldName)) - } - } - return json.Marshal(object) -} - -// Getter for additional properties for AdditionalPropertiesObject4_Inner. Returns the specified -// element and whether it was found -func (a AdditionalPropertiesObject4_Inner) Get(fieldName string) (value interface{}, found bool) { - if a.AdditionalProperties != nil { - value, found = a.AdditionalProperties[fieldName] - } - return -} - -// Setter for additional properties for AdditionalPropertiesObject4_Inner -func (a *AdditionalPropertiesObject4_Inner) Set(fieldName string, value interface{}) { - if a.AdditionalProperties == nil { - a.AdditionalProperties = make(map[string]interface{}) - } - a.AdditionalProperties[fieldName] = value -} - -// Override default JSON handling for AdditionalPropertiesObject4_Inner to handle AdditionalProperties -func (a *AdditionalPropertiesObject4_Inner) UnmarshalJSON(b []byte) error { - object := make(map[string]json.RawMessage) - err := json.Unmarshal(b, &object) - if err != nil { - return err - } - - if raw, found := object["name"]; found { - err = json.Unmarshal(raw, &a.Name) - if err != nil { - return errors.Wrap(err, "error reading 'name'") - } - delete(object, "name") - } - - 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 errors.Wrap(err, fmt.Sprintf("error unmarshaling field %s", fieldName)) - } - a.AdditionalProperties[fieldName] = fieldVal - } - } - return nil -} - -// Override default JSON handling for AdditionalPropertiesObject4_Inner to handle AdditionalProperties -func (a AdditionalPropertiesObject4_Inner) MarshalJSON() ([]byte, error) { - var err error - object := make(map[string]json.RawMessage) - - object["name"], err = json.Marshal(a.Name) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("error marshaling 'name'")) - } - - for fieldName, field := range a.AdditionalProperties { - object[fieldName], err = json.Marshal(field) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("error marshaling '%s'", fieldName)) - } - } - return json.Marshal(object) -} - -// Getter for additional properties for AdditionalPropertiesObject5. Returns the specified -// element and whether it was found -func (a AdditionalPropertiesObject5) Get(fieldName string) (value SchemaObject, found bool) { - if a.AdditionalProperties != nil { - value, found = a.AdditionalProperties[fieldName] - } - return -} - -// Setter for additional properties for AdditionalPropertiesObject5 -func (a *AdditionalPropertiesObject5) Set(fieldName string, value SchemaObject) { - if a.AdditionalProperties == nil { - a.AdditionalProperties = make(map[string]SchemaObject) - } - a.AdditionalProperties[fieldName] = value -} - -// Override default JSON handling for AdditionalPropertiesObject5 to handle AdditionalProperties -func (a *AdditionalPropertiesObject5) UnmarshalJSON(b []byte) error { - object := make(map[string]json.RawMessage) - err := json.Unmarshal(b, &object) - if err != nil { - return err - } - - if len(object) != 0 { - a.AdditionalProperties = make(map[string]SchemaObject) - for fieldName, fieldBuf := range object { - var fieldVal SchemaObject - err := json.Unmarshal(fieldBuf, &fieldVal) - if err != nil { - return errors.Wrap(err, fmt.Sprintf("error unmarshaling field %s", fieldName)) - } - a.AdditionalProperties[fieldName] = fieldVal - } - } - return nil -} - -// Override default JSON handling for AdditionalPropertiesObject5 to handle AdditionalProperties -func (a AdditionalPropertiesObject5) MarshalJSON() ([]byte, error) { - var err error - object := make(map[string]json.RawMessage) - - for fieldName, field := range a.AdditionalProperties { - object[fieldName], err = json.Marshal(field) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("error marshaling '%s'", fieldName)) - } - } - return json.Marshal(object) -} - -// RequestEditorFn is the function signature for the RequestEditor callback function -type RequestEditorFn func(req *http.Request, ctx context.Context) 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. - Server string - - // Doer for performing requests, typically a *http.Client with any - // customized settings, such as certificate chains. - Client HttpRequestDoer - - // A callback for modifying requests which are generated before sending over - // the network. - RequestEditor 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 - } - } - // create httpClient, if not already present - if client.Client == nil { - client.Client = http.DefaultClient - } - 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.RequestEditor = fn - return nil - } -} - -// The interface specification for the client above. -type ClientInterface interface { - // ParamsWithAddProps request - ParamsWithAddProps(ctx context.Context, params *ParamsWithAddPropsParams) (*http.Response, error) - - // BodyWithAddProps request with any body - BodyWithAddPropsWithBody(ctx context.Context, contentType string, body io.Reader) (*http.Response, error) - - BodyWithAddProps(ctx context.Context, body BodyWithAddPropsJSONRequestBody) (*http.Response, error) -} - -func (c *Client) ParamsWithAddProps(ctx context.Context, params *ParamsWithAddPropsParams) (*http.Response, error) { - req, err := NewParamsWithAddPropsRequest(c.Server, params) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) BodyWithAddPropsWithBody(ctx context.Context, contentType string, body io.Reader) (*http.Response, error) { - req, err := NewBodyWithAddPropsRequestWithBody(c.Server, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) BodyWithAddProps(ctx context.Context, body BodyWithAddPropsJSONRequestBody) (*http.Response, error) { - req, err := NewBodyWithAddPropsRequest(c.Server, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -// NewParamsWithAddPropsRequest generates requests for ParamsWithAddProps -func NewParamsWithAddPropsRequest(server string, params *ParamsWithAddPropsParams) (*http.Request, error) { - var err error - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/params_with_add_props")) - if err != nil { - return nil, err - } - - queryValues := queryUrl.Query() - - if queryFrag, err := runtime.StyleParam("simple", true, "p1", params.P1); 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.StyleParam("form", true, "p2", params.P2); 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() - - req, err := http.NewRequest("GET", queryUrl.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewBodyWithAddPropsRequest calls the generic BodyWithAddProps builder with application/json body -func NewBodyWithAddPropsRequest(server string, body BodyWithAddPropsJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewBodyWithAddPropsRequestWithBody(server, "application/json", bodyReader) -} - -// NewBodyWithAddPropsRequestWithBody generates requests for BodyWithAddProps with any type of body -func NewBodyWithAddPropsRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { - var err error - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/params_with_add_props")) - 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 -} - -// 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 { - if !strings.HasSuffix(baseURL, "/") { - baseURL += "/" - } - newBaseURL, err := url.Parse(baseURL) - if err != nil { - return err - } - c.Server = newBaseURL.String() - return nil - } -} - -type paramsWithAddPropsResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r paramsWithAddPropsResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r paramsWithAddPropsResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type bodyWithAddPropsResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r bodyWithAddPropsResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r bodyWithAddPropsResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -// ParamsWithAddPropsWithResponse request returning *ParamsWithAddPropsResponse -func (c *ClientWithResponses) ParamsWithAddPropsWithResponse(ctx context.Context, params *ParamsWithAddPropsParams) (*paramsWithAddPropsResponse, error) { - rsp, err := c.ParamsWithAddProps(ctx, params) - if err != nil { - return nil, err - } - return ParseParamsWithAddPropsResponse(rsp) -} - -// BodyWithAddPropsWithBodyWithResponse request with arbitrary body returning *BodyWithAddPropsResponse -func (c *ClientWithResponses) BodyWithAddPropsWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader) (*bodyWithAddPropsResponse, error) { - rsp, err := c.BodyWithAddPropsWithBody(ctx, contentType, body) - if err != nil { - return nil, err - } - return ParseBodyWithAddPropsResponse(rsp) -} - -func (c *ClientWithResponses) BodyWithAddPropsWithResponse(ctx context.Context, body BodyWithAddPropsJSONRequestBody) (*bodyWithAddPropsResponse, error) { - rsp, err := c.BodyWithAddProps(ctx, body) - if err != nil { - return nil, err - } - return ParseBodyWithAddPropsResponse(rsp) -} - -// ParseParamsWithAddPropsResponse parses an HTTP response from a ParamsWithAddPropsWithResponse call -func ParseParamsWithAddPropsResponse(rsp *http.Response) (*paramsWithAddPropsResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := ¶msWithAddPropsResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ParseBodyWithAddPropsResponse parses an HTTP response from a BodyWithAddPropsWithResponse call -func ParseBodyWithAddPropsResponse(rsp *http.Response) (*bodyWithAddPropsResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &bodyWithAddPropsResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ServerInterface represents all server handlers. -type ServerInterface interface { - - // (GET /params_with_add_props) - ParamsWithAddProps(ctx echo.Context, params ParamsWithAddPropsParams) error - - // (POST /params_with_add_props) - BodyWithAddProps(ctx echo.Context) error -} - -// ServerInterfaceWrapper converts echo contexts to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface -} - -// ParamsWithAddProps converts echo context to params. -func (w *ServerInterfaceWrapper) ParamsWithAddProps(ctx echo.Context) error { - var err error - - // Parameter object where we will unmarshal all parameters from the context - var params ParamsWithAddPropsParams - // ------------- Required query parameter "p1" ------------- - if paramValue := ctx.QueryParam("p1"); paramValue != "" { - - } else { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Query argument p1 is required, but not found")) - } - - err = runtime.BindQueryParameter("simple", true, true, "p1", ctx.QueryParams(), ¶ms.P1) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter p1: %s", err)) - } - - // ------------- Required query parameter "p2" ------------- - if paramValue := ctx.QueryParam("p2"); paramValue != "" { - - } else { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Query argument p2 is required, but not found")) - } - - err = runtime.BindQueryParameter("form", true, true, "p2", ctx.QueryParams(), ¶ms.P2) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter p2: %s", err)) - } - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.ParamsWithAddProps(ctx, params) - return err -} - -// BodyWithAddProps converts echo context to params. -func (w *ServerInterfaceWrapper) BodyWithAddProps(ctx echo.Context) error { - var err error - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.BodyWithAddProps(ctx) - return err -} - -// RegisterHandlers adds each server route to the EchoRouter. -func RegisterHandlers(router interface { - CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route -}, si ServerInterface) { - - wrapper := ServerInterfaceWrapper{ - Handler: si, - } - - router.GET("/params_with_add_props", wrapper.ParamsWithAddProps) - router.POST("/params_with_add_props", wrapper.BodyWithAddProps) - -} - -// Base64 encoded, gzipped, json marshaled Swagger object -var swaggerSpec = []string{ - - "H4sIAAAAAAAC/9xWy27bOhD9FWLuXQp2Hu1GOxdF0RRoGzQBukiMgBFHEVOZVEg6rhDo34shJcuRaVdO", - "s2lXtiTO4xyeeTxBpheVVqichfQJKm74Ah0a/3TePX29vcfM0atMK4fK/+VVVcqMO6nV9N5qRe9sVuCC", - "e09GV2icRO/pg8RS0J//DeaQwn/TPu40GNnphf9tYzVNAgYfltKggPSq9TCn1w5/umlVcjkI6eoKIQXr", - "jFR30NBRgTYzsqIcIQXO1vggATKHhyWaeh0MrXunRZvzt/WL+q9DHnzYSivbgQkP/8hNzpiVi6pE1oFk", - "ug/WZkGOZkJIMuHl+RpFSOvYA4983ogvlcM7NLAV/iO3rLdlPUNM54yMmVQOkgF1UsR9K77ACOoEdBUC", - "xCh5zql3kVCEedId7RhJ9rBwspuFnJcWh8Dfa7RMacd4WepVnIM/xf1K0E53Q3NmuYVsRoAs46qOoKq3", - "MB2Q+2Fpvzksba9EpVW90EvLciottipkVrBil0a370cpNL8L+6rwx5mHvJKXsPh2X3WP71zj634lXcGC", - "E5Zrw4TM/CETCN9KPUT4Ll3xyWq1bqqjWE7gkZdL9B0s12bBHaTg+3ay4+jJiKPxsmsjxdh/RtVW7rk0", - "1n3ZBcDocoQA/Klkw9XcjwKpck3GpcxQWeyZgs9nl+TdSUfu4RKtYxdoHr2MHtHYcI3Hk6PJUWiwqHgl", - "IYXTydHkmCqDu8LnP/Wrgr2hi73hQtwQPP/lDj3c4UAiyyCDfoliXAnG2a0WdVuVLby4iq7pWujBj+Iz", - "AWlYwSzpZCbEuU8hebalXQ0zuSyk7VPY3QZ8sI0dqKtKqIiH/hpC+fezeV+T2NKIdbW/iTCtoUnGZKs2", - "OprvAes23JKoEIVlTrNbvFZuaRQKGria8fZkmMFUh7FsyXKlzY/dDJzsZeCg7hkR/4ClaNebN828SaDS", - "NiI234ZYu7Buqot2Oi4VfRXSYOai+BOS5bXayzPpOGYbkSgtyAOBmheuzuMH0FjWN9aNF06hbv/orqUZ", - "SsOv278CAAD//0Y7czRJDQAA", -} - -// GetSwagger returns the Swagger specification corresponding to the generated code -// in this file. -func GetSwagger() (*openapi3.Swagger, 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) - } - - swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(buf.Bytes()) - if err != nil { - return nil, fmt.Errorf("error loading Swagger: %s", err) - } - return swagger, nil -} diff --git a/internal/test/components/doc.go b/internal/test/components/doc.go index c8f457a3a..25bf4a19c 100644 --- a/internal/test/components/doc.go +++ b/internal/test/components/doc.go @@ -1,3 +1,3 @@ package components -//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --package=components -o components.gen.go components.yaml +//go:generate go run github.com/weberr13/oapi-codegen/cmd/oapi-codegen --package=components -o components.gen.go components.yaml diff --git a/internal/test/issues/issue-52/issue.gen.go b/internal/test/issues/issue-52/issue.gen.go index f7a0d689e..6df59c3b4 100644 --- a/internal/test/issues/issue-52/issue.gen.go +++ b/internal/test/issues/issue-52/issue.gen.go @@ -286,7 +286,6 @@ func ParseExampleGetResponse(rsp *http.Response) (*exampleGetResponse, error) { // ServerInterface represents all server handlers. type ServerInterface interface { - // (GET /example) ExampleGet(ctx echo.Context) error } diff --git a/internal/test/issues/issue-f5-3231/doc.go b/internal/test/issues/issue-f5-3231/doc.go new file mode 100644 index 000000000..5083f826a --- /dev/null +++ b/internal/test/issues/issue-f5-3231/doc.go @@ -0,0 +1,3 @@ +package issue_f5_3231 + +//go:generate go run github.com/weberr13/oapi-codegen/cmd/oapi-codegen --package=issue_f5_3231 --generate types,server,client -o issue.gen.go spec.yaml diff --git a/internal/test/issues/issue-f5-3231/issue.gen.go b/internal/test/issues/issue-f5-3231/issue.gen.go new file mode 100644 index 000000000..9c0de6a67 --- /dev/null +++ b/internal/test/issues/issue-f5-3231/issue.gen.go @@ -0,0 +1,170 @@ +// Package issue_f5_3231 provides primitives to interact the openapi HTTP API. +// +// Code generated by github.com/weberr13/oapi-codegen DO NOT EDIT. +package issue_f5_3231 + +import ( + "context" + "fmt" + "net/http" + + "github.com/weberr13/oapi-codegen/pkg/runtime" +) + +// Book defines model for Book. +type Book struct { + Classification Classification `json:"classification,omitempty"` +} + +// Classification defines model for Classification. +type Classification interface{} + +// Novel defines model for Novel. +type Novel struct { + Genre *string `json:"genre,omitempty"` + Type string `json:"type"` +} + +// Textbook defines model for Textbook. +type Textbook struct { + Field *string `json:"field,omitempty"` + Type *string `json:"type,omitempty"` +} + +func factory(fm map[string]func() interface{}, path, dk string, o map[string]interface{}) (interface{}, error) { + var dp interface{} + var dv string + var ok bool + + if dp, ok = o[dk]; !ok { + return nil, fmt.Errorf("expecting OneOf object at path '%s' to to have a discriminator property '%s'", path, dk) + } + + if dv, ok = dp.(string); !ok { + return nil, fmt.Errorf("expecting OneOf field '%s's' discriminator property '%s' value to be a string", path, dk) + } + + f, ok := fm[dv] + if !ok { + return nil, fmt.Errorf("Unknown discriminator value '%s' when handling OneOf field '%s'", path, dv) + } + return f(), nil +} + +// Factory method for objects at path Book.classification +func Book_classification_Factory(o map[string]interface{}) (interface{}, error) { + fm := map[string]func() interface{}{ + "Novel": NewNovel, + "Textbook": NewTextbook, + } + return factory(fm, "Book.classification", "type", o) +} + +func SchemaPathFactory(path string) (func(map[string]interface{}) (interface{}, error), error) { + // Map StringPath => Factory + pathFactoryMap := map[string]func(map[string]interface{}) (interface{}, error){ + "Book.classification": Book_classification_Factory, + } + + return pathFactoryMap[path], nil +} + +func TypeFactory(kind string) (interface{}, error) { + // Map StringPath => Factory + var factoryMap = map[string]func() interface{}{ + "Novel": NewNovel, + "Textbook": NewTextbook, + } + f, ok := factoryMap[kind] + if !ok { + return nil, fmt.Errorf("cannot find type %s", kind) + } + return f(), nil +} + +func NewNovel() interface{} { + _d := "Novel" + return &Novel{Type: _d} +} + +func (r Novel) Discriminator() string { + return "type" +} + +func NewTextbook() interface{} { + _d := "Textbook" + return &Textbook{Type: &_d} +} + +func (r Textbook) Discriminator() string { + return "type" +} + +// RequestEditorFn is the function signature for the RequestEditor callback function +type RequestEditorFn func(req *http.Request, ctx context.Context) error + +type HTTPClientInterface 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. + Server string + + // HTTP client with any customized settings, such as certificate chains. + Client HTTPClientInterface + + // A callback for modifying requests which are generated before sending over + // the network. + RequestEditor RequestEditorFn +} + +// The interface specification for the client above. +type ClientInterface interface { +} + +// ClientWithResponses builds on ClientInterface to offer response payloads +type ClientWithResponses struct { + ClientInterface +} + +// NewClientWithResponses returns a ClientWithResponses with a default Client: +func NewClientWithResponses(server string) *ClientWithResponses { + return &ClientWithResponses{ + ClientInterface: &Client{ + Client: &http.Client{}, + Server: server, + }, + } +} + +// NewClientWithResponsesAndRequestEditorFunc takes in a RequestEditorFn callback function and returns a ClientWithResponses with a default Client: +func NewClientWithResponsesAndRequestEditorFunc(server string, reqEditorFn RequestEditorFn) *ClientWithResponses { + return &ClientWithResponses{ + ClientInterface: &Client{ + Client: &http.Client{}, + Server: server, + RequestEditor: reqEditorFn, + }, + } +} + +func (c *ClientWithResponses) UpdateHttpClient(cli HTTPClientInterface) { + c.ClientInterface.(*Client).Client = cli +} + +// ServerInterface represents all server handlers. +type ServerInterface interface { +} + +// ServerInterfaceWrapper converts echo contexts to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface +} + +// RegisterHandlers adds each server route to the EchoRouter. +func RegisterHandlers(router runtime.EchoRouter, si ServerInterface) { + +} diff --git a/internal/test/issues/issue-f5-3231/issue_test.go b/internal/test/issues/issue-f5-3231/issue_test.go new file mode 100644 index 000000000..bec9723e5 --- /dev/null +++ b/internal/test/issues/issue-f5-3231/issue_test.go @@ -0,0 +1,31 @@ +package issue_f5_3231 + +import ( + "io/ioutil" + "testing" + + "github.com/getkin/kin-openapi/openapi3" + "github.com/stretchr/testify/require" + "github.com/weberr13/oapi-codegen/pkg/codegen" +) + +func TestIssue(t *testing.T) { + // load spec from testdata identified by spec + bytes, err := ioutil.ReadFile(`spec.yaml`) + if err != nil { + t.Fatal(err) + } + // Get a spec from the test definition in this file: + swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(bytes) + require.NoError(t, err) + + opts := codegen.Options{ + GenerateClient: true, + GenerateServer: true, + GenerateTypes: true, + EmbedSpec: true, + } + + _, err = codegen.Generate(swagger, "issue_f5_3231", opts) + require.NoError(t, err) +} diff --git a/internal/test/issues/issue-f5-3231/spec.yaml b/internal/test/issues/issue-f5-3231/spec.yaml new file mode 100644 index 000000000..4961beddc --- /dev/null +++ b/internal/test/issues/issue-f5-3231/spec.yaml @@ -0,0 +1,41 @@ +openapi: 3.0.2 +info: + version: '0.0.1' + title: example + desscription: | + Ensure discriminator type is generated correctly +paths: +components: + schemas: + Book: + type: object + properties: + classification: + $ref: '#/components/schemas/Classification' + Classification: + oneOf: + - $ref: '#/components/schemas/Novel' + - $ref: '#/components/schemas/Textbook' + discriminator: + required: true + propertyName: type + + + Novel: + type: object + required: + - type + properties: + type: + type: string + genre: + type: string + + Textbook: + type: object + properties: + type: + type: string + field: + type: string + diff --git a/internal/test/parameters/doc.go b/internal/test/parameters/doc.go index e4b88fb55..0db61a22e 100644 --- a/internal/test/parameters/doc.go +++ b/internal/test/parameters/doc.go @@ -1,3 +1,3 @@ package parameters -//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --package=parameters -o parameters.gen.go parameters.yaml +//go:generate go run github.com/weberr13/oapi-codegen/cmd/oapi-codegen --package=parameters -o parameters.gen.go parameters.yaml diff --git a/internal/test/parameters/parameters.gen.go b/internal/test/parameters/parameters.gen.go deleted file mode 100644 index 835b987e5..000000000 --- a/internal/test/parameters/parameters.gen.go +++ /dev/null @@ -1,2869 +0,0 @@ -// Package parameters provides primitives to interact the openapi HTTP API. -// -// Code generated by github.com/deepmap/oapi-codegen DO NOT EDIT. -package parameters - -import ( - "bytes" - "compress/gzip" - "context" - "encoding/base64" - "encoding/json" - "fmt" - "github.com/deepmap/oapi-codegen/pkg/runtime" - "github.com/getkin/kin-openapi/openapi3" - "github.com/labstack/echo/v4" - "io/ioutil" - "net/http" - "net/url" - "strings" -) - -// ComplexObject defines model for ComplexObject. -type ComplexObject struct { - Id string `json:"Id"` - Object Object `json:"Object"` -} - -// Object defines model for Object. -type Object struct { - FirstName string `json:"firstName"` - Role string `json:"role"` -} - -// GetCookieParams defines parameters for GetCookie. -type GetCookieParams struct { - - // primitive - P *int32 `json:"p,omitempty"` - - // primitive - Ep *int32 `json:"ep,omitempty"` - - // exploded array - Ea *[]int32 `json:"ea,omitempty"` - - // array - A *[]int32 `json:"a,omitempty"` - - // exploded object - Eo *Object `json:"eo,omitempty"` - - // object - O *Object `json:"o,omitempty"` - - // complex object - Co *ComplexObject `json:"co,omitempty"` -} - -// GetHeaderParams defines parameters for GetHeader. -type GetHeaderParams struct { - - // primitive - XPrimitive *int32 `json:"X-Primitive,omitempty"` - - // primitive - XPrimitiveExploded *int32 `json:"X-Primitive-Exploded,omitempty"` - - // exploded array - XArrayExploded *[]int32 `json:"X-Array-Exploded,omitempty"` - - // array - XArray *[]int32 `json:"X-Array,omitempty"` - - // exploded object - XObjectExploded *Object `json:"X-Object-Exploded,omitempty"` - - // object - XObject *Object `json:"X-Object,omitempty"` - - // complex object - XComplexObject *ComplexObject `json:"X-Complex-Object,omitempty"` -} - -// GetQueryFormParams defines parameters for GetQueryForm. -type GetQueryFormParams struct { - - // exploded array - Ea *[]int32 `json:"ea,omitempty"` - - // array - A *[]int32 `json:"a,omitempty"` - - // exploded object - Eo *Object `json:"eo,omitempty"` - - // object - O *Object `json:"o,omitempty"` - - // exploded primitive - Ep *int32 `json:"ep,omitempty"` - - // primitive - P *int32 `json:"p,omitempty"` - - // complex object - Co *ComplexObject `json:"co,omitempty"` -} - -// RequestEditorFn is the function signature for the RequestEditor callback function -type RequestEditorFn func(req *http.Request, ctx context.Context) 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. - Server string - - // Doer for performing requests, typically a *http.Client with any - // customized settings, such as certificate chains. - Client HttpRequestDoer - - // A callback for modifying requests which are generated before sending over - // the network. - RequestEditor 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 - } - } - // create httpClient, if not already present - if client.Client == nil { - client.Client = http.DefaultClient - } - 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.RequestEditor = fn - return nil - } -} - -// The interface specification for the client above. -type ClientInterface interface { - // GetContentObject request - GetContentObject(ctx context.Context, param ComplexObject) (*http.Response, error) - - // GetCookie request - GetCookie(ctx context.Context, params *GetCookieParams) (*http.Response, error) - - // GetHeader request - GetHeader(ctx context.Context, params *GetHeaderParams) (*http.Response, error) - - // GetLabelExplodeArray request - GetLabelExplodeArray(ctx context.Context, param []int32) (*http.Response, error) - - // GetLabelExplodeObject request - GetLabelExplodeObject(ctx context.Context, param Object) (*http.Response, error) - - // GetLabelNoExplodeArray request - GetLabelNoExplodeArray(ctx context.Context, param []int32) (*http.Response, error) - - // GetLabelNoExplodeObject request - GetLabelNoExplodeObject(ctx context.Context, param Object) (*http.Response, error) - - // GetMatrixExplodeArray request - GetMatrixExplodeArray(ctx context.Context, id []int32) (*http.Response, error) - - // GetMatrixExplodeObject request - GetMatrixExplodeObject(ctx context.Context, id Object) (*http.Response, error) - - // GetMatrixNoExplodeArray request - GetMatrixNoExplodeArray(ctx context.Context, id []int32) (*http.Response, error) - - // GetMatrixNoExplodeObject request - GetMatrixNoExplodeObject(ctx context.Context, id Object) (*http.Response, error) - - // GetPassThrough request - GetPassThrough(ctx context.Context, param string) (*http.Response, error) - - // GetQueryForm request - GetQueryForm(ctx context.Context, params *GetQueryFormParams) (*http.Response, error) - - // GetSimpleExplodeArray request - GetSimpleExplodeArray(ctx context.Context, param []int32) (*http.Response, error) - - // GetSimpleExplodeObject request - GetSimpleExplodeObject(ctx context.Context, param Object) (*http.Response, error) - - // GetSimpleNoExplodeArray request - GetSimpleNoExplodeArray(ctx context.Context, param []int32) (*http.Response, error) - - // GetSimpleNoExplodeObject request - GetSimpleNoExplodeObject(ctx context.Context, param Object) (*http.Response, error) - - // GetSimplePrimitive request - GetSimplePrimitive(ctx context.Context, param int32) (*http.Response, error) -} - -func (c *Client) GetContentObject(ctx context.Context, param ComplexObject) (*http.Response, error) { - req, err := NewGetContentObjectRequest(c.Server, param) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) GetCookie(ctx context.Context, params *GetCookieParams) (*http.Response, error) { - req, err := NewGetCookieRequest(c.Server, params) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) GetHeader(ctx context.Context, params *GetHeaderParams) (*http.Response, error) { - req, err := NewGetHeaderRequest(c.Server, params) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) GetLabelExplodeArray(ctx context.Context, param []int32) (*http.Response, error) { - req, err := NewGetLabelExplodeArrayRequest(c.Server, param) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) GetLabelExplodeObject(ctx context.Context, param Object) (*http.Response, error) { - req, err := NewGetLabelExplodeObjectRequest(c.Server, param) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) GetLabelNoExplodeArray(ctx context.Context, param []int32) (*http.Response, error) { - req, err := NewGetLabelNoExplodeArrayRequest(c.Server, param) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) GetLabelNoExplodeObject(ctx context.Context, param Object) (*http.Response, error) { - req, err := NewGetLabelNoExplodeObjectRequest(c.Server, param) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) GetMatrixExplodeArray(ctx context.Context, id []int32) (*http.Response, error) { - req, err := NewGetMatrixExplodeArrayRequest(c.Server, id) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) GetMatrixExplodeObject(ctx context.Context, id Object) (*http.Response, error) { - req, err := NewGetMatrixExplodeObjectRequest(c.Server, id) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) GetMatrixNoExplodeArray(ctx context.Context, id []int32) (*http.Response, error) { - req, err := NewGetMatrixNoExplodeArrayRequest(c.Server, id) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) GetMatrixNoExplodeObject(ctx context.Context, id Object) (*http.Response, error) { - req, err := NewGetMatrixNoExplodeObjectRequest(c.Server, id) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) GetPassThrough(ctx context.Context, param string) (*http.Response, error) { - req, err := NewGetPassThroughRequest(c.Server, param) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) GetQueryForm(ctx context.Context, params *GetQueryFormParams) (*http.Response, error) { - req, err := NewGetQueryFormRequest(c.Server, params) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) GetSimpleExplodeArray(ctx context.Context, param []int32) (*http.Response, error) { - req, err := NewGetSimpleExplodeArrayRequest(c.Server, param) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) GetSimpleExplodeObject(ctx context.Context, param Object) (*http.Response, error) { - req, err := NewGetSimpleExplodeObjectRequest(c.Server, param) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) GetSimpleNoExplodeArray(ctx context.Context, param []int32) (*http.Response, error) { - req, err := NewGetSimpleNoExplodeArrayRequest(c.Server, param) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) GetSimpleNoExplodeObject(ctx context.Context, param Object) (*http.Response, error) { - req, err := NewGetSimpleNoExplodeObjectRequest(c.Server, param) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) GetSimplePrimitive(ctx context.Context, param int32) (*http.Response, error) { - req, err := NewGetSimplePrimitiveRequest(c.Server, param) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -// NewGetContentObjectRequest generates requests for GetContentObject -func NewGetContentObjectRequest(server string, param ComplexObject) (*http.Request, error) { - var err error - - var pathParam0 string - - var pathParamBuf0 []byte - pathParamBuf0, err = json.Marshal(param) - if err != nil { - return nil, err - } - pathParam0 = string(pathParamBuf0) - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/contentObject/%s", pathParam0)) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryUrl.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetCookieRequest generates requests for GetCookie -func NewGetCookieRequest(server string, params *GetCookieParams) (*http.Request, error) { - var err error - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/cookie")) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryUrl.String(), nil) - if err != nil { - return nil, err - } - - if params.P != nil { - var cookieParam0 string - - cookieParam0, err = runtime.StyleParam("simple", false, "p", *params.P) - if err != nil { - return nil, err - } - - cookie0 := &http.Cookie{ - Name: "p", - Value: cookieParam0, - } - req.AddCookie(cookie0) - } - - if params.Ep != nil { - var cookieParam1 string - - cookieParam1, err = runtime.StyleParam("simple", true, "ep", *params.Ep) - if err != nil { - return nil, err - } - - cookie1 := &http.Cookie{ - Name: "ep", - Value: cookieParam1, - } - req.AddCookie(cookie1) - } - - if params.Ea != nil { - var cookieParam2 string - - cookieParam2, err = runtime.StyleParam("simple", true, "ea", *params.Ea) - if err != nil { - return nil, err - } - - cookie2 := &http.Cookie{ - Name: "ea", - Value: cookieParam2, - } - req.AddCookie(cookie2) - } - - if params.A != nil { - var cookieParam3 string - - cookieParam3, err = runtime.StyleParam("simple", false, "a", *params.A) - if err != nil { - return nil, err - } - - cookie3 := &http.Cookie{ - Name: "a", - Value: cookieParam3, - } - req.AddCookie(cookie3) - } - - if params.Eo != nil { - var cookieParam4 string - - cookieParam4, err = runtime.StyleParam("simple", true, "eo", *params.Eo) - if err != nil { - return nil, err - } - - cookie4 := &http.Cookie{ - Name: "eo", - Value: cookieParam4, - } - req.AddCookie(cookie4) - } - - if params.O != nil { - var cookieParam5 string - - cookieParam5, err = runtime.StyleParam("simple", false, "o", *params.O) - if err != nil { - return nil, err - } - - cookie5 := &http.Cookie{ - Name: "o", - Value: cookieParam5, - } - req.AddCookie(cookie5) - } - - if params.Co != nil { - var cookieParam6 string - - var cookieParamBuf6 []byte - cookieParamBuf6, err = json.Marshal(*params.Co) - if err != nil { - return nil, err - } - cookieParam6 = url.QueryEscape(string(cookieParamBuf6)) - - cookie6 := &http.Cookie{ - Name: "co", - Value: cookieParam6, - } - req.AddCookie(cookie6) - } - - return req, nil -} - -// NewGetHeaderRequest generates requests for GetHeader -func NewGetHeaderRequest(server string, params *GetHeaderParams) (*http.Request, error) { - var err error - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/header")) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryUrl.String(), nil) - if err != nil { - return nil, err - } - - if params.XPrimitive != nil { - var headerParam0 string - - headerParam0, err = runtime.StyleParam("simple", false, "X-Primitive", *params.XPrimitive) - if err != nil { - return nil, err - } - - req.Header.Add("X-Primitive", headerParam0) - } - - if params.XPrimitiveExploded != nil { - var headerParam1 string - - headerParam1, err = runtime.StyleParam("simple", true, "X-Primitive-Exploded", *params.XPrimitiveExploded) - if err != nil { - return nil, err - } - - req.Header.Add("X-Primitive-Exploded", headerParam1) - } - - if params.XArrayExploded != nil { - var headerParam2 string - - headerParam2, err = runtime.StyleParam("simple", true, "X-Array-Exploded", *params.XArrayExploded) - if err != nil { - return nil, err - } - - req.Header.Add("X-Array-Exploded", headerParam2) - } - - if params.XArray != nil { - var headerParam3 string - - headerParam3, err = runtime.StyleParam("simple", false, "X-Array", *params.XArray) - if err != nil { - return nil, err - } - - req.Header.Add("X-Array", headerParam3) - } - - if params.XObjectExploded != nil { - var headerParam4 string - - headerParam4, err = runtime.StyleParam("simple", true, "X-Object-Exploded", *params.XObjectExploded) - if err != nil { - return nil, err - } - - req.Header.Add("X-Object-Exploded", headerParam4) - } - - if params.XObject != nil { - var headerParam5 string - - headerParam5, err = runtime.StyleParam("simple", false, "X-Object", *params.XObject) - if err != nil { - return nil, err - } - - req.Header.Add("X-Object", headerParam5) - } - - if params.XComplexObject != nil { - var headerParam6 string - - var headerParamBuf6 []byte - headerParamBuf6, err = json.Marshal(*params.XComplexObject) - if err != nil { - return nil, err - } - headerParam6 = string(headerParamBuf6) - - req.Header.Add("X-Complex-Object", headerParam6) - } - - return req, nil -} - -// NewGetLabelExplodeArrayRequest generates requests for GetLabelExplodeArray -func NewGetLabelExplodeArrayRequest(server string, param []int32) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParam("label", true, "param", param) - if err != nil { - return nil, err - } - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/labelExplodeArray/%s", pathParam0)) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryUrl.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetLabelExplodeObjectRequest generates requests for GetLabelExplodeObject -func NewGetLabelExplodeObjectRequest(server string, param Object) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParam("label", true, "param", param) - if err != nil { - return nil, err - } - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/labelExplodeObject/%s", pathParam0)) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryUrl.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetLabelNoExplodeArrayRequest generates requests for GetLabelNoExplodeArray -func NewGetLabelNoExplodeArrayRequest(server string, param []int32) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParam("label", false, "param", param) - if err != nil { - return nil, err - } - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/labelNoExplodeArray/%s", pathParam0)) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryUrl.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetLabelNoExplodeObjectRequest generates requests for GetLabelNoExplodeObject -func NewGetLabelNoExplodeObjectRequest(server string, param Object) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParam("label", false, "param", param) - if err != nil { - return nil, err - } - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/labelNoExplodeObject/%s", pathParam0)) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryUrl.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetMatrixExplodeArrayRequest generates requests for GetMatrixExplodeArray -func NewGetMatrixExplodeArrayRequest(server string, id []int32) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParam("matrix", true, "id", id) - if err != nil { - return nil, err - } - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/matrixExplodeArray/%s", pathParam0)) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryUrl.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetMatrixExplodeObjectRequest generates requests for GetMatrixExplodeObject -func NewGetMatrixExplodeObjectRequest(server string, id Object) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParam("matrix", true, "id", id) - if err != nil { - return nil, err - } - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/matrixExplodeObject/%s", pathParam0)) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryUrl.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetMatrixNoExplodeArrayRequest generates requests for GetMatrixNoExplodeArray -func NewGetMatrixNoExplodeArrayRequest(server string, id []int32) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParam("matrix", false, "id", id) - if err != nil { - return nil, err - } - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/matrixNoExplodeArray/%s", pathParam0)) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryUrl.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetMatrixNoExplodeObjectRequest generates requests for GetMatrixNoExplodeObject -func NewGetMatrixNoExplodeObjectRequest(server string, id Object) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParam("matrix", false, "id", id) - if err != nil { - return nil, err - } - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/matrixNoExplodeObject/%s", pathParam0)) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryUrl.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetPassThroughRequest generates requests for GetPassThrough -func NewGetPassThroughRequest(server string, param string) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0 = param - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/passThrough/%s", pathParam0)) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryUrl.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetQueryFormRequest generates requests for GetQueryForm -func NewGetQueryFormRequest(server string, params *GetQueryFormParams) (*http.Request, error) { - var err error - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/queryForm")) - if err != nil { - return nil, err - } - - queryValues := queryUrl.Query() - - if params.Ea != nil { - - if queryFrag, err := runtime.StyleParam("form", true, "ea", *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 queryFrag, err := runtime.StyleParam("form", false, "a", *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 queryFrag, err := runtime.StyleParam("form", true, "eo", *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 queryFrag, err := runtime.StyleParam("form", false, "o", *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 queryFrag, err := runtime.StyleParam("form", true, "ep", *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 queryFrag, err := runtime.StyleParam("form", false, "p", *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.Co != nil { - - if queryParamBuf, err := json.Marshal(*params.Co); err != nil { - return nil, err - } else { - queryValues.Add("co", string(queryParamBuf)) - } - - } - - queryUrl.RawQuery = queryValues.Encode() - - req, err := http.NewRequest("GET", queryUrl.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetSimpleExplodeArrayRequest generates requests for GetSimpleExplodeArray -func NewGetSimpleExplodeArrayRequest(server string, param []int32) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParam("simple", true, "param", param) - if err != nil { - return nil, err - } - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/simpleExplodeArray/%s", pathParam0)) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryUrl.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetSimpleExplodeObjectRequest generates requests for GetSimpleExplodeObject -func NewGetSimpleExplodeObjectRequest(server string, param Object) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParam("simple", true, "param", param) - if err != nil { - return nil, err - } - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/simpleExplodeObject/%s", pathParam0)) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryUrl.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetSimpleNoExplodeArrayRequest generates requests for GetSimpleNoExplodeArray -func NewGetSimpleNoExplodeArrayRequest(server string, param []int32) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParam("simple", false, "param", param) - if err != nil { - return nil, err - } - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/simpleNoExplodeArray/%s", pathParam0)) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryUrl.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetSimpleNoExplodeObjectRequest generates requests for GetSimpleNoExplodeObject -func NewGetSimpleNoExplodeObjectRequest(server string, param Object) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParam("simple", false, "param", param) - if err != nil { - return nil, err - } - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/simpleNoExplodeObject/%s", pathParam0)) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryUrl.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetSimplePrimitiveRequest generates requests for GetSimplePrimitive -func NewGetSimplePrimitiveRequest(server string, param int32) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParam("simple", false, "param", param) - if err != nil { - return nil, err - } - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/simplePrimitive/%s", pathParam0)) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryUrl.String(), nil) - if err != nil { - return nil, err - } - - return req, 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 { - if !strings.HasSuffix(baseURL, "/") { - baseURL += "/" - } - newBaseURL, err := url.Parse(baseURL) - if err != nil { - return err - } - c.Server = newBaseURL.String() - return nil - } -} - -type getContentObjectResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r getContentObjectResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r getContentObjectResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type getCookieResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r getCookieResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r getCookieResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type getHeaderResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r getHeaderResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r getHeaderResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type getLabelExplodeArrayResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r getLabelExplodeArrayResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r getLabelExplodeArrayResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type getLabelExplodeObjectResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r getLabelExplodeObjectResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r getLabelExplodeObjectResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type getLabelNoExplodeArrayResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r getLabelNoExplodeArrayResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r getLabelNoExplodeArrayResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type getLabelNoExplodeObjectResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r getLabelNoExplodeObjectResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r getLabelNoExplodeObjectResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type getMatrixExplodeArrayResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r getMatrixExplodeArrayResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r getMatrixExplodeArrayResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type getMatrixExplodeObjectResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r getMatrixExplodeObjectResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r getMatrixExplodeObjectResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type getMatrixNoExplodeArrayResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r getMatrixNoExplodeArrayResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r getMatrixNoExplodeArrayResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type getMatrixNoExplodeObjectResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r getMatrixNoExplodeObjectResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r getMatrixNoExplodeObjectResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type getPassThroughResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r getPassThroughResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r getPassThroughResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type getQueryFormResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r getQueryFormResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r getQueryFormResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type getSimpleExplodeArrayResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r getSimpleExplodeArrayResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r getSimpleExplodeArrayResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type getSimpleExplodeObjectResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r getSimpleExplodeObjectResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r getSimpleExplodeObjectResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type getSimpleNoExplodeArrayResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r getSimpleNoExplodeArrayResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r getSimpleNoExplodeArrayResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type getSimpleNoExplodeObjectResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r getSimpleNoExplodeObjectResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r getSimpleNoExplodeObjectResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type getSimplePrimitiveResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r getSimplePrimitiveResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r getSimplePrimitiveResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -// GetContentObjectWithResponse request returning *GetContentObjectResponse -func (c *ClientWithResponses) GetContentObjectWithResponse(ctx context.Context, param ComplexObject) (*getContentObjectResponse, error) { - rsp, err := c.GetContentObject(ctx, param) - if err != nil { - return nil, err - } - return ParseGetContentObjectResponse(rsp) -} - -// GetCookieWithResponse request returning *GetCookieResponse -func (c *ClientWithResponses) GetCookieWithResponse(ctx context.Context, params *GetCookieParams) (*getCookieResponse, error) { - rsp, err := c.GetCookie(ctx, params) - if err != nil { - return nil, err - } - return ParseGetCookieResponse(rsp) -} - -// GetHeaderWithResponse request returning *GetHeaderResponse -func (c *ClientWithResponses) GetHeaderWithResponse(ctx context.Context, params *GetHeaderParams) (*getHeaderResponse, error) { - rsp, err := c.GetHeader(ctx, params) - if err != nil { - return nil, err - } - return ParseGetHeaderResponse(rsp) -} - -// GetLabelExplodeArrayWithResponse request returning *GetLabelExplodeArrayResponse -func (c *ClientWithResponses) GetLabelExplodeArrayWithResponse(ctx context.Context, param []int32) (*getLabelExplodeArrayResponse, error) { - rsp, err := c.GetLabelExplodeArray(ctx, param) - if err != nil { - return nil, err - } - return ParseGetLabelExplodeArrayResponse(rsp) -} - -// GetLabelExplodeObjectWithResponse request returning *GetLabelExplodeObjectResponse -func (c *ClientWithResponses) GetLabelExplodeObjectWithResponse(ctx context.Context, param Object) (*getLabelExplodeObjectResponse, error) { - rsp, err := c.GetLabelExplodeObject(ctx, param) - if err != nil { - return nil, err - } - return ParseGetLabelExplodeObjectResponse(rsp) -} - -// GetLabelNoExplodeArrayWithResponse request returning *GetLabelNoExplodeArrayResponse -func (c *ClientWithResponses) GetLabelNoExplodeArrayWithResponse(ctx context.Context, param []int32) (*getLabelNoExplodeArrayResponse, error) { - rsp, err := c.GetLabelNoExplodeArray(ctx, param) - if err != nil { - return nil, err - } - return ParseGetLabelNoExplodeArrayResponse(rsp) -} - -// GetLabelNoExplodeObjectWithResponse request returning *GetLabelNoExplodeObjectResponse -func (c *ClientWithResponses) GetLabelNoExplodeObjectWithResponse(ctx context.Context, param Object) (*getLabelNoExplodeObjectResponse, error) { - rsp, err := c.GetLabelNoExplodeObject(ctx, param) - if err != nil { - return nil, err - } - return ParseGetLabelNoExplodeObjectResponse(rsp) -} - -// GetMatrixExplodeArrayWithResponse request returning *GetMatrixExplodeArrayResponse -func (c *ClientWithResponses) GetMatrixExplodeArrayWithResponse(ctx context.Context, id []int32) (*getMatrixExplodeArrayResponse, error) { - rsp, err := c.GetMatrixExplodeArray(ctx, id) - if err != nil { - return nil, err - } - return ParseGetMatrixExplodeArrayResponse(rsp) -} - -// GetMatrixExplodeObjectWithResponse request returning *GetMatrixExplodeObjectResponse -func (c *ClientWithResponses) GetMatrixExplodeObjectWithResponse(ctx context.Context, id Object) (*getMatrixExplodeObjectResponse, error) { - rsp, err := c.GetMatrixExplodeObject(ctx, id) - if err != nil { - return nil, err - } - return ParseGetMatrixExplodeObjectResponse(rsp) -} - -// GetMatrixNoExplodeArrayWithResponse request returning *GetMatrixNoExplodeArrayResponse -func (c *ClientWithResponses) GetMatrixNoExplodeArrayWithResponse(ctx context.Context, id []int32) (*getMatrixNoExplodeArrayResponse, error) { - rsp, err := c.GetMatrixNoExplodeArray(ctx, id) - if err != nil { - return nil, err - } - return ParseGetMatrixNoExplodeArrayResponse(rsp) -} - -// GetMatrixNoExplodeObjectWithResponse request returning *GetMatrixNoExplodeObjectResponse -func (c *ClientWithResponses) GetMatrixNoExplodeObjectWithResponse(ctx context.Context, id Object) (*getMatrixNoExplodeObjectResponse, error) { - rsp, err := c.GetMatrixNoExplodeObject(ctx, id) - if err != nil { - return nil, err - } - return ParseGetMatrixNoExplodeObjectResponse(rsp) -} - -// GetPassThroughWithResponse request returning *GetPassThroughResponse -func (c *ClientWithResponses) GetPassThroughWithResponse(ctx context.Context, param string) (*getPassThroughResponse, error) { - rsp, err := c.GetPassThrough(ctx, param) - if err != nil { - return nil, err - } - return ParseGetPassThroughResponse(rsp) -} - -// GetQueryFormWithResponse request returning *GetQueryFormResponse -func (c *ClientWithResponses) GetQueryFormWithResponse(ctx context.Context, params *GetQueryFormParams) (*getQueryFormResponse, error) { - rsp, err := c.GetQueryForm(ctx, params) - if err != nil { - return nil, err - } - return ParseGetQueryFormResponse(rsp) -} - -// GetSimpleExplodeArrayWithResponse request returning *GetSimpleExplodeArrayResponse -func (c *ClientWithResponses) GetSimpleExplodeArrayWithResponse(ctx context.Context, param []int32) (*getSimpleExplodeArrayResponse, error) { - rsp, err := c.GetSimpleExplodeArray(ctx, param) - if err != nil { - return nil, err - } - return ParseGetSimpleExplodeArrayResponse(rsp) -} - -// GetSimpleExplodeObjectWithResponse request returning *GetSimpleExplodeObjectResponse -func (c *ClientWithResponses) GetSimpleExplodeObjectWithResponse(ctx context.Context, param Object) (*getSimpleExplodeObjectResponse, error) { - rsp, err := c.GetSimpleExplodeObject(ctx, param) - if err != nil { - return nil, err - } - return ParseGetSimpleExplodeObjectResponse(rsp) -} - -// GetSimpleNoExplodeArrayWithResponse request returning *GetSimpleNoExplodeArrayResponse -func (c *ClientWithResponses) GetSimpleNoExplodeArrayWithResponse(ctx context.Context, param []int32) (*getSimpleNoExplodeArrayResponse, error) { - rsp, err := c.GetSimpleNoExplodeArray(ctx, param) - if err != nil { - return nil, err - } - return ParseGetSimpleNoExplodeArrayResponse(rsp) -} - -// GetSimpleNoExplodeObjectWithResponse request returning *GetSimpleNoExplodeObjectResponse -func (c *ClientWithResponses) GetSimpleNoExplodeObjectWithResponse(ctx context.Context, param Object) (*getSimpleNoExplodeObjectResponse, error) { - rsp, err := c.GetSimpleNoExplodeObject(ctx, param) - if err != nil { - return nil, err - } - return ParseGetSimpleNoExplodeObjectResponse(rsp) -} - -// GetSimplePrimitiveWithResponse request returning *GetSimplePrimitiveResponse -func (c *ClientWithResponses) GetSimplePrimitiveWithResponse(ctx context.Context, param int32) (*getSimplePrimitiveResponse, error) { - rsp, err := c.GetSimplePrimitive(ctx, param) - if err != nil { - return nil, err - } - return ParseGetSimplePrimitiveResponse(rsp) -} - -// ParseGetContentObjectResponse parses an HTTP response from a GetContentObjectWithResponse call -func ParseGetContentObjectResponse(rsp *http.Response) (*getContentObjectResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &getContentObjectResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ParseGetCookieResponse parses an HTTP response from a GetCookieWithResponse call -func ParseGetCookieResponse(rsp *http.Response) (*getCookieResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &getCookieResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ParseGetHeaderResponse parses an HTTP response from a GetHeaderWithResponse call -func ParseGetHeaderResponse(rsp *http.Response) (*getHeaderResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &getHeaderResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ParseGetLabelExplodeArrayResponse parses an HTTP response from a GetLabelExplodeArrayWithResponse call -func ParseGetLabelExplodeArrayResponse(rsp *http.Response) (*getLabelExplodeArrayResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &getLabelExplodeArrayResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ParseGetLabelExplodeObjectResponse parses an HTTP response from a GetLabelExplodeObjectWithResponse call -func ParseGetLabelExplodeObjectResponse(rsp *http.Response) (*getLabelExplodeObjectResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &getLabelExplodeObjectResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ParseGetLabelNoExplodeArrayResponse parses an HTTP response from a GetLabelNoExplodeArrayWithResponse call -func ParseGetLabelNoExplodeArrayResponse(rsp *http.Response) (*getLabelNoExplodeArrayResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &getLabelNoExplodeArrayResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ParseGetLabelNoExplodeObjectResponse parses an HTTP response from a GetLabelNoExplodeObjectWithResponse call -func ParseGetLabelNoExplodeObjectResponse(rsp *http.Response) (*getLabelNoExplodeObjectResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &getLabelNoExplodeObjectResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ParseGetMatrixExplodeArrayResponse parses an HTTP response from a GetMatrixExplodeArrayWithResponse call -func ParseGetMatrixExplodeArrayResponse(rsp *http.Response) (*getMatrixExplodeArrayResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &getMatrixExplodeArrayResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ParseGetMatrixExplodeObjectResponse parses an HTTP response from a GetMatrixExplodeObjectWithResponse call -func ParseGetMatrixExplodeObjectResponse(rsp *http.Response) (*getMatrixExplodeObjectResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &getMatrixExplodeObjectResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ParseGetMatrixNoExplodeArrayResponse parses an HTTP response from a GetMatrixNoExplodeArrayWithResponse call -func ParseGetMatrixNoExplodeArrayResponse(rsp *http.Response) (*getMatrixNoExplodeArrayResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &getMatrixNoExplodeArrayResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ParseGetMatrixNoExplodeObjectResponse parses an HTTP response from a GetMatrixNoExplodeObjectWithResponse call -func ParseGetMatrixNoExplodeObjectResponse(rsp *http.Response) (*getMatrixNoExplodeObjectResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &getMatrixNoExplodeObjectResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ParseGetPassThroughResponse parses an HTTP response from a GetPassThroughWithResponse call -func ParseGetPassThroughResponse(rsp *http.Response) (*getPassThroughResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &getPassThroughResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ParseGetQueryFormResponse parses an HTTP response from a GetQueryFormWithResponse call -func ParseGetQueryFormResponse(rsp *http.Response) (*getQueryFormResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &getQueryFormResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ParseGetSimpleExplodeArrayResponse parses an HTTP response from a GetSimpleExplodeArrayWithResponse call -func ParseGetSimpleExplodeArrayResponse(rsp *http.Response) (*getSimpleExplodeArrayResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &getSimpleExplodeArrayResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ParseGetSimpleExplodeObjectResponse parses an HTTP response from a GetSimpleExplodeObjectWithResponse call -func ParseGetSimpleExplodeObjectResponse(rsp *http.Response) (*getSimpleExplodeObjectResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &getSimpleExplodeObjectResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ParseGetSimpleNoExplodeArrayResponse parses an HTTP response from a GetSimpleNoExplodeArrayWithResponse call -func ParseGetSimpleNoExplodeArrayResponse(rsp *http.Response) (*getSimpleNoExplodeArrayResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &getSimpleNoExplodeArrayResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ParseGetSimpleNoExplodeObjectResponse parses an HTTP response from a GetSimpleNoExplodeObjectWithResponse call -func ParseGetSimpleNoExplodeObjectResponse(rsp *http.Response) (*getSimpleNoExplodeObjectResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &getSimpleNoExplodeObjectResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ParseGetSimplePrimitiveResponse parses an HTTP response from a GetSimplePrimitiveWithResponse call -func ParseGetSimplePrimitiveResponse(rsp *http.Response) (*getSimplePrimitiveResponse, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &getSimplePrimitiveResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ServerInterface represents all server handlers. -type ServerInterface interface { - - // (GET /contentObject/{param}) - GetContentObject(ctx echo.Context, param ComplexObject) error - - // (GET /cookie) - GetCookie(ctx echo.Context, params GetCookieParams) error - - // (GET /header) - GetHeader(ctx echo.Context, params GetHeaderParams) error - - // (GET /labelExplodeArray/{.param*}) - GetLabelExplodeArray(ctx echo.Context, param []int32) error - - // (GET /labelExplodeObject/{.param*}) - GetLabelExplodeObject(ctx echo.Context, param Object) error - - // (GET /labelNoExplodeArray/{.param}) - GetLabelNoExplodeArray(ctx echo.Context, param []int32) error - - // (GET /labelNoExplodeObject/{.param}) - GetLabelNoExplodeObject(ctx echo.Context, param Object) error - - // (GET /matrixExplodeArray/{.id*}) - GetMatrixExplodeArray(ctx echo.Context, id []int32) error - - // (GET /matrixExplodeObject/{.id*}) - GetMatrixExplodeObject(ctx echo.Context, id Object) error - - // (GET /matrixNoExplodeArray/{.id}) - GetMatrixNoExplodeArray(ctx echo.Context, id []int32) error - - // (GET /matrixNoExplodeObject/{.id}) - GetMatrixNoExplodeObject(ctx echo.Context, id Object) error - - // (GET /passThrough/{param}) - GetPassThrough(ctx echo.Context, param string) error - - // (GET /queryForm) - GetQueryForm(ctx echo.Context, params GetQueryFormParams) error - - // (GET /simpleExplodeArray/{param*}) - GetSimpleExplodeArray(ctx echo.Context, param []int32) error - - // (GET /simpleExplodeObject/{param*}) - GetSimpleExplodeObject(ctx echo.Context, param Object) error - - // (GET /simpleNoExplodeArray/{param}) - GetSimpleNoExplodeArray(ctx echo.Context, param []int32) error - - // (GET /simpleNoExplodeObject/{param}) - GetSimpleNoExplodeObject(ctx echo.Context, param Object) error - - // (GET /simplePrimitive/{param}) - GetSimplePrimitive(ctx echo.Context, param int32) error -} - -// ServerInterfaceWrapper converts echo contexts to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface -} - -// GetContentObject converts echo context to params. -func (w *ServerInterfaceWrapper) GetContentObject(ctx echo.Context) error { - var err error - // ------------- Path parameter "param" ------------- - var param ComplexObject - - err = json.Unmarshal([]byte(ctx.Param("param")), ¶m) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter 'param' as JSON") - } - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.GetContentObject(ctx, param) - return err -} - -// GetCookie converts echo context to params. -func (w *ServerInterfaceWrapper) GetCookie(ctx echo.Context) error { - var err error - - // Parameter object where we will unmarshal all parameters from the context - var params GetCookieParams - - if cookie, err := ctx.Cookie("p"); err == nil { - - var value int32 - err = runtime.BindStyledParameter("simple", false, "p", cookie.Value, &value) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter p: %s", err)) - } - params.P = &value - - } - - if cookie, err := ctx.Cookie("ep"); err == nil { - - var value int32 - err = runtime.BindStyledParameter("simple", true, "ep", cookie.Value, &value) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter ep: %s", err)) - } - params.Ep = &value - - } - - if cookie, err := ctx.Cookie("ea"); err == nil { - - var value []int32 - err = runtime.BindStyledParameter("simple", true, "ea", cookie.Value, &value) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter ea: %s", err)) - } - params.Ea = &value - - } - - if cookie, err := ctx.Cookie("a"); err == nil { - - var value []int32 - err = runtime.BindStyledParameter("simple", false, "a", cookie.Value, &value) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter a: %s", err)) - } - params.A = &value - - } - - if cookie, err := ctx.Cookie("eo"); err == nil { - - var value Object - err = runtime.BindStyledParameter("simple", true, "eo", cookie.Value, &value) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter eo: %s", err)) - } - params.Eo = &value - - } - - if cookie, err := ctx.Cookie("o"); err == nil { - - var value Object - err = runtime.BindStyledParameter("simple", false, "o", cookie.Value, &value) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter o: %s", err)) - } - params.O = &value - - } - - if cookie, err := ctx.Cookie("co"); err == nil { - - var value ComplexObject - var decoded string - decoded, err := url.QueryUnescape(cookie.Value) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, "Error unescaping cookie parameter 'co'") - } - err = json.Unmarshal([]byte(decoded), &value) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter 'co' as JSON") - } - params.Co = &value - - } - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.GetCookie(ctx, params) - return err -} - -// GetHeader converts echo context to params. -func (w *ServerInterfaceWrapper) GetHeader(ctx echo.Context) error { - var err error - - // Parameter object where we will unmarshal all parameters from the context - var params GetHeaderParams - - headers := ctx.Request().Header - // ------------- Optional header parameter "X-Primitive" ------------- - if valueList, found := headers[http.CanonicalHeaderKey("X-Primitive")]; found { - var XPrimitive int32 - n := len(valueList) - if n != 1 { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Primitive, got %d", n)) - } - - err = runtime.BindStyledParameter("simple", false, "X-Primitive", valueList[0], &XPrimitive) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter X-Primitive: %s", err)) - } - - params.XPrimitive = &XPrimitive - } - // ------------- Optional header parameter "X-Primitive-Exploded" ------------- - if valueList, found := headers[http.CanonicalHeaderKey("X-Primitive-Exploded")]; found { - var XPrimitiveExploded int32 - n := len(valueList) - if n != 1 { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Primitive-Exploded, got %d", n)) - } - - err = runtime.BindStyledParameter("simple", true, "X-Primitive-Exploded", valueList[0], &XPrimitiveExploded) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter X-Primitive-Exploded: %s", err)) - } - - params.XPrimitiveExploded = &XPrimitiveExploded - } - // ------------- Optional header parameter "X-Array-Exploded" ------------- - if valueList, found := headers[http.CanonicalHeaderKey("X-Array-Exploded")]; found { - var XArrayExploded []int32 - n := len(valueList) - if n != 1 { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Array-Exploded, got %d", n)) - } - - err = runtime.BindStyledParameter("simple", true, "X-Array-Exploded", valueList[0], &XArrayExploded) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter X-Array-Exploded: %s", err)) - } - - params.XArrayExploded = &XArrayExploded - } - // ------------- Optional header parameter "X-Array" ------------- - if valueList, found := headers[http.CanonicalHeaderKey("X-Array")]; found { - var XArray []int32 - n := len(valueList) - if n != 1 { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Array, got %d", n)) - } - - err = runtime.BindStyledParameter("simple", false, "X-Array", valueList[0], &XArray) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter X-Array: %s", err)) - } - - params.XArray = &XArray - } - // ------------- Optional header parameter "X-Object-Exploded" ------------- - if valueList, found := headers[http.CanonicalHeaderKey("X-Object-Exploded")]; found { - var XObjectExploded Object - n := len(valueList) - if n != 1 { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Object-Exploded, got %d", n)) - } - - err = runtime.BindStyledParameter("simple", true, "X-Object-Exploded", valueList[0], &XObjectExploded) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter X-Object-Exploded: %s", err)) - } - - params.XObjectExploded = &XObjectExploded - } - // ------------- Optional header parameter "X-Object" ------------- - if valueList, found := headers[http.CanonicalHeaderKey("X-Object")]; found { - var XObject Object - n := len(valueList) - if n != 1 { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Object, got %d", n)) - } - - err = runtime.BindStyledParameter("simple", false, "X-Object", valueList[0], &XObject) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter X-Object: %s", err)) - } - - params.XObject = &XObject - } - // ------------- Optional header parameter "X-Complex-Object" ------------- - if valueList, found := headers[http.CanonicalHeaderKey("X-Complex-Object")]; found { - var XComplexObject ComplexObject - n := len(valueList) - if n != 1 { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Complex-Object, got %d", n)) - } - - err = json.Unmarshal([]byte(valueList[0]), &XComplexObject) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter 'X-Complex-Object' as JSON") - } - - params.XComplexObject = &XComplexObject - } - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.GetHeader(ctx, params) - return err -} - -// GetLabelExplodeArray converts echo context to params. -func (w *ServerInterfaceWrapper) GetLabelExplodeArray(ctx echo.Context) error { - var err error - // ------------- Path parameter "param" ------------- - var param []int32 - - err = runtime.BindStyledParameter("label", true, "param", ctx.Param("param"), ¶m) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err)) - } - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.GetLabelExplodeArray(ctx, param) - return err -} - -// GetLabelExplodeObject converts echo context to params. -func (w *ServerInterfaceWrapper) GetLabelExplodeObject(ctx echo.Context) error { - var err error - // ------------- Path parameter "param" ------------- - var param Object - - err = runtime.BindStyledParameter("label", true, "param", ctx.Param("param"), ¶m) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err)) - } - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.GetLabelExplodeObject(ctx, param) - return err -} - -// GetLabelNoExplodeArray converts echo context to params. -func (w *ServerInterfaceWrapper) GetLabelNoExplodeArray(ctx echo.Context) error { - var err error - // ------------- Path parameter "param" ------------- - var param []int32 - - err = runtime.BindStyledParameter("label", false, "param", ctx.Param("param"), ¶m) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err)) - } - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.GetLabelNoExplodeArray(ctx, param) - return err -} - -// GetLabelNoExplodeObject converts echo context to params. -func (w *ServerInterfaceWrapper) GetLabelNoExplodeObject(ctx echo.Context) error { - var err error - // ------------- Path parameter "param" ------------- - var param Object - - err = runtime.BindStyledParameter("label", false, "param", ctx.Param("param"), ¶m) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err)) - } - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.GetLabelNoExplodeObject(ctx, param) - return err -} - -// GetMatrixExplodeArray converts echo context to params. -func (w *ServerInterfaceWrapper) GetMatrixExplodeArray(ctx echo.Context) error { - var err error - // ------------- Path parameter "id" ------------- - var id []int32 - - err = runtime.BindStyledParameter("matrix", true, "id", ctx.Param("id"), &id) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err)) - } - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.GetMatrixExplodeArray(ctx, id) - return err -} - -// GetMatrixExplodeObject converts echo context to params. -func (w *ServerInterfaceWrapper) GetMatrixExplodeObject(ctx echo.Context) error { - var err error - // ------------- Path parameter "id" ------------- - var id Object - - err = runtime.BindStyledParameter("matrix", true, "id", ctx.Param("id"), &id) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err)) - } - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.GetMatrixExplodeObject(ctx, id) - return err -} - -// GetMatrixNoExplodeArray converts echo context to params. -func (w *ServerInterfaceWrapper) GetMatrixNoExplodeArray(ctx echo.Context) error { - var err error - // ------------- Path parameter "id" ------------- - var id []int32 - - err = runtime.BindStyledParameter("matrix", false, "id", ctx.Param("id"), &id) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err)) - } - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.GetMatrixNoExplodeArray(ctx, id) - return err -} - -// GetMatrixNoExplodeObject converts echo context to params. -func (w *ServerInterfaceWrapper) GetMatrixNoExplodeObject(ctx echo.Context) error { - var err error - // ------------- Path parameter "id" ------------- - var id Object - - err = runtime.BindStyledParameter("matrix", false, "id", ctx.Param("id"), &id) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err)) - } - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.GetMatrixNoExplodeObject(ctx, id) - return err -} - -// GetPassThrough converts echo context to params. -func (w *ServerInterfaceWrapper) GetPassThrough(ctx echo.Context) error { - var err error - // ------------- Path parameter "param" ------------- - var param string - - param = ctx.Param("param") - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.GetPassThrough(ctx, param) - return err -} - -// GetQueryForm converts echo context to params. -func (w *ServerInterfaceWrapper) GetQueryForm(ctx echo.Context) error { - var err error - - // Parameter object where we will unmarshal all parameters from the context - var params GetQueryFormParams - // ------------- Optional query parameter "ea" ------------- - if paramValue := ctx.QueryParam("ea"); paramValue != "" { - - } - - err = runtime.BindQueryParameter("form", true, false, "ea", ctx.QueryParams(), ¶ms.Ea) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter ea: %s", err)) - } - - // ------------- Optional query parameter "a" ------------- - if paramValue := ctx.QueryParam("a"); paramValue != "" { - - } - - err = runtime.BindQueryParameter("form", false, false, "a", ctx.QueryParams(), ¶ms.A) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter a: %s", err)) - } - - // ------------- Optional query parameter "eo" ------------- - if paramValue := ctx.QueryParam("eo"); paramValue != "" { - - } - - err = runtime.BindQueryParameter("form", true, false, "eo", ctx.QueryParams(), ¶ms.Eo) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter eo: %s", err)) - } - - // ------------- Optional query parameter "o" ------------- - if paramValue := ctx.QueryParam("o"); paramValue != "" { - - } - - err = runtime.BindQueryParameter("form", false, false, "o", ctx.QueryParams(), ¶ms.O) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter o: %s", err)) - } - - // ------------- Optional query parameter "ep" ------------- - if paramValue := ctx.QueryParam("ep"); paramValue != "" { - - } - - err = runtime.BindQueryParameter("form", true, false, "ep", ctx.QueryParams(), ¶ms.Ep) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter ep: %s", err)) - } - - // ------------- Optional query parameter "p" ------------- - if paramValue := ctx.QueryParam("p"); paramValue != "" { - - } - - err = runtime.BindQueryParameter("form", false, false, "p", ctx.QueryParams(), ¶ms.P) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter p: %s", err)) - } - - // ------------- Optional query parameter "co" ------------- - if paramValue := ctx.QueryParam("co"); paramValue != "" { - - var value ComplexObject - err = json.Unmarshal([]byte(paramValue), &value) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter 'co' as JSON") - } - params.Co = &value - - } - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.GetQueryForm(ctx, params) - return err -} - -// GetSimpleExplodeArray converts echo context to params. -func (w *ServerInterfaceWrapper) GetSimpleExplodeArray(ctx echo.Context) error { - var err error - // ------------- Path parameter "param" ------------- - var param []int32 - - err = runtime.BindStyledParameter("simple", true, "param", ctx.Param("param"), ¶m) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err)) - } - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.GetSimpleExplodeArray(ctx, param) - return err -} - -// GetSimpleExplodeObject converts echo context to params. -func (w *ServerInterfaceWrapper) GetSimpleExplodeObject(ctx echo.Context) error { - var err error - // ------------- Path parameter "param" ------------- - var param Object - - err = runtime.BindStyledParameter("simple", true, "param", ctx.Param("param"), ¶m) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err)) - } - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.GetSimpleExplodeObject(ctx, param) - return err -} - -// GetSimpleNoExplodeArray converts echo context to params. -func (w *ServerInterfaceWrapper) GetSimpleNoExplodeArray(ctx echo.Context) error { - var err error - // ------------- Path parameter "param" ------------- - var param []int32 - - err = runtime.BindStyledParameter("simple", false, "param", ctx.Param("param"), ¶m) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err)) - } - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.GetSimpleNoExplodeArray(ctx, param) - return err -} - -// GetSimpleNoExplodeObject converts echo context to params. -func (w *ServerInterfaceWrapper) GetSimpleNoExplodeObject(ctx echo.Context) error { - var err error - // ------------- Path parameter "param" ------------- - var param Object - - err = runtime.BindStyledParameter("simple", false, "param", ctx.Param("param"), ¶m) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err)) - } - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.GetSimpleNoExplodeObject(ctx, param) - return err -} - -// GetSimplePrimitive converts echo context to params. -func (w *ServerInterfaceWrapper) GetSimplePrimitive(ctx echo.Context) error { - var err error - // ------------- Path parameter "param" ------------- - var param int32 - - err = runtime.BindStyledParameter("simple", false, "param", ctx.Param("param"), ¶m) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err)) - } - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.GetSimplePrimitive(ctx, param) - return err -} - -// RegisterHandlers adds each server route to the EchoRouter. -func RegisterHandlers(router interface { - CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route -}, si ServerInterface) { - - wrapper := ServerInterfaceWrapper{ - Handler: si, - } - - router.GET("/contentObject/:param", wrapper.GetContentObject) - router.GET("/cookie", wrapper.GetCookie) - router.GET("/header", wrapper.GetHeader) - router.GET("/labelExplodeArray/:param", wrapper.GetLabelExplodeArray) - router.GET("/labelExplodeObject/:param", wrapper.GetLabelExplodeObject) - router.GET("/labelNoExplodeArray/:param", wrapper.GetLabelNoExplodeArray) - router.GET("/labelNoExplodeObject/:param", wrapper.GetLabelNoExplodeObject) - router.GET("/matrixExplodeArray/:id", wrapper.GetMatrixExplodeArray) - router.GET("/matrixExplodeObject/:id", wrapper.GetMatrixExplodeObject) - router.GET("/matrixNoExplodeArray/:id", wrapper.GetMatrixNoExplodeArray) - router.GET("/matrixNoExplodeObject/:id", wrapper.GetMatrixNoExplodeObject) - router.GET("/passThrough/:param", wrapper.GetPassThrough) - router.GET("/queryForm", wrapper.GetQueryForm) - router.GET("/simpleExplodeArray/:param", wrapper.GetSimpleExplodeArray) - router.GET("/simpleExplodeObject/:param", wrapper.GetSimpleExplodeObject) - router.GET("/simpleNoExplodeArray/:param", wrapper.GetSimpleNoExplodeArray) - router.GET("/simpleNoExplodeObject/:param", wrapper.GetSimpleNoExplodeObject) - router.GET("/simplePrimitive/:param", wrapper.GetSimplePrimitive) - -} - -// Base64 encoded, gzipped, json marshaled Swagger object -var swaggerSpec = []string{ - - "H4sIAAAAAAAC/9xZyW7jOBD9FaNmTgO15e6+6dYIZgkwWWacwwCBD4xUtpmRRIakAxuG/r1BarG1WKYS", - "WXZyi6VaXj0+VcjiFnwWcRZjrCR4WxAoOYslmh9TGvEQ/80e6Sc+ixXGSv+pcK1cHhIa61/SX2JEzPMN", - "R/BAKkHjBSRJ4kCA0heUK8pi8ODHSJq4ozzXiD09o69Am6ZxTPYrpq3Wd+lLbwtcMI5C0RTcddCQzYGd", - "+a8C5+DBL+6uQjcL797tMgp8WVGBAXiPubOjg89Kwcq551RIdUsibIQgWNj0opLLWDl7oWaGKxrPmXYO", - "qY8Z6bFJBDfXDzq6okqHhweUajRF8YoCHHhFIVN6v44n44k2ZBxjwil48H08GX8FBzhRS4PfzdYxrc/d", - "ciJIlOg3CzTl6mKJXi/NMvyJ6mrfwYQSJEKFQoL3WNIF4TykvnF2nyWrqKNtUcoLnrEBnoENTk6DyQz7", - "XCqxwmTmlLX7bTI5lK+wcysCT0xO12fsf4rtbBiLGg1loXNBI6roqzbENQ9ZgODNSSgxK8zPw+SllcrK", - "LHfczZmIiAIPaKy+fwMnFxiNFS5QaIVZQdB8HUCA/UPI0gYjIgTZ2OIg7TiowkhaASqepOkbANZwtS3R", - "gLgK4lj+0Vkxx9oR2nXFKpY6hDaSeoJwqqZSLs1PDXYsN5bkN9SUzEy7WCIJULS1i79Si/e2i2UeJsP0", - "35f7PZdhG0cLli+/Z8I9TyupI/uhrS1RDdZYDsC8tPZSh5l+SZZ0nqLbHIL08ZtOvbIs0MEKsxYUkicM", - "sxUxMnK3Y9Nrfmvd1P1ddau3qCZN2OzH+lGtA1JtzG7XVAg97fIckKsoImIDXrwKwxqF+ba4K4eHdsd9", - "kGij36HpumVNmjtOV9mvha/9z/7zqq6go6y7DjweFd57iLww5UVECbquCI8G7V/pTc3pLV8pDU6uuLS6", - "wfgrFNeJwLf3uSMMdpPaUFzV2hwNLLjqocl9Ir3Ve1w3Et/R4T6Y5jiR8mEp2GqxtBnM3e/MW8dyHca1", - "Zxm6vaxQbP5gImor9p/C6MhZ2uqkaFIOMXPayUe7QseTYgXm+VDanRirrJ5hHlWBcBIEBRnHJiVVPgYa", - "8rbw0QeCcx6TK+U0j+b660zpbVV5C2BxMJzW3C73dJ2WeMr/aiUSS9dOHVi8nPP1UIRVt57H9wPTBr8L", - "PmEPTqT9lee0yfEizthDkVaM9O3p2r+RqBD1JmIspHUaVkzvl+Z6PYW/EiF4sFSKe66b3a0rlGocIPKI", - "8DGhkMySnwEAAP//njtWvlEhAAA=", -} - -// GetSwagger returns the Swagger specification corresponding to the generated code -// in this file. -func GetSwagger() (*openapi3.Swagger, 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) - } - - swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(buf.Bytes()) - if err != nil { - return nil, fmt.Errorf("error loading Swagger: %s", err) - } - return swagger, nil -} diff --git a/internal/test/parameters/parameters_test.go b/internal/test/parameters/parameters_test.go index 466a54ff5..8755b5566 100644 --- a/internal/test/parameters/parameters_test.go +++ b/internal/test/parameters/parameters_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/deepmap/oapi-codegen/pkg/testutil" + "github.com/weberr13/oapi-codegen/pkg/testutil" ) type testServer struct { diff --git a/internal/test/schemas/doc.go b/internal/test/schemas/doc.go index 81a093624..f6dc80930 100644 --- a/internal/test/schemas/doc.go +++ b/internal/test/schemas/doc.go @@ -1,3 +1,3 @@ package schemas -//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --package=schemas -o schemas.gen.go schemas.yaml +//go:generate go run github.com/weberr13/oapi-codegen/cmd/oapi-codegen --package=schemas -o schemas.gen.go schemas.yaml diff --git a/internal/test/schemas/schemas.gen.go b/internal/test/schemas/schemas.gen.go deleted file mode 100644 index b8fe16f42..000000000 --- a/internal/test/schemas/schemas.gen.go +++ /dev/null @@ -1,612 +0,0 @@ -// Package schemas provides primitives to interact the openapi HTTP API. -// -// Code generated by github.com/deepmap/oapi-codegen DO NOT EDIT. -package schemas - -import ( - "bytes" - "compress/gzip" - "context" - "encoding/base64" - "encoding/json" - "fmt" - "github.com/deepmap/oapi-codegen/pkg/runtime" - "github.com/getkin/kin-openapi/openapi3" - "github.com/labstack/echo/v4" - "io" - "io/ioutil" - "net/http" - "net/url" - "strings" -) - -// N5StartsWithNumber defines model for 5StartsWithNumber. -type N5StartsWithNumber map[string]interface{} - -// AnyType1 defines model for AnyType1. -type AnyType1 interface{} - -// AnyType2 defines model for AnyType2. -type AnyType2 interface{} - -// CustomStringType defines model for CustomStringType. -type CustomStringType string - -// GenericObject defines model for GenericObject. -type GenericObject map[string]interface{} - -// Issue9JSONBody defines parameters for Issue9. -type Issue9JSONBody interface{} - -// Issue9Params defines parameters for Issue9. -type Issue9Params struct { - Foo string `json:"foo"` -} - -// Issue9RequestBody defines body for Issue9 for application/json ContentType. -type Issue9JSONRequestBody Issue9JSONBody - -// RequestEditorFn is the function signature for the RequestEditor callback function -type RequestEditorFn func(req *http.Request, ctx context.Context) 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. - Server string - - // Doer for performing requests, typically a *http.Client with any - // customized settings, such as certificate chains. - Client HttpRequestDoer - - // A callback for modifying requests which are generated before sending over - // the network. - RequestEditor 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 - } - } - // create httpClient, if not already present - if client.Client == nil { - client.Client = http.DefaultClient - } - 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.RequestEditor = fn - return nil - } -} - -// The interface specification for the client above. -type ClientInterface interface { - // Issue30 request - Issue30(ctx context.Context, pFallthrough string) (*http.Response, error) - - // Issue41 request - Issue41(ctx context.Context, n1param N5StartsWithNumber) (*http.Response, error) - - // Issue9 request with any body - Issue9WithBody(ctx context.Context, params *Issue9Params, contentType string, body io.Reader) (*http.Response, error) - - Issue9(ctx context.Context, params *Issue9Params, body Issue9JSONRequestBody) (*http.Response, error) -} - -func (c *Client) Issue30(ctx context.Context, pFallthrough string) (*http.Response, error) { - req, err := NewIssue30Request(c.Server, pFallthrough) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) Issue41(ctx context.Context, n1param N5StartsWithNumber) (*http.Response, error) { - req, err := NewIssue41Request(c.Server, n1param) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) Issue9WithBody(ctx context.Context, params *Issue9Params, contentType string, body io.Reader) (*http.Response, error) { - req, err := NewIssue9RequestWithBody(c.Server, params, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -func (c *Client) Issue9(ctx context.Context, params *Issue9Params, body Issue9JSONRequestBody) (*http.Response, error) { - req, err := NewIssue9Request(c.Server, params, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if c.RequestEditor != nil { - err = c.RequestEditor(req, ctx) - if err != nil { - return nil, err - } - } - return c.Client.Do(req) -} - -// NewIssue30Request generates requests for Issue30 -func NewIssue30Request(server string, pFallthrough string) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParam("simple", false, "fallthrough", pFallthrough) - if err != nil { - return nil, err - } - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/issues/30/%s", pathParam0)) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryUrl.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewIssue41Request generates requests for Issue41 -func NewIssue41Request(server string, n1param N5StartsWithNumber) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParam("simple", false, "1param", n1param) - if err != nil { - return nil, err - } - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/issues/41/%s", pathParam0)) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryUrl.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewIssue9Request calls the generic Issue9 builder with application/json body -func NewIssue9Request(server string, params *Issue9Params, body Issue9JSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewIssue9RequestWithBody(server, params, "application/json", bodyReader) -} - -// NewIssue9RequestWithBody generates requests for Issue9 with any type of body -func NewIssue9RequestWithBody(server string, params *Issue9Params, contentType string, body io.Reader) (*http.Request, error) { - var err error - - queryUrl, err := url.Parse(server) - if err != nil { - return nil, err - } - queryUrl, err = queryUrl.Parse(fmt.Sprintf("/issues/9")) - if err != nil { - return nil, err - } - - queryValues := queryUrl.Query() - - if queryFrag, err := runtime.StyleParam("form", true, "foo", 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() - - req, err := http.NewRequest("GET", queryUrl.String(), body) - if err != nil { - return nil, err - } - - req.Header.Add("Content-Type", contentType) - return req, 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 { - if !strings.HasSuffix(baseURL, "/") { - baseURL += "/" - } - newBaseURL, err := url.Parse(baseURL) - if err != nil { - return err - } - c.Server = newBaseURL.String() - return nil - } -} - -type issue30Response struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r issue30Response) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r issue30Response) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type issue41Response struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r issue41Response) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r issue41Response) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type issue9Response struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r issue9Response) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r issue9Response) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -// Issue30WithResponse request returning *Issue30Response -func (c *ClientWithResponses) Issue30WithResponse(ctx context.Context, pFallthrough string) (*issue30Response, error) { - rsp, err := c.Issue30(ctx, pFallthrough) - if err != nil { - return nil, err - } - return ParseIssue30Response(rsp) -} - -// Issue41WithResponse request returning *Issue41Response -func (c *ClientWithResponses) Issue41WithResponse(ctx context.Context, n1param N5StartsWithNumber) (*issue41Response, error) { - rsp, err := c.Issue41(ctx, n1param) - if err != nil { - return nil, err - } - return ParseIssue41Response(rsp) -} - -// Issue9WithBodyWithResponse request with arbitrary body returning *Issue9Response -func (c *ClientWithResponses) Issue9WithBodyWithResponse(ctx context.Context, params *Issue9Params, contentType string, body io.Reader) (*issue9Response, error) { - rsp, err := c.Issue9WithBody(ctx, params, contentType, body) - if err != nil { - return nil, err - } - return ParseIssue9Response(rsp) -} - -func (c *ClientWithResponses) Issue9WithResponse(ctx context.Context, params *Issue9Params, body Issue9JSONRequestBody) (*issue9Response, error) { - rsp, err := c.Issue9(ctx, params, body) - if err != nil { - return nil, err - } - return ParseIssue9Response(rsp) -} - -// ParseIssue30Response parses an HTTP response from a Issue30WithResponse call -func ParseIssue30Response(rsp *http.Response) (*issue30Response, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &issue30Response{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ParseIssue41Response parses an HTTP response from a Issue41WithResponse call -func ParseIssue41Response(rsp *http.Response) (*issue41Response, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &issue41Response{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ParseIssue9Response parses an HTTP response from a Issue9WithResponse call -func ParseIssue9Response(rsp *http.Response) (*issue9Response, error) { - bodyBytes, err := ioutil.ReadAll(rsp.Body) - defer rsp.Body.Close() - if err != nil { - return nil, err - } - - response := &issue9Response{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - } - - return response, nil -} - -// ServerInterface represents all server handlers. -type ServerInterface interface { - - // (GET /issues/30/{fallthrough}) - Issue30(ctx echo.Context, pFallthrough string) error - - // (GET /issues/41/{1param}) - Issue41(ctx echo.Context, n1param N5StartsWithNumber) error - - // (GET /issues/9) - Issue9(ctx echo.Context, params Issue9Params) error -} - -// ServerInterfaceWrapper converts echo contexts to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface -} - -// Issue30 converts echo context to params. -func (w *ServerInterfaceWrapper) Issue30(ctx echo.Context) error { - var err error - // ------------- Path parameter "fallthrough" ------------- - var pFallthrough string - - err = runtime.BindStyledParameter("simple", false, "fallthrough", ctx.Param("fallthrough"), &pFallthrough) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter fallthrough: %s", err)) - } - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.Issue30(ctx, pFallthrough) - return err -} - -// Issue41 converts echo context to params. -func (w *ServerInterfaceWrapper) Issue41(ctx echo.Context) error { - var err error - // ------------- Path parameter "1param" ------------- - var n1param N5StartsWithNumber - - err = runtime.BindStyledParameter("simple", false, "1param", ctx.Param("1param"), &n1param) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter 1param: %s", err)) - } - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.Issue41(ctx, n1param) - return err -} - -// Issue9 converts echo context to params. -func (w *ServerInterfaceWrapper) Issue9(ctx echo.Context) error { - var err error - - // Parameter object where we will unmarshal all parameters from the context - var params Issue9Params - // ------------- Required query parameter "foo" ------------- - if paramValue := ctx.QueryParam("foo"); paramValue != "" { - - } else { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Query argument foo is required, but not found")) - } - - err = runtime.BindQueryParameter("form", true, true, "foo", ctx.QueryParams(), ¶ms.Foo) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter foo: %s", err)) - } - - // Invoke the callback with all the unmarshalled arguments - err = w.Handler.Issue9(ctx, params) - return err -} - -// RegisterHandlers adds each server route to the EchoRouter. -func RegisterHandlers(router interface { - CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route -}, si ServerInterface) { - - wrapper := ServerInterfaceWrapper{ - Handler: si, - } - - router.GET("/issues/30/:fallthrough", wrapper.Issue30) - router.GET("/issues/41/:1param", wrapper.Issue41) - router.GET("/issues/9", wrapper.Issue9) - -} - -// Base64 encoded, gzipped, json marshaled Swagger object -var swaggerSpec = []string{ - - "H4sIAAAAAAAC/5STQVPbMBCF/8rOtkePnRR6QLeWQ4dLYQozPRQOirWORW1JSKtQj8f/vSM5IaZAO70p", - "jlbvfW93R6xt76whwwHFiKFuqZf5+PGapefwXXP7NfYb8umjolB77VhbgwJvWh1gLgEje4KQS+BRcwsS", - "zFxWIA+OUKDd3FPNOBX4yQw3g6M1ivH468NbAq2NnYINgTSgDZNvZE3jlB46j4Ftf81em+1NVhmxsb6X", - "jALr/OdRP+RrqewLGfK6vpwNifFPh9NUoDaNfcURBYZaBgrQWA876bWNAXQIMX+KRoHdkQfWPZVw1ZEM", - "BFIpkMCH2lR6a6QZYBO30OhfpMpbk4xq7uigck1+l+PbkQ+z+rpclasEYB0Z6TQKPClX5RoLdJLb3Ldq", - "9lKdrKqxkV3Hrbdx204vWb5RSBIKftLwaL1aRu08ZV+gTYaUm45yj8PsdEs5N+vIy/TchUKBF0n5JBt0", - "0suemHxA8WNEnfSSRSwwvYICF96wQE8PUXtSKNhHKvaDuGjNoXnT3VQ8MZ6uq3GdpTLe3tRzyquDk8WI", - "arOdh/RpRF8BOZ1j/RfHrP9XhPeeGhT4rjouW7XftOrlmiXEBePZm2TnnSbDkPUDpJxAm9p6TzV3Qzp3", - "UZHKg5rMpaHK1BurBpBG3Zoj3tzWV2I4eyOFh0h+WLTT2v9r43yZAn+2akg3amuYTOaUznW6zkaq+5Bg", - "x+NTeTufJ3GZD7LLZM9sNLILNOWSPOx7gug7FNgyO1FV+2VK61kqItdLV0qN0930OwAA///Z/BiYHwUA", - "AA==", -} - -// GetSwagger returns the Swagger specification corresponding to the generated code -// in this file. -func GetSwagger() (*openapi3.Swagger, 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) - } - - swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(buf.Bytes()) - if err != nil { - return nil, fmt.Errorf("error loading Swagger: %s", err) - } - return swagger, nil -} diff --git a/internal/test/server/server.gen.go b/internal/test/server/server.gen.go index 5babef1eb..aa5d8822b 100644 --- a/internal/test/server/server.gen.go +++ b/internal/test/server/server.gen.go @@ -365,7 +365,7 @@ func Handler(si ServerInterface) http.Handler { } // HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux. -func HandlerFromMux(si ServerInterface, r chi.Router) http.Handler { +func HandlerFromMux(si ServerInterface, r *chi.Mux) http.Handler { r.Group(func(r chi.Router) { r.Use(GetSimpleCtx) r.Get("/get-simple", si.GetSimple) diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 90015ee59..03d5bdaa2 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -19,6 +19,7 @@ import ( "bytes" "fmt" "go/format" + "os" "regexp" "sort" "strings" @@ -27,19 +28,21 @@ import ( "github.com/getkin/kin-openapi/openapi3" "github.com/pkg/errors" - "github.com/deepmap/oapi-codegen/pkg/codegen/templates" + "github.com/weberr13/oapi-codegen/pkg/codegen/templates" ) // Options defines the optional code to generate. type Options struct { - GenerateChiServer bool // GenerateChiServer specifies whether to generate chi server boilerplate - GenerateEchoServer bool // GenerateEchoServer specifies whether to generate echo server boilerplate - GenerateClient bool // GenerateClient specifies whether to generate client boilerplate - GenerateTypes bool // GenerateTypes specifies whether to generate type definitions - EmbedSpec bool // Whether to embed the swagger spec in the generated code - SkipFmt bool // Whether to skip go fmt on the generated code - IncludeTags []string // Only include operations that have one of these tags. Ignored when empty. - ExcludeTags []string // Exclude operations that have one of these tags. Ignored when empty. + GenerateChiServer bool // GenerateChiServer specifies whether to generate chi server boilerplate + GenerateEchoServer bool // GenerateEchoServer specifies whether to generate echo server boilerplate + GenerateClient bool // GenerateClient specifies whether to generate client boilerplate + GenerateTypes bool // GenerateTypes specifies whether to generate type definitions + EmbedSpec bool // Whether to embed the swagger spec in the generated code + SkipFmt bool // Whether to skip go fmt on the generated code + IncludeTags []string // Only include operations that have one of these tags. Ignored when empty. + ExcludeTags []string // Exclude operations that have one of these tags. Ignored when empty. + ClearRefsSpec bool // Whether to resolve all references in the included swagger spec + ImportedTypes map[string]TypeImportSpec // Additional imports added when using remote references } type goImport struct { @@ -72,19 +75,47 @@ var ( {lookFor: "ioutil\\.", packageName: "io/ioutil"}, {lookFor: "json\\.", packageName: "encoding/json"}, {lookFor: "openapi3\\.", packageName: "github.com/getkin/kin-openapi/openapi3"}, - {lookFor: "openapi_types\\.", alias: "openapi_types", packageName: "github.com/deepmap/oapi-codegen/pkg/types"}, + {lookFor: "openapi_types\\.", alias: "openapi_types", packageName: "github.com/weberr13/oapi-codegen/pkg/types"}, {lookFor: "path\\.", packageName: "path"}, - {lookFor: "runtime\\.", packageName: "github.com/deepmap/oapi-codegen/pkg/runtime"}, + {lookFor: "runtime\\.", packageName: "github.com/weberr13/oapi-codegen/pkg/runtime"}, {lookFor: "strings\\.", packageName: "strings"}, {lookFor: "time\\.Duration", packageName: "time"}, {lookFor: "time\\.Time", packageName: "time"}, {lookFor: "url\\.", packageName: "net/url"}, {lookFor: "xml\\.", packageName: "encoding/xml"}, {lookFor: "yaml\\.", packageName: "gopkg.in/yaml.v2"}, + {lookFor: "decode\\.", packageName: "github.com/weberr13/go-decode/decode"}, } ) // Uses the Go templating engine to generate all of our server wrappers from + +type genCtx struct { + PackageName string + TypeDefs []TypeDefinition + OpDefs []OperationDefinition + GoSchemaMap map[string]Schema + ImportedTypes map[string]TypeImportSpec + Swagger *openapi3.Swagger + HasDecorators bool +} + +func newGenCtx(swagger *openapi3.Swagger, packageName string, opts Options) *genCtx { + return &genCtx{Swagger: swagger, PackageName: packageName, + TypeDefs: []TypeDefinition{}, GoSchemaMap: map[string]Schema{}, + ImportedTypes: opts.ImportedTypes, + } +} + +func (ctx *genCtx) getAllOpTypes() []TypeDefinition { + var td []TypeDefinition + for _, op := range ctx.OpDefs { + td = append(td, op.TypeDefinitions...) + } + return td +} + +// Generate uses the Go templating engine to generate all of our server wrappers from // the descriptions we've built up above from the schema objects. // opts defines func Generate(swagger *openapi3.Swagger, packageName string, opts Options) (string, error) { @@ -99,14 +130,19 @@ func Generate(swagger *openapi3.Swagger, packageName string, opts Options) (stri return "", errors.Wrap(err, "error parsing oapi-codegen templates") } - ops, err := OperationDefinitions(swagger) - if err != nil { - return "", errors.Wrap(err, "error creating operation definitions") + ctx := newGenCtx(swagger, packageName, opts) + + // only generate operation typedefs if not producing resolved spec + if !opts.ClearRefsSpec { + err = OperationDefinitions(ctx, swagger) + if err != nil { + return "", errors.Wrap(err, "error creating operation definitions") + } } var typeDefinitions string if opts.GenerateTypes { - typeDefinitions, err = GenerateTypeDefinitions(t, swagger, ops) + typeDefinitions, err = GenerateTypeDefinitions(ctx, t, swagger) if err != nil { return "", errors.Wrap(err, "error generating type definitions") } @@ -130,7 +166,7 @@ func Generate(swagger *openapi3.Swagger, packageName string, opts Options) (stri var clientOut string if opts.GenerateClient { - clientOut, err = GenerateClient(t, ops) + clientOut, err = GenerateClient(ctx, t) if err != nil { return "", errors.Wrap(err, "error generating client") } @@ -138,7 +174,7 @@ func Generate(swagger *openapi3.Swagger, packageName string, opts Options) (stri var clientWithResponsesOut string if opts.GenerateClient { - clientWithResponsesOut, err = GenerateClientWithResponses(t, ops) + clientWithResponsesOut, err = GenerateClientWithResponses(ctx, t) if err != nil { return "", errors.Wrap(err, "error generating client with responses") } @@ -146,18 +182,25 @@ func Generate(swagger *openapi3.Swagger, packageName string, opts Options) (stri var inlinedSpec string if opts.EmbedSpec { - inlinedSpec, err = GenerateInlinedSpec(t, swagger) + inlinedSpec, err = GenerateInlinedSpec(ctx, t, swagger) if err != nil { return "", errors.Wrap(err, "error generating Go handlers for Paths") } } // Imports needed for the generated code to compile - var imports []string + var imports []TypeImportSpec var buf bytes.Buffer w := bufio.NewWriter(&buf) + // TODO: this is error prone, use tighter matches + allCode := strings.Join([]string{typeDefinitions, echoServerOut, chiServerOut, clientOut, clientWithResponsesOut, inlinedSpec}, "\n") + for t, i := range ctx.ImportedTypes { + if strings.Contains(allCode, t) { + allGoImports = append(allGoImports, goImport{lookFor: `\` + i.Name, packageName: i.PackageName}) + } + } // Based on module prefixes, figure out which optional imports are required. for _, str := range []string{typeDefinitions, chiServerOut, echoServerOut, clientOut, clientWithResponsesOut, inlinedSpec} { for _, goImport := range allGoImports { @@ -171,7 +214,7 @@ func Generate(swagger *openapi3.Swagger, packageName string, opts Options) (stri } } - importsOut, err := GenerateImports(t, imports, packageName) + importsOut, err := GenerateImports(ctx, t, imports) if err != nil { return "", errors.Wrap(err, "error generating imports") } @@ -240,41 +283,39 @@ func Generate(swagger *openapi3.Swagger, packageName string, opts Options) (stri return string(outBytes), nil } -func GenerateTypeDefinitions(t *template.Template, swagger *openapi3.Swagger, ops []OperationDefinition) (string, error) { - schemaTypes, err := GenerateTypesForSchemas(t, swagger.Components.Schemas) +func GenerateTypeDefinitions(ctx *genCtx, t *template.Template, swagger *openapi3.Swagger) (string, error) { + var err error + + err = GenerateTypesForSchemas(ctx, t, swagger.Components.Schemas) if err != nil { return "", errors.Wrap(err, "error generating Go types for component schemas") } - paramTypes, err := GenerateTypesForParameters(t, swagger.Components.Parameters) + err = GenerateTypesForParameters(ctx, t, swagger.Components.Parameters) if err != nil { return "", errors.Wrap(err, "error generating Go types for component parameters") } - allTypes := append(schemaTypes, paramTypes...) - responseTypes, err := GenerateTypesForResponses(t, swagger.Components.Responses) + err = GenerateTypesForResponses(ctx, t, swagger.Components.Responses) if err != nil { return "", errors.Wrap(err, "error generating Go types for component responses") } - allTypes = append(allTypes, responseTypes...) - bodyTypes, err := GenerateTypesForRequestBodies(t, swagger.Components.RequestBodies) + err = GenerateTypesForRequestBodies(ctx, t, swagger.Components.RequestBodies) if err != nil { return "", errors.Wrap(err, "error generating Go types for component request bodies") } - allTypes = append(allTypes, bodyTypes...) - paramTypesOut, err := GenerateTypesForOperations(t, ops) + paramTypesOut, err := GenerateTypesForOperations(ctx, t) if err != nil { return "", errors.Wrap(err, "error generating Go types for operation parameters") } - typesOut, err := GenerateTypes(t, allTypes) + typesOut, err := GenerateTypes(ctx, t) if err != nil { return "", errors.Wrap(err, "error generating code for type definitions") } - - allOfBoilerplate, err := GenerateAdditionalPropertyBoilerplate(t, allTypes) + allOfBoilerplate, err := GenerateAdditionalPropertyBoilerplate(ctx, t, ctx.TypeDefs) if err != nil { return "", errors.Wrap(err, "error generating allOf boilerplate") } @@ -285,38 +326,37 @@ func GenerateTypeDefinitions(t *template.Template, swagger *openapi3.Swagger, op // Generates type definitions for any custom types defined in the // components/schemas section of the Swagger spec. -func GenerateTypesForSchemas(t *template.Template, schemas map[string]*openapi3.SchemaRef) ([]TypeDefinition, error) { - types := make([]TypeDefinition, 0) +func GenerateTypesForSchemas(ctx *genCtx, t *template.Template, schemas map[string]*openapi3.SchemaRef) error { + // We're going to define Go types for every object under components/schemas for _, schemaName := range SortedSchemaKeys(schemas) { schemaRef := schemas[schemaName] - goSchema, err := GenerateGoSchema(schemaRef, []string{schemaName}) + goSchema, err := GenerateGoSchema(ctx, schemaRef, []string{schemaName}) if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("error converting Schema %s to Go type", schemaName)) + return errors.Wrap(err, fmt.Sprintf("error converting Schema %s to Go type", schemaName)) } - types = append(types, TypeDefinition{ + ctx.TypeDefs = append(ctx.TypeDefs, TypeDefinition{ JsonName: schemaName, TypeName: SchemaNameToTypeName(schemaName), Schema: goSchema, }) - types = append(types, goSchema.GetAdditionalTypeDefs()...) + ctx.TypeDefs = append(ctx.TypeDefs, goSchema.GetAdditionalTypeDefs()...) } - return types, nil + return nil } // Generates type definitions for any custom types defined in the // components/parameters section of the Swagger spec. -func GenerateTypesForParameters(t *template.Template, params map[string]*openapi3.ParameterRef) ([]TypeDefinition, error) { - var types []TypeDefinition +func GenerateTypesForParameters(ctx *genCtx, t *template.Template, params map[string]*openapi3.ParameterRef) error { for _, paramName := range SortedParameterKeys(params) { paramOrRef := params[paramName] - goType, err := paramToGoType(paramOrRef.Value, nil) + goType, err := paramToGoType(ctx, paramOrRef.Value, nil) if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("error generating Go type for schema in parameter %s", paramName)) + return errors.Wrap(err, fmt.Sprintf("error generating Go type for schema in parameter %s", paramName)) } typeDef := TypeDefinition{ @@ -327,22 +367,21 @@ func GenerateTypesForParameters(t *template.Template, params map[string]*openapi if paramOrRef.Ref != "" { // Generate a reference type for referenced parameters - refType, err := RefPathToGoType(paramOrRef.Ref) + refType, err := RefPathToGoType(paramOrRef.Ref, ctx.ImportedTypes) if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("error generating Go type for (%s) in parameter %s", paramOrRef.Ref, paramName)) + return errors.Wrap(err, fmt.Sprintf("error generating Go type for (%s) in parameter %s", paramOrRef.Ref, paramName)) } typeDef.TypeName = SchemaNameToTypeName(refType) } - types = append(types, typeDef) + ctx.TypeDefs = append(ctx.TypeDefs, typeDef) } - return types, nil + return nil } // Generates type definitions for any custom types defined in the // components/responses section of the Swagger spec. -func GenerateTypesForResponses(t *template.Template, responses openapi3.Responses) ([]TypeDefinition, error) { - var types []TypeDefinition +func GenerateTypesForResponses(ctx *genCtx, t *template.Template, responses openapi3.Responses) error { for _, responseName := range SortedResponsesKeys(responses) { responseOrRef := responses[responseName] @@ -353,9 +392,9 @@ func GenerateTypesForResponses(t *template.Template, responses openapi3.Response response := responseOrRef.Value jsonResponse, found := response.Content["application/json"] if found { - goType, err := GenerateGoSchema(jsonResponse.Schema, []string{responseName}) + goType, err := GenerateGoSchema(ctx, jsonResponse.Schema, []string{responseName}) if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("error generating Go type for schema in response %s", responseName)) + return errors.Wrap(err, fmt.Sprintf("error generating Go type for schema in response %s", responseName)) } typeDef := TypeDefinition{ @@ -366,21 +405,21 @@ func GenerateTypesForResponses(t *template.Template, responses openapi3.Response if responseOrRef.Ref != "" { // Generate a reference type for referenced parameters - refType, err := RefPathToGoType(responseOrRef.Ref) + refType, err := RefPathToGoType(responseOrRef.Ref, ctx.ImportedTypes) if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("error generating Go type for (%s) in parameter %s", responseOrRef.Ref, responseName)) + return errors.Wrap(err, fmt.Sprintf("error generating Go type for (%s) in parameter %s", responseOrRef.Ref, responseName)) } typeDef.TypeName = SchemaNameToTypeName(refType) } - types = append(types, typeDef) + ctx.TypeDefs = append(ctx.TypeDefs, typeDef) } } - return types, nil + return nil } // Generates type definitions for any custom types defined in the // components/requestBodies section of the Swagger spec. -func GenerateTypesForRequestBodies(t *template.Template, bodies map[string]*openapi3.RequestBodyRef) ([]TypeDefinition, error) { +func GenerateTypesForRequestBodies(ctx *genCtx, t *template.Template, bodies map[string]*openapi3.RequestBodyRef) error { var types []TypeDefinition for _, bodyName := range SortedRequestBodyKeys(bodies) { @@ -391,9 +430,9 @@ func GenerateTypesForRequestBodies(t *template.Template, bodies map[string]*open response := bodyOrRef.Value jsonBody, found := response.Content["application/json"] if found { - goType, err := GenerateGoSchema(jsonBody.Schema, []string{bodyName}) + goType, err := GenerateGoSchema(ctx, jsonBody.Schema, []string{bodyName}) if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("error generating Go type for schema in body %s", bodyName)) + return errors.Wrap(err, fmt.Sprintf("error generating Go type for schema in body %s", bodyName)) } typeDef := TypeDefinition{ @@ -404,31 +443,26 @@ func GenerateTypesForRequestBodies(t *template.Template, bodies map[string]*open if bodyOrRef.Ref != "" { // Generate a reference type for referenced bodies - refType, err := RefPathToGoType(bodyOrRef.Ref) + refType, err := RefPathToGoType(bodyOrRef.Ref, ctx.ImportedTypes) if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("error generating Go type for (%s) in body %s", bodyOrRef.Ref, bodyName)) + return errors.Wrap(err, fmt.Sprintf("error generating Go type for (%s) in body %s", bodyOrRef.Ref, bodyName)) } typeDef.TypeName = SchemaNameToTypeName(refType) } types = append(types, typeDef) } } - return types, nil + ctx.TypeDefs = append(ctx.TypeDefs, types...) + return nil } // Helper function to pass a bunch of types to the template engine, and buffer // its output into a string. -func GenerateTypes(t *template.Template, types []TypeDefinition) (string, error) { +func GenerateTypes(ctx *genCtx, t *template.Template) (string, error) { var buf bytes.Buffer w := bufio.NewWriter(&buf) - context := struct { - Types []TypeDefinition - }{ - Types: types, - } - - err := t.ExecuteTemplate(w, "typedef.tmpl", context) + err := t.ExecuteTemplate(w, "typedef.tmpl", ctx) if err != nil { return "", errors.Wrap(err, "error generating types") } @@ -440,17 +474,17 @@ func GenerateTypes(t *template.Template, types []TypeDefinition) (string, error) } // Generate our import statements and package definition. -func GenerateImports(t *template.Template, imports []string, packageName string) (string, error) { - sort.Strings(imports) +func GenerateImports(ctx *genCtx, t *template.Template, imports []TypeImportSpec) (string, error) { + sort.Slice(imports, func(i, j int) bool { return imports[i].ImportPath < imports[j].ImportPath }) var buf bytes.Buffer w := bufio.NewWriter(&buf) context := struct { - Imports []string + Imports []TypeImportSpec PackageName string }{ Imports: imports, - PackageName: packageName, + PackageName: ctx.PackageName, } err := t.ExecuteTemplate(w, "imports.tmpl", context) if err != nil { @@ -463,25 +497,108 @@ func GenerateImports(t *template.Template, imports []string, packageName string) return buf.String(), nil } +func getDecorators(decorators map[string]Decorator, s Schema) map[string]Decorator { + if len(s.Decorators) > 0 { + for k, v := range s.Decorators { + decorators[k] = v + } + } + if s.AdditionalPropertiesType != nil { + m := getDecorators(decorators, *s.AdditionalPropertiesType) + for k, v := range m { + decorators[k] = v + } + } + for _, p := range s.Properties { + m := getDecorators(decorators, p.Schema) + for k, v := range m { + decorators[k] = v + } + } + for _, p := range s.AdditionalTypes { + m := getDecorators(decorators, p.Schema) + for k, v := range m { + decorators[k] = v + } + } + return decorators +} + // Generate all the glue code which provides the API for interacting with // additional properties and JSON-ification -func GenerateAdditionalPropertyBoilerplate(t *template.Template, typeDefs []TypeDefinition) (string, error) { +func GenerateAdditionalPropertyBoilerplate(ctx *genCtx, t *template.Template, td []TypeDefinition) (string, error) { var buf bytes.Buffer w := bufio.NewWriter(&buf) var filteredTypes []TypeDefinition - for _, t := range typeDefs { + decorators := make(map[string]Decorator) + for _, t := range td { if t.Schema.HasAdditionalProperties { filteredTypes = append(filteredTypes, t) } + // If the type is an empty interface, can assume it's decorators are held by parent that references it + if t.Schema.GoType != "interface{}" { + decorators = getDecorators(decorators, t.Schema) + } + } + + // filter out all decorators with a schema path that is deeper than SchemaName.property + // since the decode library always operates on an object of the current schema, iterating over its properties + for k, _ := range decorators { + if strings.Count(k, ".") > 1 { + delete(decorators, k) + } + } + + // todo: this has side effects that should be computed elsewhere + ctx.HasDecorators = ctx.HasDecorators || len(decorators) > 0 + + type factoryMap struct { + Discriminator string + Factories []Decorator + } + + dsm := map[string]Decorator{} + dsp := map[string]factoryMap{} + for _, v := range decorators { + dsm[v.SchemaName] = v + + fm := dsp[v.SchemaPath] + fm.Discriminator = v.Discriminator + fm.Factories = append(fm.Factories, v) + dsp[v.SchemaPath] = fm + + } + for _, v := range dsp { + sort.Slice(v.Factories, func(i, j int) bool { return v.Factories[i].JSONName < v.Factories[j].JSONName }) + } + + // issue a warning if dsm contains schemas that have duplicate JSONName (this will cause TypeFactory to have + // duplicate map entries and will therefore not compile. TypeFactory is intended to be removed. This is a temporary measure + // todo: remove once we no longer use type factory + djn := map[string]Decorator{} + for _, v := range dsm { + if d, ok := djn[v.JSONName]; ok { + fmt.Fprintf(os.Stderr, "Duplicate Discriminator JSON value `%s` (schema1: %s, schema2: %s). Code will not compile\n", v.JSONName, d.SchemaName, v.SchemaName) + } + djn[v.JSONName] = v } context := struct { - Types []TypeDefinition + Types []TypeDefinition + Decorators map[string]Decorator + DecoratedSchemas map[string]Decorator + DecoratedPaths map[string]factoryMap + HasDecorators bool }{ - Types: filteredTypes, + Types: filteredTypes, + Decorators: decorators, + DecoratedSchemas: dsm, + DecoratedPaths: dsp, + HasDecorators: ctx.HasDecorators, } + //debug.PrintStack() err := t.ExecuteTemplate(w, "additional-properties.tmpl", context) if err != nil { return "", errors.Wrap(err, "error generating additional properties code") diff --git a/pkg/codegen/codegen_test.go b/pkg/codegen/codegen_test.go index f534d9ec7..d2e3f8857 100644 --- a/pkg/codegen/codegen_test.go +++ b/pkg/codegen/codegen_test.go @@ -2,16 +2,28 @@ package codegen import ( "bytes" + "encoding/json" + "errors" + "flag" "go/format" "io/ioutil" + "net" "net/http" + "net/http/httptest" + "os" + "os/exec" + "path/filepath" + "strings" "testing" examplePetstoreClient "github.com/deepmap/oapi-codegen/examples/petstore-expanded" - examplePetstore "github.com/deepmap/oapi-codegen/examples/petstore-expanded/echo/api" + examplePetstore "github.com/weberr13/oapi-codegen/examples/petstore-expanded/echo/api" + "github.com/getkin/kin-openapi/openapi3" "github.com/golangci/lint-1" + "github.com/onsi/gomega/gexec" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestExamplePetStoreCodeGeneration(t *testing.T) { @@ -78,7 +90,6 @@ func TestExamplePetStoreParseFunction(t *testing.T) { assert.NotNil(t, findPetByIDResponse.JSON200.Tag) assert.Equal(t, "cat", *findPetByIDResponse.JSON200.Tag) } - func TestFilterOperationsByTag(t *testing.T) { packageName := "testswagger" t.Run("include tags", func(t *testing.T) { @@ -124,36 +135,163 @@ func TestFilterOperationsByTag(t *testing.T) { }) } -func TestExampleOpenAPICodeGeneration(t *testing.T) { +var update = flag.Bool("update", false, "update .golden files") + +//func TestExampleOpenAPICodeGeneration(t *testing.T) { +// +// testCases := map[string]struct { +// Spec string +// Name string +// }{ +// "standard test": { +// Spec: "testdata/testOpenAPIDefinition.yaml", +// Name: "testOpenAPIDefinition", +// }, +// "discriminated oneOf test with enums": { +// Spec: "testdata/testOpenAPIDefinitionWithOneOfDiscriminatorsAndEnums.yaml", +// Name: "testOpenAPIDefinitionWithOneOfDiscriminatorsAndEnums", +// }, +// "discriminated oneOf test with enums and mappings": { +// Spec: "testdata/pets.yaml", +// Name: "pets", +// }, +// } +// for testname, test := range testCases { +// t.Run(testname, func(t *testing.T) { +// // Input vars for code generation: +// packageName := "testswagger" +// opts := Options{ +// GenerateClient: true, +// GenerateServer: true, +// GenerateTypes: true, +// EmbedSpec: true, +// } +// // load spec from testdata identified by spec +// bytes, err := ioutil.ReadFile(test.Spec) +// if err != nil { +// t.Fatal(err) +// } +// // Get a spec from the test definition in this file: +// swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(bytes) +// assert.NoError(t, err) +// +// // Run our code generation: +// code, err := Generate(swagger, packageName, opts) +// codeBytes := []byte(code) +// assert.NoError(t, err) +// assert.NotEmpty(t, code) +// +// // Make sure the code is formattable +// _, err = format.Source([]byte(code)) +// assert.NoError(t, err) +// +// // Make sure the generated code is valid: +// linter := new(lint.Linter) +// problems, err := linter.Lint("test.gen.go", codeBytes) +// assert.NoError(t, err) +// assert.Len(t, problems, 0) +// +// // if update flag is set, write to golden file +// golden := filepath.Join("testdata/", test.Name+".golden") +// if *update { +// ioutil.WriteFile(golden, codeBytes, 0644) +// } +// +// // load the golden file and run formatting to ensure test does not fail due to different go format version +// expected, _ := ioutil.ReadFile(golden) +// expected, err = format.Source(expected) +// assert.NoError(t, err) +// +// // Compare generated code with golden file contents +// assert.Equal(t, codeBytes, expected) +// }) +// } +//} + +func TestOneOfCodeGenerationErrors(t *testing.T) { + + testCases := map[string]struct { + Spec string + ContentAsserts func(t *testing.T, code string, err error) + }{ + "failed oneOf - anonymous nested schema": { + Spec: "testdata/failedOneOfAnonymousSchema.yaml", + ContentAsserts: func(t *testing.T, code string, err error) { + assert.Empty(t, code) + // Check that we have valid (formattable) code: + // + // Cannot instance an interface + assert.NotNil(t, err, "expecting error") + assert.Contains(t, err.Error(), `'Cat.echoChamberOneOf.sound' defines a oneOf property inside an anonymous schema`) + }, + }, + "failed oneOf - missing discriminator": { + Spec: "testdata/failedOneOfMissingDiscriminator.yaml", + ContentAsserts: func(t *testing.T, code string, err error) { + assert.Empty(t, code) + + assert.NotNil(t, err, "expecting error") + assert.Contains(t, err.Error(), `error processing oneOf`) + assert.Contains(t, err.Error(), `Schema 'CatAlive' does not have discriminator property`) + }, + }, + } + for testname, test := range testCases { + t.Run(testname, func(t *testing.T) { + // Input vars for code generation: + packageName := "testswagger" + opts := Options{ + GenerateClient: true, + GenerateServer: true, + GenerateTypes: true, + EmbedSpec: true, + } + // load spec from testdata identified by spec + bytes, err := ioutil.ReadFile(test.Spec) + if err != nil { + t.Fatal(err) + } + // Get a spec from the test definition in this file: + swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(bytes) + assert.NoError(t, err) + + // Run our code generation: + code, err := Generate(swagger, packageName, opts) + assert.Error(t, err) + test.ContentAsserts(t, code, err) + }) + } +} + +func TestExampleOpenAPICodeGenerationOfDefaults(t *testing.T) { + testSpec := "testdata/pets.yaml" + _, code, err := loadSwaggerFromFileAndGenerateCode(t, testSpec, Options{GenerateTypes: true}) + assert.NoError(t, err) + + // ensure default values are stored as struct tags in generated structs + assert.Regexp(t, "Type.*\\*string.*`.*default:\"black\"`", code) + assert.Regexp(t, "Halls.*\\*int.*`.*default:\"7\"`", code) + assert.Regexp(t, "Towers.*\\*int.*`.*default:\"1\"`", code) + assert.NotRegexp(t, "Type.*\\*array.*`.*default:\".*\"`", code) +} +func loadSwaggerFromFileAndGenerateCode(t *testing.T, testSpec string, opts Options) (*openapi3.Swagger, string, error) { // Input vars for code generation: packageName := "testswagger" - opts := Options{ - GenerateClient: true, - GenerateEchoServer: true, - GenerateTypes: true, - EmbedSpec: true, - } // Get a spec from the test definition in this file: - swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData([]byte(testOpenAPIDefinition)) - assert.NoError(t, err) - + swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromFile(testSpec) + if err != nil { + return nil, "", err + } // Run our code generation: code, err := Generate(swagger, packageName, 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 response structs are generated correctly: - assert.Contains(t, code, "type getTestByNameResponse struct {") - + if err != nil { + return nil, "", err + } + if code == "" { + return nil, "", errors.New("empty code generated") + } // Check that response structs contains fallbacks to interface for invalid types: // Here an invalid array with no items. assert.Contains(t, code, ` @@ -178,147 +316,114 @@ type getTestByNameResponse struct { assert.Contains(t, code, "func (c *Client) GetTestByName(ctx context.Context, name string, params *GetTestByNameParams) (*http.Response, error) {") assert.Contains(t, code, "func (c *ClientWithResponses) GetTestByNameWithResponse(ctx context.Context, name string, params *GetTestByNameParams) (*getTestByNameResponse, error) {") + // Make sure the code is formattable + _, err = format.Source([]byte(code)) + if err != nil { + return nil, "", err + } // Make sure the generated code is valid: linter := new(lint.Linter) problems, err := linter.Lint("test.gen.go", []byte(code)) - assert.NoError(t, err) - assert.Len(t, problems, 0) + if err != nil { + return nil, "", err + } + if len(problems) > 0 { + return nil, "", errors.New("linting problems found") + } + return swagger, code, nil +} + +func createTestServer(handler http.Handler) *httptest.Server { + ts := httptest.NewUnstartedServer(handler) + l, _ := net.Listen("tcp", "localhost:23456") + ts.Listener.Close() + ts.Listener = l + return ts } -const testOpenAPIDefinition = ` -openapi: 3.0.1 - -info: - title: OpenAPI-CodeGen Test - description: 'This is a test OpenAPI Spec' - version: 1.0.0 - -servers: -- url: https://test.oapi-codegen.com/v2 -- url: http://test.oapi-codegen.com/v2 - -paths: - /test/{name}: - get: - tags: - - test - summary: Get test - operationId: getTestByName - parameters: - - name: name - in: path - required: true - schema: - type: string - - name: $top - in: query - required: false - schema: - type: integer - responses: - 200: - description: Success - content: - application/xml: - schema: - type: array - items: - $ref: '#/components/schemas/Test' - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Test' - 422: - description: InvalidArray - content: - application/xml: - schema: - type: array - application/json: - schema: - type: array - default: - description: Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /cat: - get: - tags: - - cat - summary: Get cat status - operationId: getCatStatus - responses: - 200: - description: Success - content: - application/json: - schema: - oneOf: - - $ref: '#/components/schemas/CatAlive' - - $ref: '#/components/schemas/CatDead' - application/xml: - schema: - anyOf: - - $ref: '#/components/schemas/CatAlive' - - $ref: '#/components/schemas/CatDead' - application/yaml: - schema: - allOf: - - $ref: '#/components/schemas/CatAlive' - - $ref: '#/components/schemas/CatDead' - default: - description: Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - -components: - schemas: - - Test: - properties: - name: - type: string - cases: - type: array - items: - $ref: '#/components/schemas/TestCase' - - TestCase: - properties: - name: - type: string - command: - type: string - - Error: - properties: - code: - type: integer - format: int32 - message: - type: string - - CatAlive: - properties: - name: - type: string - alive_since: - type: string - format: date-time - - CatDead: - properties: - name: - type: string - dead_since: - type: string - format: date-time - cause: - type: string - enum: [car, dog, oldage] -` +func startTestServer(system http.FileSystem) func() { + fs := http.FileServer(system) + ts := createTestServer(fs) + ts.Start() + return ts.Close +} + +// TestResolvedSchema tests that a schema containing remote references is resolved correctly. +// To do so, it starts an HTTP server serving files; the schema under test here contains a reference +// to a file located at the server we just started. This requires that the host address be known here +// at the test site, but also be coded in the spec itself (see testResolvingSpec.yaml) +// Additionally, in order to ensure that the test is generating the proper spec, the generated code is compiled +// and executed and the resulting document is then compared with a golden file (which was inspected manually) +func TestResolvedSchema(t *testing.T) { + + cs := startTestServer(http.Dir("testdata")) + defer cs() + + const mainStr = "\nfunc main(){ s, _ := GetSwaggerSpec(); fmt.Println(s)}" + const testDir = "./testdata" + const packageName = "main" + testSpec := "testResolvingSpec.yaml" + testSpecPath := filepath.Join(testDir, testSpec) + + // TODO: these tests duplicate code that is in main() - we should refactor main at some point + opts := Options{ + EmbedSpec: true, + } + // load spec from testdata identified by spec + specBytes, err := ioutil.ReadFile(testSpecPath) + require.NoError(t, err) + + // Get a spec from the test definition in this file: + swagger, err := openapi3.NewSwaggerLoader( + openapi3.WithAllowExternalRefs(true), + openapi3.WithClearResolvedRefs(true)).LoadSwaggerFromData(specBytes) + require.NoError(t, err) + + // Run our code generation: + code, err := Generate(swagger, packageName, opts) + require.NoError(t, err) + require.NotEmpty(t, code) + + // append our main driver so that we can get the swagger string and dump it to stdout, and save the `program` + code += mainStr + tmpDir, err := ioutil.TempDir(testDir, "resolve") + require.NoError(t, err) + + // defer clean up test dir/file + defer os.RemoveAll(tmpDir) + + testFile := filepath.Join(tmpDir, testSpec+".go") + err = ioutil.WriteFile(testFile, []byte(code), 0644) + require.NoError(t, err) + + // user gomega to build a temporary executable representing the spec + testPath, _ := filepath.Abs(testFile) + testPath = filepath.Dir(testPath) + testBin, err := gexec.Build(testFile) + require.NoError(t, err) + defer gexec.CleanupBuildArtifacts() + + // run the executable + stdOut := &bytes.Buffer{} + stdErr := &bytes.Buffer{} + command := exec.Command(testBin) + command.Stdout = stdOut + command.Stderr = stdErr + require.NoError(t, command.Start()) + require.NoError(t, command.Wait()) + + ib := &bytes.Buffer{} + require.NoError(t, json.Indent(ib, stdOut.Bytes(), "", " ")) + + golden := strings.TrimSuffix(testSpecPath, ".yaml") + ".json.golden" + if *update { + ioutil.WriteFile(golden, ib.Bytes(), 0644) + } + + // load the golden file and run formatting to ensure test does not fail due to different go format version + expected, _ := ioutil.ReadFile(golden) + + // Compare generated code with golden file contents + require.Equal(t, ib.Bytes(), expected) + +} diff --git a/pkg/codegen/inline.go b/pkg/codegen/inline.go index 76251c9a9..3715e1952 100644 --- a/pkg/codegen/inline.go +++ b/pkg/codegen/inline.go @@ -26,7 +26,7 @@ import ( // This generates a gzipped, base64 encoded JSON representation of the // swagger definition, which we embed inside the generated code. -func GenerateInlinedSpec(t *template.Template, swagger *openapi3.Swagger) (string, error) { +func GenerateInlinedSpec(ctx *genCtx, t *template.Template, swagger *openapi3.Swagger) (string, error) { // Marshal to json encoded, err := swagger.MarshalJSON() if err != nil { diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index 916643dd3..35bcefdee 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -141,12 +141,12 @@ func (p ParameterDefinitions) FindByName(name string) *ParameterDefinition { // This function walks the given parameters dictionary, and generates the above // descriptors into a flat list. This makes it a lot easier to traverse the // data in the template engine. -func DescribeParameters(params openapi3.Parameters, path []string) ([]ParameterDefinition, error) { +func DescribeParameters(ctx *genCtx, params openapi3.Parameters, path []string) ([]ParameterDefinition, error) { outParams := make([]ParameterDefinition, 0) for _, paramOrRef := range params { param := paramOrRef.Value - goType, err := paramToGoType(param, append(path, param.Name)) + goType, err := paramToGoType(ctx, param, append(path, param.Name)) if err != nil { return nil, fmt.Errorf("error generating type for param (%s): %s", param.Name, err) @@ -164,7 +164,7 @@ func DescribeParameters(params openapi3.Parameters, path []string) ([]ParameterD // name as the type. $ref: "#/components/schemas/custom_type" becomes // "CustomType". if paramOrRef.Ref != "" { - goType, err := RefPathToGoType(paramOrRef.Ref) + goType, err := RefPathToGoType(paramOrRef.Ref, ctx.ImportedTypes) if err != nil { return nil, fmt.Errorf("error dereferencing (%s) for param (%s): %s", paramOrRef.Ref, param.Name, err) @@ -204,10 +204,11 @@ type OperationDefinition struct { TypeDefinitions []TypeDefinition // These are all the types we need to define for this operation SecurityDefinitions []SecurityDefinition // These are the security providers BodyRequired bool - Bodies []RequestBodyDefinition // The list of bodies for which to generate handlers. - Summary string // Summary string from Swagger, used to generate a comment - Method string // GET, POST, DELETE, etc. - Path string // The Swagger path for the operation, like /resource/{id} + Bodies []RequestBodyDefinition // The list of bodies for which to generate handlers. + Summary string // Summary string from Swagger, used to generate a comment + Method string // GET, POST, DELETE, etc. + Path string // The Swagger path for the operation, like /resource/{id} + ImportedTypes map[string]TypeImportSpec // map of typename to go path for import Spec *openapi3.Operation } @@ -258,7 +259,7 @@ func (o *OperationDefinition) SummaryAsComment() string { // types which we know how to parse. These will be turned into fields on a // response object for automatic deserialization of responses in the generated // Client code. See "client-with-responses.tmpl". -func (o *OperationDefinition) GetResponseTypeDefinitions() ([]TypeDefinition, error) { +func (o *OperationDefinition) GetResponseTypeDefinitions(ctx *genCtx) ([]TypeDefinition, error) { var tds []TypeDefinition responses := o.Spec.Responses @@ -273,7 +274,7 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]TypeDefinition, er 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}) + responseSchema, err := GenerateGoSchema(ctx, contentType.Schema, []string{responseName}) if err != nil { return nil, errors.Wrap(err, fmt.Sprintf("Unable to determine Go type for %s.%s", o.OperationId, contentTypeName)) } @@ -298,7 +299,7 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]TypeDefinition, er ResponseName: responseName, } if contentType.Schema.Ref != "" { - refType, err := RefPathToGoType(contentType.Schema.Ref) + refType, err := RefPathToGoType(contentType.Schema.Ref, o.ImportedTypes) if err != nil { return nil, errors.Wrap(err, "error dereferencing response Ref") } @@ -368,16 +369,15 @@ func FilterParameterDefinitionByType(params []ParameterDefinition, in string) [] } // OperationDefinitions returns all operations for a swagger definition. -func OperationDefinitions(swagger *openapi3.Swagger) ([]OperationDefinition, error) { - var operations []OperationDefinition +func OperationDefinitions(ctx *genCtx, swagger *openapi3.Swagger) error { for _, requestPath := range SortedPathsKeys(swagger.Paths) { pathItem := swagger.Paths[requestPath] // These are parameters defined for all methods on a given path. They // are shared by all methods. - globalParams, err := DescribeParameters(pathItem.Parameters, nil) + globalParams, err := DescribeParameters(ctx, pathItem.Parameters, nil) if err != nil { - return nil, fmt.Errorf("error describing global parameters for %s: %s", + return fmt.Errorf("error describing global parameters for %s: %s", requestPath, err) } @@ -386,22 +386,20 @@ func OperationDefinitions(swagger *openapi3.Swagger) ([]OperationDefinition, err for _, opName := range SortedOperationsKeys(pathOps) { op := pathOps[opName] // We rely on OperationID to generate function names, it's required - if op.OperationID == "" { - op.OperationID, err = generateDefaultOperationID(opName, requestPath) - if err != nil { - return nil, fmt.Errorf("error generating default OperationID for %s/%s: %s", - opName, requestPath, err) - } - op.OperationID = op.OperationID - } else { - op.OperationID = ToCamelCase(op.OperationID) + opID := op.OperationID + if opID == "" { + // construct a default operationID + opID = opName + " " + requestPath + opID = ReplacePathParamsWithParNStr(opID) + opID = strings.ReplaceAll(opID, "/", " ") } + opID = ToCamelCase(opID) // These are parameters defined for the specific path method that // we're iterating over. - localParams, err := DescribeParameters(op.Parameters, []string{op.OperationID + "Params"}) + localParams, err := DescribeParameters(ctx, op.Parameters, []string{opID + "Params"}) if err != nil { - return nil, fmt.Errorf("error describing global parameters for %s/%s: %s", + return fmt.Errorf("error describing global parameters for %s/%s: %s", opName, requestPath, err) } // All the parameters required by a handler are the union of the @@ -414,12 +412,12 @@ func OperationDefinitions(swagger *openapi3.Swagger) ([]OperationDefinition, err pathParams := FilterParameterDefinitionByType(allParams, "path") pathParams, err = SortParamsByPath(requestPath, pathParams) if err != nil { - return nil, err + return err } - bodyDefinitions, typeDefinitions, err := GenerateBodyDefinitions(op.OperationID, op.RequestBody) + bodyDefinitions, typeDefinitions, err := GenerateBodyDefinitions(ctx, opID, op.RequestBody) if err != nil { - return nil, errors.Wrap(err, "error generating body definitions") + return errors.Wrap(err, "error generating body definitions") } opDef := OperationDefinition{ @@ -427,7 +425,7 @@ func OperationDefinitions(swagger *openapi3.Swagger) ([]OperationDefinition, err HeaderParams: FilterParameterDefinitionByType(allParams, "header"), QueryParams: FilterParameterDefinitionByType(allParams, "query"), CookieParams: FilterParameterDefinitionByType(allParams, "cookie"), - OperationId: ToCamelCase(op.OperationID), + OperationId: opID, // Replace newlines in summary. Summary: op.Summary, Method: opName, @@ -435,6 +433,7 @@ func OperationDefinitions(swagger *openapi3.Swagger) ([]OperationDefinition, err Spec: op, Bodies: bodyDefinitions, TypeDefinitions: typeDefinitions, + ImportedTypes: ctx.ImportedTypes, } // check for overrides of SecurityDefinitions. @@ -458,10 +457,10 @@ func OperationDefinitions(swagger *openapi3.Swagger) ([]OperationDefinition, err // Generate all the type definitions needed for this operation opDef.TypeDefinitions = append(opDef.TypeDefinitions, GenerateTypeDefsForOperation(opDef)...) - operations = append(operations, opDef) + ctx.OpDefs = append(ctx.OpDefs, opDef) } } - return operations, nil + return nil } func generateDefaultOperationID(opName string, requestPath string) (string, error) { @@ -486,7 +485,7 @@ func generateDefaultOperationID(opName string, requestPath string) (string, erro // This function turns the Swagger body definitions into a list of our body // definitions which will be used for code generation. -func GenerateBodyDefinitions(operationID string, bodyOrRef *openapi3.RequestBodyRef) ([]RequestBodyDefinition, []TypeDefinition, error) { +func GenerateBodyDefinitions(ctx *genCtx, operationID string, bodyOrRef *openapi3.RequestBodyRef) ([]RequestBodyDefinition, []TypeDefinition, error) { if bodyOrRef == nil { return nil, nil, nil } @@ -508,7 +507,7 @@ func GenerateBodyDefinitions(operationID string, bodyOrRef *openapi3.RequestBody } bodyTypeName := operationID + tag + "Body" - bodySchema, err := GenerateGoSchema(content.Schema, []string{bodyTypeName}) + bodySchema, err := GenerateGoSchema(ctx, content.Schema, []string{bodyTypeName}) if err != nil { return nil, nil, errors.Wrap(err, "error generating request body definition") } @@ -516,7 +515,7 @@ func GenerateBodyDefinitions(operationID string, bodyOrRef *openapi3.RequestBody // If the body is a pre-defined type if bodyOrRef.Ref != "" { // Convert the reference path to Go type - refType, err := RefPathToGoType(bodyOrRef.Ref) + refType, err := RefPathToGoType(bodyOrRef.Ref, ctx.ImportedTypes) if err != nil { return nil, nil, errors.Wrap(err, fmt.Sprintf("error turning reference (%s) into a Go type", bodyOrRef.Ref)) } @@ -607,27 +606,22 @@ func GenerateParamsTypes(op OperationDefinition) []TypeDefinition { } // Generates code for all types produced -func GenerateTypesForOperations(t *template.Template, ops []OperationDefinition) (string, error) { +func GenerateTypesForOperations(ctx *genCtx, t *template.Template) (string, error) { var buf bytes.Buffer w := bufio.NewWriter(&buf) - err := t.ExecuteTemplate(w, "param-types.tmpl", ops) + err := t.ExecuteTemplate(w, "param-types.tmpl", ctx) if err != nil { return "", errors.Wrap(err, "error generating types for params objects") } - err = t.ExecuteTemplate(w, "request-bodies.tmpl", ops) + err = t.ExecuteTemplate(w, "request-bodies.tmpl", ctx) if err != nil { return "", errors.Wrap(err, "error generating request bodies for operations") } // Generate boiler plate for all additional types. - var td []TypeDefinition - for _, op := range ops { - td = append(td, op.TypeDefinitions...) - } - - addProps, err := GenerateAdditionalPropertyBoilerplate(t, td) + addProps, err := GenerateAdditionalPropertyBoilerplate(ctx, t, ctx.getAllOpTypes()) if err != nil { return "", errors.Wrap(err, "error generating additional properties boilerplate for operations") } @@ -681,18 +675,19 @@ func GenerateChiServer(t *template.Template, operations []OperationDefinition) ( // 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) { - si, err := GenerateServerInterface(t, operations) +func GenerateEchoServer(ctx *genCtx, t *template.Template, operations []OperationDefinition) (string, error) { + si, err := GenerateServerInterface(ctx, t, operations) + if err != nil { return "", fmt.Errorf("Error generating server types and interface: %s", err) } - wrappers, err := GenerateWrappers(t, operations) + wrappers, err := GenerateWrappers(ctx, t) if err != nil { return "", fmt.Errorf("Error generating handler wrappers: %s", err) } - register, err := GenerateRegistration(t, operations) + register, err := GenerateRegistration(ctx, t) if err != nil { return "", fmt.Errorf("Error generating handler registration: %s", err) } @@ -700,11 +695,11 @@ func GenerateEchoServer(t *template.Template, operations []OperationDefinition) } // Uses the template engine to generate the server interface -func GenerateServerInterface(t *template.Template, ops []OperationDefinition) (string, error) { +func GenerateServerInterface(ctx *genCtx, t *template.Template, operations []OperationDefinition) (string, error) { var buf bytes.Buffer w := bufio.NewWriter(&buf) - err := t.ExecuteTemplate(w, "server-interface.tmpl", ops) + err := t.ExecuteTemplate(w, "server-interface.tmpl", ctx) if err != nil { return "", fmt.Errorf("error generating server interface: %s", err) @@ -719,11 +714,11 @@ func GenerateServerInterface(t *template.Template, ops []OperationDefinition) (s // Uses the template engine to generate all the wrappers which wrap our simple // interface functions and perform marshallin/unmarshalling from HTTP // request objects. -func GenerateWrappers(t *template.Template, ops []OperationDefinition) (string, error) { +func GenerateWrappers(ctx *genCtx, t *template.Template) (string, error) { var buf bytes.Buffer w := bufio.NewWriter(&buf) - err := t.ExecuteTemplate(w, "wrappers.tmpl", ops) + err := t.ExecuteTemplate(w, "wrappers.tmpl", ctx) if err != nil { return "", fmt.Errorf("error generating server interface: %s", err) @@ -737,11 +732,11 @@ func GenerateWrappers(t *template.Template, ops []OperationDefinition) (string, // Uses the template engine to generate the function which registers our wrappers // as Echo path handlers. -func GenerateRegistration(t *template.Template, ops []OperationDefinition) (string, error) { +func GenerateRegistration(ctx *genCtx, t *template.Template) (string, error) { var buf bytes.Buffer w := bufio.NewWriter(&buf) - err := t.ExecuteTemplate(w, "register.tmpl", ops) + err := t.ExecuteTemplate(w, "register.tmpl", ctx) if err != nil { return "", fmt.Errorf("error generating route registration: %s", err) @@ -755,11 +750,11 @@ func GenerateRegistration(t *template.Template, ops []OperationDefinition) (stri // Uses the template engine to generate the function which registers our wrappers // as Echo path handlers. -func GenerateClient(t *template.Template, ops []OperationDefinition) (string, error) { +func GenerateClient(ctx *genCtx, t *template.Template) (string, error) { var buf bytes.Buffer w := bufio.NewWriter(&buf) - err := t.ExecuteTemplate(w, "client.tmpl", ops) + err := t.ExecuteTemplate(w, "client.tmpl", ctx) if err != nil { return "", fmt.Errorf("error generating client bindings: %s", err) @@ -773,11 +768,11 @@ func GenerateClient(t *template.Template, ops []OperationDefinition) (string, er // This generates a client which extends the basic client which does response // unmarshaling. -func GenerateClientWithResponses(t *template.Template, ops []OperationDefinition) (string, error) { +func GenerateClientWithResponses(ctx *genCtx, t *template.Template) (string, error) { var buf bytes.Buffer w := bufio.NewWriter(&buf) - err := t.ExecuteTemplate(w, "client-with-responses.tmpl", ops) + err := t.ExecuteTemplate(w, "client-with-responses.tmpl", ctx) if err != nil { return "", fmt.Errorf("error generating client bindings: %s", err) diff --git a/pkg/codegen/operations_test.go b/pkg/codegen/operations_test.go index 0636f299a..538b06fb9 100644 --- a/pkg/codegen/operations_test.go +++ b/pkg/codegen/operations_test.go @@ -20,45 +20,45 @@ import ( func TestGenerateDefaultOperationID(t *testing.T) { type test struct { - op string - path string - want string + op string + path string + want string wantErr bool } - suite := []test { + suite := []test{ { - op: http.MethodGet, - path: "/v1/foo/bar", - want: "GetV1FooBar", + op: http.MethodGet, + path: "/v1/foo/bar", + want: "GetV1FooBar", wantErr: false, }, { - op: http.MethodGet, - path: "/v1/foo/bar/", - want: "GetV1FooBar", + op: http.MethodGet, + path: "/v1/foo/bar/", + want: "GetV1FooBar", wantErr: false, }, { - op: http.MethodPost, - path: "/v1", - want: "PostV1", + op: http.MethodPost, + path: "/v1", + want: "PostV1", wantErr: false, }, { - op: http.MethodPost, - path: "v1", - want: "PostV1", + op: http.MethodPost, + path: "v1", + want: "PostV1", wantErr: false, }, { - path: "v1", - want: "", + path: "v1", + want: "", wantErr: true, }, { - path: "", - want: "PostV1", + path: "", + want: "PostV1", wantErr: true, }, } @@ -71,11 +71,11 @@ func TestGenerateDefaultOperationID(t *testing.T) { } } - if test.wantErr { + if test.wantErr { return } if got != test.want { t.Fatalf("Operation ID generation error. Want [%v] Got [%v]", test.want, got) } } -} \ No newline at end of file +} diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 36a1ac277..8544e49f6 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -5,13 +5,33 @@ import ( "strings" "github.com/getkin/kin-openapi/openapi3" + "github.com/iancoleman/strcase" "github.com/pkg/errors" ) +// Decorator functions for some of the generated schema types +type Decorator struct { + SchemaPath string + SchemaName string + JSONName string + Discriminator string + DiscriminatorPascal string + Required bool +} + +// TypeImportSpec describes a type, defined by an external OpenAPI schema and its associated golang import related bits. +// This is used when generating code for types in the current schema that refer to the imported types +type TypeImportSpec struct { + Name string + PackageName string + ImportPath string +} + // This describes a Schema, a type definition. type Schema struct { - GoType string // The Go type needed to represent the schema - RefType string // If the type has a type name, this is set + GoType string // The Go type needed to represent the schema + RefType string // If the type has a type name, this is set + Default *string // Default value, if specified in the spec. Only applies to base data types Properties []Property // For an object, the fields with names HasAdditionalProperties bool // Whether we support additional properties @@ -19,6 +39,13 @@ type Schema struct { AdditionalTypes []TypeDefinition // We may need to generate auxiliary helper types, stored here SkipOptionalPointer bool // Some types don't need a * in front when they're optional + + Decorators map[string]Decorator +} + +// Create a new TypeImportSpec for the provided type, package and import +func NewTypeImportSpec(n, p, i string) TypeImportSpec { + return TypeImportSpec{Name: n, PackageName: p, ImportPath: i} } func (s Schema) IsRef() bool { @@ -82,10 +109,78 @@ func PropertiesEqual(a, b Property) bool { return a.JsonFieldName == b.JsonFieldName && a.Schema.TypeDecl() == b.Schema.TypeDecl() && a.Required == b.Required } -func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { - // If Ref is set on the SchemaRef, it means that this type is actually a reference to - // another type. We're not de-referencing, so simply use the referenced type. - var refType string +func generateSchemaDecorators(path []string, srefs []*openapi3.SchemaRef, discriminator *openapi3.Discriminator, + importedTypes map[string]TypeImportSpec) (map[string]Decorator, error) { + rm := map[string]string{} + m := make(map[string]Decorator) + oneOfPath := append(path[:0], path...) + + // Special case where the schema directly contains oneOf instead of properties + if len(oneOfPath) == 1 { + oneOfPath = append(oneOfPath, discriminator.PropertyName) + } + + // reverse mapping so that the refs are the keys + if discriminator.Mapping != nil { + for k, v := range discriminator.Mapping { + rm[v] = k + } + } + + for _, v := range srefs { + required := false + name, err := RefPathToGoType(v.Ref, importedTypes) + if err != nil { + continue + } + + // by default the key is the schema name. This is also the default for external schemas + jname := strcase.ToCamel(name) + + if v.Value.Properties != nil { + // by if the discriminator is specified and is enum, override default + discriminatorDef, ok := v.Value.Properties[discriminator.PropertyName] + if !ok { + return nil, fmt.Errorf("Schema '%s' does not have discriminator property '%s'", name, discriminator.PropertyName) + } + if discriminatorDef.Value.Type == "string" { + if len(discriminatorDef.Value.Enum) > 0 { + jname = discriminatorDef.Value.Enum[0].(string) + } + } + + // if the discriminator is denoted as a required property, mark that + for _, r := range v.Value.Required { + if r == discriminator.PropertyName { + required = true + } + } + } + + // if we have explicit mapping, use that + if mapping, ok := rm[v.Ref]; ok { + jname = mapping + } + + // add a decorator for this schema instance + //decPath := append(path[:0], path...) + //decPath = append(decPath, name) + dsp := DotSeparatedPath(oneOfPath) + dk := fmt.Sprintf("%s(%s=%s)", dsp, discriminator.PropertyName, jname) + m[dk] = Decorator{ + SchemaPath: dsp, + SchemaName: name, + JSONName: jname, + Discriminator: discriminator.PropertyName, + DiscriminatorPascal: strcase.ToCamel(discriminator.PropertyName), + Required: required, + } + } + + return m, nil +} + +func GenerateGoSchema(ctx *genCtx, sref *openapi3.SchemaRef, path []string) (Schema, error) { // Add a fallback value in case the sref is nil. // i.e. the parent schema defines a type:array, but the array has @@ -96,25 +191,51 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { schema := sref.Value + var refType string + + //If Ref is set on the SchemaRef, it means that this type is actually a reference to + // another type. if sref.Ref != "" { - var err error - // Convert the reference path to Go type - refType, err = RefPathToGoType(sref.Ref) + refType, err := RefPathToGoType(sref.Ref, ctx.ImportedTypes) if err != nil { - return Schema{}, fmt.Errorf("error turning reference (%s) into a Go type: %s", - sref.Ref, err) + return Schema{}, fmt.Errorf("error turning reference (%s) into a Go type: %s", sref.Ref, err) } - return Schema{ - GoType: refType, - }, nil + + // If the type being referenced to is a oneOf, we stil want the decorators and GoType to be set + if schema != nil && schema.OneOf != nil { + if schema.Discriminator != nil && schema.Discriminator.PropertyName != "" { + decorators, err := generateSchemaDecorators(path, schema.OneOf, schema.Discriminator, ctx.ImportedTypes) + if err != nil { + return Schema{}, errors.Wrap(err, "error processing oneOf") + } + return Schema{GoType: refType, RefType: refType, SkipOptionalPointer: true, Decorators: decorators}, nil + } + return Schema{GoType: refType, RefType: refType}, nil + } + //We're not de-referencing, so simply use the referenced type. + return Schema{GoType: refType}, nil } // We can't support this in any meaningful way if schema.AnyOf != nil { return Schema{GoType: "interface{}", RefType: refType}, nil } - // We can't support this in any meaningful way + + // When a discriminator is found there is a way to support this if schema.OneOf != nil { + if schema.Discriminator != nil && schema.Discriminator.PropertyName != "" { + // we only support oneOf properties of a named schema. This requires refType to be defined + // and path to include the schema name and attribute names only + if refType == "" && len(path) > 2 { + return Schema{}, fmt.Errorf("oneOf only supported for named schemas, '%s' defines a oneOf property inside an anonymous schema", DotSeparatedPath(path)) + } + decorators, err := generateSchemaDecorators(path, schema.OneOf, schema.Discriminator, ctx.ImportedTypes) + if err != nil { + return Schema{}, errors.Wrap(err, "error processing oneOf") + } + + return Schema{GoType: "interface{}", RefType: refType, SkipOptionalPointer: true, Decorators: decorators}, nil + } return Schema{GoType: "interface{}", RefType: refType}, nil } @@ -123,7 +244,7 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { // so that in a RESTful paradigm, the Create operation can return // (object, id), so that other operations can refer to (id) if schema.AllOf != nil { - mergedSchema, err := MergeSchemas(schema.AllOf, path) + mergedSchema, err := MergeSchemas(ctx, schema.AllOf, path, ctx.ImportedTypes) if err != nil { return Schema{}, errors.Wrap(err, "error merging schemas") } @@ -159,7 +280,7 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { for _, pName := range SortedSchemaKeys(schema.Properties) { p := schema.Properties[pName] propertyPath := append(path, pName) - pSchema, err := GenerateGoSchema(p, propertyPath) + pSchema, err := GenerateGoSchema(ctx, p, propertyPath) if err != nil { return Schema{}, errors.Wrap(err, fmt.Sprintf("error generating Go schema for property '%s'", pName)) } @@ -200,7 +321,7 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { GoType: "interface{}", } if schema.AdditionalProperties != nil { - additionalSchema, err := GenerateGoSchema(schema.AdditionalProperties, path) + additionalSchema, err := GenerateGoSchema(ctx, schema.AdditionalProperties, path) if err != nil { return Schema{}, errors.Wrap(err, "error generating type for additional properties") } @@ -212,16 +333,18 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { return outSchema, nil } else { f := schema.Format + defaultOK := true switch t { case "array": // For arrays, we'll get the type of the Items and throw a // [] in front of it. - arrayType, err := GenerateGoSchema(schema.Items, path) + arrayType, err := GenerateGoSchema(ctx, schema.Items, path) if err != nil { return Schema{}, errors.Wrap(err, "error generating type for array") } outSchema.GoType = "[]" + arrayType.TypeDecl() + defaultOK = false case "integer": // We default to int if format doesn't ask for something else. if f == "int64" { @@ -266,6 +389,10 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { default: return Schema{}, fmt.Errorf("unhandled Schema type: %s", t) } + if defaultOK && schema.Default != nil { + dv := fmt.Sprintf("%v", schema.Default) + outSchema.Default = &dv + } } return outSchema, nil } @@ -303,6 +430,13 @@ func GenFieldsFromProperties(props []Property) []string { } else { field += fmt.Sprintf(" `json:\"%s,omitempty\"`", p.JsonFieldName) } + + // set default value if present + if p.Schema.Default != nil { + field += fmt.Sprintf(" default:\"%s\"", *p.Schema.Default) + } + + field += "`" fields = append(fields, field) } return fields @@ -328,7 +462,7 @@ func GenStructFromSchema(schema Schema) string { } // Merge all the fields in the schemas supplied into one giant schema. -func MergeSchemas(allOf []*openapi3.SchemaRef, path []string) (Schema, error) { +func MergeSchemas(ctx *genCtx, allOf []*openapi3.SchemaRef, path []string, importedTypes map[string]TypeImportSpec) (Schema, error) { var outSchema Schema for _, schemaOrRef := range allOf { ref := schemaOrRef.Ref @@ -336,13 +470,13 @@ func MergeSchemas(allOf []*openapi3.SchemaRef, path []string) (Schema, error) { var refType string var err error if ref != "" { - refType, err = RefPathToGoType(ref) + refType, err = RefPathToGoType(ref, importedTypes) if err != nil { return Schema{}, errors.Wrap(err, "error converting reference path to a go type") } } - schema, err := GenerateGoSchema(schemaOrRef, path) + schema, err := GenerateGoSchema(ctx, schemaOrRef, path) if err != nil { return Schema{}, errors.Wrap(err, "error generating Go schema in allOf") } @@ -373,7 +507,7 @@ func MergeSchemas(allOf []*openapi3.SchemaRef, path []string) (Schema, error) { // Now, we generate the struct which merges together all the fields. var err error - outSchema.GoType, err = GenStructFromAllOf(allOf, path) + outSchema.GoType, err = GenStructFromAllOf(ctx, allOf, path) if err != nil { return Schema{}, errors.Wrap(err, "unable to generate aggregate type for AllOf") } @@ -383,7 +517,7 @@ func MergeSchemas(allOf []*openapi3.SchemaRef, path []string) (Schema, error) { // This function generates an object that is the union of the objects in the // input array. In the case of Ref objects, we use an embedded struct, otherwise, // we inline the fields. -func GenStructFromAllOf(allOf []*openapi3.SchemaRef, path []string) (string, error) { +func GenStructFromAllOf(ctx *genCtx, allOf []*openapi3.SchemaRef, path []string) (string, error) { // Start out with struct { objectParts := []string{"struct {"} for _, schemaOrRef := range allOf { @@ -395,7 +529,7 @@ func GenStructFromAllOf(allOf []*openapi3.SchemaRef, path []string) (string, err // InlinedMember // ... // } - goType, err := RefPathToGoType(ref) + goType, err := RefPathToGoType(ref, ctx.ImportedTypes) if err != nil { return "", err } @@ -406,7 +540,7 @@ func GenStructFromAllOf(allOf []*openapi3.SchemaRef, path []string) (string, err } else { // Inline all the fields from the schema into the output struct, // just like in the simple case of generating an object. - goSchema, err := GenerateGoSchema(schemaOrRef, path) + goSchema, err := GenerateGoSchema(ctx, schemaOrRef, path) if err != nil { return "", err } @@ -421,14 +555,14 @@ func GenStructFromAllOf(allOf []*openapi3.SchemaRef, path []string) (string, err // This constructs a Go type for a parameter, looking at either the schema or // the content, whichever is available -func paramToGoType(param *openapi3.Parameter, path []string) (Schema, error) { +func paramToGoType(ctx *genCtx, param *openapi3.Parameter, path []string) (Schema, error) { if param.Content == nil && param.Schema == nil { return Schema{}, fmt.Errorf("parameter '%s' has no schema or content", param.Name) } // We can process the schema through the generic schema processor if param.Schema != nil { - return GenerateGoSchema(param.Schema, path) + return GenerateGoSchema(ctx, param.Schema, path) } // At this point, we have a content type. We know how to deal with @@ -450,5 +584,5 @@ func paramToGoType(param *openapi3.Parameter, path []string) (Schema, error) { } // For json, we go through the standard schema mechanism - return GenerateGoSchema(mt.Schema, path) + return GenerateGoSchema(ctx, mt.Schema, path) } diff --git a/pkg/codegen/template_helpers.go b/pkg/codegen/template_helpers.go index 2afb7bdf0..eb1711ac3 100644 --- a/pkg/codegen/template_helpers.go +++ b/pkg/codegen/template_helpers.go @@ -101,6 +101,8 @@ func genResponsePayload(operationID string) string { func genResponseUnmarshal(op *OperationDefinition) string { var buffer = bytes.NewBufferString("") var caseClauses = make(map[string]string) + operationID := op.OperationID + responses := op.Responses // Get the type definitions from the operation: typeDefinitions, err := op.GetResponseTypeDefinitions() @@ -109,7 +111,6 @@ func genResponseUnmarshal(op *OperationDefinition) string { } // Add a case for each possible response: - responses := op.Spec.Responses for _, typeDefinition := range typeDefinitions { responseRef, ok := responses[typeDefinition.ResponseName] @@ -139,21 +140,68 @@ func genResponseUnmarshal(op *OperationDefinition) string { // If we made it this far then we need to handle unmarshaling for each content-type: sortedContentKeys := SortedContentKeys(responseRef.Value.Content) for _, contentTypeName := range sortedContentKeys { + contentType, ok := responseRef.Value.Content[contentTypeName] + if !ok { + continue + } + + // But we can only do this if we actually have a schema (otherwise there will be no struct to unmarshal into): + if contentType.Schema == nil { + fmt.Fprintf(os.Stderr, "Response %s.%s has nil schema\n", operationID, responseName) + continue + } + + // Make sure that we actually have a go-type for this response: + goType, err := GenerateGoSchema(ctx, contentType.Schema, []string{contentTypeName}) + if err != nil { + fmt.Fprintf(os.Stderr, "Unable to determine Go type for %s.%s: %v\n", operationID, contentTypeName, err) + continue + } // We get "interface{}" when using "anyOf" or "oneOf" (which doesn't work with Go types): - if typeDefinition.TypeName == "interface{}" { + if goType.TypeDecl() == "interface{}" && !goType.SkipOptionalPointer { // Unable to unmarshal this, so we leave it out: continue } + // decodeable types unmarshal differently + if goType.TypeDecl() == "interface{}" { + // Need to define the type in a ref in order to decode.Unmarshal + attributeName := fmt.Sprintf("JSON%s", ToCamelCase(responseName)) + + var decorator *Decorator + for _, v := range goType.Decorators { + if v.Discriminator != "" { + decorator = &v + } + } + if decorator != nil { + caseAction := fmt.Sprintf("res, err := decode.UnmarshalJSONInto(bodyBytes, &%s{}, SchemaPathFactory) \n if err != nil { \n return nil, err \n} \n response.%s = &res", decorator.SchemaName, attributeName) + if responseName == "default" { + caseClause := fmt.Sprintf("case strings.Contains(rsp.Header.Get(\"%s\"), \"json\"):", echo.HeaderContentType) + leastSpecific[caseClause] = caseAction + } else { + caseClause := fmt.Sprintf("case strings.Contains(rsp.Header.Get(\"%s\"), \"json\") && rsp.StatusCode == %s:", echo.HeaderContentType, responseName) + mostSpecific[caseClause] = caseAction + } + } + continue + } + // Add content-types here (json / yaml / xml etc): switch { // JSON: case StringInArray(contentTypeName, contentTypesJSON): - var caseAction string - if typeDefinition.Schema.TypeDecl() == "interface{}" { - caseAction = fmt.Sprintf("var temp interface{}\nresponse.%s = &temp \n if err := json.Unmarshal(bodyBytes, response.%s); err != nil { \n return nil, err \n}", typeDefinition.TypeName, typeDefinition.TypeName) + attributeName := fmt.Sprintf("JSON%s", ToCamelCase(responseName)) + fmtStr := "response.%s = &%s{} \n if err := json.Unmarshal(bodyBytes, response.%s); err != nil { \n return nil, err \n}" + if ctx.HasDecorators { + fmtStr = "response.%s = &%s{} \nif _, err := decode.UnmarshalJSONInto(bodyBytes, response.%s, SchemaPathFactory); err != nil { \n return nil, err \n}" + } + caseAction := fmt.Sprintf(fmtStr, attributeName, goType.TypeDecl(), attributeName) + if responseName == "default" { + caseClause := fmt.Sprintf("case strings.Contains(rsp.Header.Get(\"%s\"), \"json\"):", echo.HeaderContentType) + leastSpecific[caseClause] = caseAction } else { caseAction = fmt.Sprintf("response.%s = &%s{} \n if err := json.Unmarshal(bodyBytes, response.%s); err != nil { \n return nil, err \n}", typeDefinition.TypeName, typeDefinition.Schema.TypeDecl(), typeDefinition.TypeName) } @@ -223,8 +271,8 @@ func genResponseTypeName(operationID string) string { return fmt.Sprintf("%s%s", LowercaseFirstCharacter(operationID), responseTypeSuffix) } -func getResponseTypeDefinitions(op *OperationDefinition) []TypeDefinition { - td, err := op.GetResponseTypeDefinitions() +func getResponseTypeDefinitions(ctx *genCtx, op *OperationDefinition) []TypeDefinition { + td, err := op.GetResponseTypeDefinitions(ctx) if err != nil { panic(err) } @@ -261,4 +309,6 @@ var TemplateFunctions = template.FuncMap{ "lower": strings.ToLower, "title": strings.Title, "stripNewLines": stripNewLines, + "split": strings.Split, + "dottedStringToTypeName": DottedStringToTypeName, } diff --git a/pkg/codegen/templates/additional-properties.tmpl b/pkg/codegen/templates/additional-properties.tmpl index 0430d9135..70e1b1367 100644 --- a/pkg/codegen/templates/additional-properties.tmpl +++ b/pkg/codegen/templates/additional-properties.tmpl @@ -1,3 +1,73 @@ +{{if .HasDecorators}} +func factory(fm map[string]func() interface{}, path, dk string, o map[string]interface{}) (interface{}, error) { + var dp interface{} + var dv string + var ok bool + + if dp, ok = o[dk]; !ok { + return nil, fmt.Errorf( "expecting OneOf object at path '%s' to to have a discriminator property '%s'", path, dk ) + } + + if dv, ok = dp.(string); !ok { + return nil, fmt.Errorf("expecting OneOf field '%s's' discriminator property '%s' value to be a string", path, dk) + } + + f, ok := fm[dv] + if !ok { + return nil, fmt.Errorf("Unknown discriminator value '%s' when handling OneOf field '%s'", path, dv) + } + return f(), nil +} + +{{range $key, $value := .DecoratedPaths}} +// Factory method for objects at path {{$key}} +func {{dottedStringToTypeName $key}}_Factory(o map[string]interface{}) (interface{}, error) { + fm := map[string]func() interface{} { {{range $v2 := $value.Factories}} + "{{ $v2.JSONName }}": New{{ $v2.SchemaName }}, + {{- end }} + } + return factory(fm, "{{$key}}", "{{$value.Discriminator}}", o) +} +{{end}} + + +func SchemaPathFactory(path string) (func(map[string]interface{}) (interface{}, error), error) { + // Map StringPath => Factory + pathFactoryMap := map[string]func(map[string]interface{}) (interface{}, error) { {{range $key, $value := .DecoratedPaths}} + "{{$key}}": {{dottedStringToTypeName $key}}_Factory, + {{- end}} + } + + return pathFactoryMap[path], nil +} + + +func TypeFactory(kind string) (interface{}, error) { + // Map StringPath => Factory + var factoryMap = map[string]func() interface{} { {{range $key, $value := .DecoratedSchemas}} + "{{$value.JSONName}}": New{{ $value.SchemaName }}, + {{- end}} + } + f, ok := factoryMap[kind] + if !ok { + return nil, fmt.Errorf("cannot find type %s", kind) + } + return f(), nil +} + +{{range $key, $value := .DecoratedSchemas}} +func New{{ $key }}() interface{} { + _d := "{{- $value.JSONName -}}"; return &{{ $key }} { {{ $value.DiscriminatorPascal }}: {{if ne true $value.Required }} &{{end}}_d } +} + +func (r {{ $key }}) Discriminator() string { + return "{{ $value.Discriminator }}" +} + +{{end -}} +{{end}} + + {{range .Types}}{{$addType := .Schema.AdditionalPropertiesType.TypeDecl}} // Getter for additional properties for {{.TypeName}}. Returns the specified diff --git a/pkg/codegen/templates/client-with-responses.tmpl b/pkg/codegen/templates/client-with-responses.tmpl index e71f4be4e..4d785e9a8 100644 --- a/pkg/codegen/templates/client-with-responses.tmpl +++ b/pkg/codegen/templates/client-with-responses.tmpl @@ -10,7 +10,12 @@ func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithRes if err != nil { return nil, err } - return &ClientWithResponses{client}, nil + return &ClientWithResponses{ + ClientInterface: &Client{ + Client: client, + Server: server, + }, + }, nil } // WithBaseURL overrides the baseURL. @@ -29,10 +34,26 @@ func WithBaseURL(baseURL string) ClientOption { } {{range .}}{{$opid := .OperationId}}{{$op := .}} +// NewClientWithResponsesAndRequestEditorFunc takes in a RequestEditorFn callback function and returns a ClientWithResponses with a default Client: +func NewClientWithResponsesAndRequestEditorFunc(server string, reqEditorFn RequestEditorFn) *ClientWithResponses { + return &ClientWithResponses{ + ClientInterface: &Client{ + Client: &http.Client{}, + Server: server, + RequestEditor: reqEditorFn, + }, + } +} + +func (c *ClientWithResponses) UpdateHttpClient(cli HTTPClientInterface) { + c.ClientInterface.(*Client).Client = cli +} + +{{range .OpDefs}}{{$opid := .OperationId}}{{$op := .}} type {{$opid | lcFirst}}Response struct { Body []byte HTTPResponse *http.Response - {{- range getResponseTypeDefinitions .}} + {{- range getResponseTypeDefinitions $ .}} {{.TypeName}} *{{.Schema.TypeDecl}} {{- end}} } @@ -55,7 +76,7 @@ func (r {{$opid | lcFirst}}Response) StatusCode() int { {{end}} -{{range .}} +{{range .OpDefs}} {{$opid := .OperationId -}} {{/* Generate client methods (with responses)*/}} @@ -84,7 +105,7 @@ func (c *ClientWithResponses) {{$opid}}{{.Suffix}}WithResponse(ctx context.Conte {{end}}{{/* operations */}} {{/* Generate parse functions for responses*/}} -{{range .}}{{$opid := .OperationId}} +{{range .OpDefs}}{{$opid := .OperationId}} // Parse{{genResponseTypeName $opid | ucFirst}} parses an HTTP response from a {{$opid}}WithResponse call func Parse{{genResponseTypeName $opid | ucFirst}}(rsp *http.Response) (*{{genResponseTypeName $opid}}, error) { @@ -96,9 +117,9 @@ func Parse{{genResponseTypeName $opid | ucFirst}}(rsp *http.Response) (*{{genRes response := {{genResponsePayload $opid}} - {{genResponseUnmarshal .}} + {{genResponseUnmarshal $ $opid .Spec.Responses }} return response, nil } -{{end}}{{/* range . $opid := .OperationId */}} +{{end}}{{/* range .OpDefs $opid := .OperationId */}} diff --git a/pkg/codegen/templates/client.tmpl b/pkg/codegen/templates/client.tmpl index 19e0734db..f9b1d3bc7 100644 --- a/pkg/codegen/templates/client.tmpl +++ b/pkg/codegen/templates/client.tmpl @@ -1,11 +1,8 @@ // RequestEditorFn is the function signature for the RequestEditor callback function type RequestEditorFn func(req *http.Request, ctx context.Context) error -// Doer performs HTTP requests. -// -// The standard http.Client implements this interface. -type HttpRequestDoer interface { - Do(req *http.Request) (*http.Response, error) +type HTTPClientInterface interface { + Do(req *http.Request) (*http.Response, error) } // Client which conforms to the OpenAPI3 specification for this service. @@ -14,9 +11,8 @@ type Client struct { // https://api.deepmap.com for example. Server string - // Doer for performing requests, typically a *http.Client with any - // customized settings, such as certificate chains. - Client HttpRequestDoer + // HTTP client with any customized settings, such as certificate chains. + Client HTTPClientInterface // A callback for modifying requests which are generated before sending over // the network. @@ -65,7 +61,7 @@ func WithRequestEditorFn(fn RequestEditorFn) ClientOption { // The interface specification for the client above. type ClientInterface interface { -{{range . -}} +{{range .OpDefs -}} {{$hasParams := .RequiresParamObject -}} {{$pathParams := .PathParams -}} {{$opid := .OperationId -}} @@ -74,12 +70,12 @@ type ClientInterface interface { {{range .Bodies}} {{$opid}}{{.Suffix}}(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}, body {{$opid}}{{.NameTag}}RequestBody) (*http.Response, error) {{end}}{{/* range .Bodies */}} -{{end}}{{/* range . $opid := .OperationId */}} +{{end}}{{/* range .OpDefs $opid := .OperationId */}} } {{/* Generate client methods */}} -{{range . -}} +{{range .OpDefs -}} {{$hasParams := .RequiresParamObject -}} {{$pathParams := .PathParams -}} {{$opid := .OperationId -}} @@ -118,7 +114,7 @@ func (c *Client) {{$opid}}{{.Suffix}}(ctx context.Context{{genParamArgs $pathPar {{end}} {{/* Generate request builders */}} -{{range .}} +{{range .OpDefs}} {{$hasParams := .RequiresParamObject -}} {{$pathParams := .PathParams -}} {{$bodyRequired := .BodyRequired -}} @@ -154,7 +150,7 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr pathParam{{$paramIdx}} = string(pathParamBuf{{$paramIdx}}) {{end}} {{if .IsStyled}} - pathParam{{$paramIdx}}, err = runtime.StyleParam("{{.Style}}", {{.Explode}}, "{{.ParamName}}", {{.GoVariableName}}) + pathParam{{$paramIdx}}, err = runtime.StyleParam("{{.Style}}", {{.Explode}}, url.PathEscape, "{{.ParamName}}", {{.GoVariableName}}) if err != nil { return nil, err } @@ -184,7 +180,8 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr {{end}} {{if .IsStyled}} - if queryFrag, err := runtime.StyleParam("{{.Style}}", {{.Explode}}, "{{.ParamName}}", {{if not .Required}}*{{end}}params.{{.GoName}}); err != nil { + queryParam{{$paramIdx}}, err = runtime.StyleParam("{{.Style}}", {{.Explode}}, url.QueryEscape, "{{.ParamName}}", {{if not .Required}}*{{end}}params.{{.GoName}}) + if err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { return nil, err @@ -220,7 +217,10 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr headerParam{{$paramIdx}} = string(headerParamBuf{{$paramIdx}}) {{end}} {{if .IsStyled}} - headerParam{{$paramIdx}}, err = runtime.StyleParam("{{.Style}}", {{.Explode}}, "{{.ParamName}}", {{if not .Required}}*{{end}}params.{{.GoName}}) + passthrough := func(s string) string { + return s + } + headerParam{{$paramIdx}}, err = runtime.StyleParam("{{.Style}}", {{.Explode}}, passthrough, "{{.ParamName}}", {{if not .Required}}*{{end}}params.{{.GoName}}) if err != nil { return nil, err } @@ -244,7 +244,10 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr cookieParam{{$paramIdx}} = url.QueryEscape(string(cookieParamBuf{{$paramIdx}})) {{end}} {{if .IsStyled}} - cookieParam{{$paramIdx}}, err = runtime.StyleParam("simple", {{.Explode}}, "{{.ParamName}}", {{if not .Required}}*{{end}}params.{{.GoName}}) + passthrough := func(s string) string { + return s + } + cookieParam{{$paramIdx}}, err = runtime.StyleParam("simple", {{.Explode}}, passthrough, "{{.ParamName}}", {{if not .Required}}*{{end}}params.{{.GoName}}) if err != nil { return nil, err } diff --git a/pkg/codegen/templates/imports.tmpl b/pkg/codegen/templates/imports.tmpl index b5c5f1ed8..4da634468 100644 --- a/pkg/codegen/templates/imports.tmpl +++ b/pkg/codegen/templates/imports.tmpl @@ -1,10 +1,10 @@ // Package {{.PackageName}} provides primitives to interact the openapi HTTP API. // -// Code generated by github.com/deepmap/oapi-codegen DO NOT EDIT. +// Code generated by github.com/weberr13/oapi-codegen DO NOT EDIT. package {{.PackageName}} {{if .Imports}} import ( -{{range .Imports}} {{ . }} +{{range .Imports}} {{.PackageName}} "{{.ImportPath}}" {{end}}) {{end}} diff --git a/pkg/codegen/templates/inline.tmpl b/pkg/codegen/templates/inline.tmpl index 0ab3116ea..26c7a33fe 100644 --- a/pkg/codegen/templates/inline.tmpl +++ b/pkg/codegen/templates/inline.tmpl @@ -7,23 +7,34 @@ var swaggerSpec = []string{ // GetSwagger returns the Swagger specification corresponding to the generated code // in this file. func GetSwagger() (*openapi3.Swagger, error) { + + spec, err := GetSwaggerSpec() + if err != nil { + return nil, err + } + swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData([]byte(spec)) + if err != nil { + return nil, fmt.Errorf("error loading Swagger: %s", err) + } + return swagger, nil +} + + +// GetSwaggerSpec returns the Swagger specification as string corresponding to the generated code +// in this file. +func GetSwaggerSpec() (string, error) { zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, "")) if err != nil { - return nil, fmt.Errorf("error base64 decoding spec: %s", err) + return "", 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) + return "", 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) - } - - swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(buf.Bytes()) - if err != nil { - return nil, fmt.Errorf("error loading Swagger: %s", err) + return "", fmt.Errorf("error decompressing spec: %s", err) } - return swagger, nil + return buf.String(), nil } diff --git a/pkg/codegen/templates/param-types.tmpl b/pkg/codegen/templates/param-types.tmpl index b35cce5d7..1089fd0b7 100644 --- a/pkg/codegen/templates/param-types.tmpl +++ b/pkg/codegen/templates/param-types.tmpl @@ -1,4 +1,4 @@ -{{range .}}{{$opid := .OperationId}} +{{range .OpDefs}}{{$opid := .OperationId}} {{range .TypeDefinitions}} // {{.TypeName}} defines parameters for {{$opid}}. type {{.TypeName}} {{.Schema.TypeDecl}} diff --git a/pkg/codegen/templates/register.tmpl b/pkg/codegen/templates/register.tmpl index 4198b23b3..2b4a86692 100644 --- a/pkg/codegen/templates/register.tmpl +++ b/pkg/codegen/templates/register.tmpl @@ -17,6 +17,6 @@ func RegisterHandlers(router interface { Handler: si, } {{end}} -{{range .}}router.{{.Method}}("{{.Path | swaggerUriToEchoUri}}", wrapper.{{.OperationId}}) +{{range .OpDefs}}router.{{.Method}}("{{.Path | swaggerUriToEchoUri}}", wrapper.{{.OperationId}}) {{end}} } diff --git a/pkg/codegen/templates/request-bodies.tmpl b/pkg/codegen/templates/request-bodies.tmpl index cec74bcb0..5db05b299 100644 --- a/pkg/codegen/templates/request-bodies.tmpl +++ b/pkg/codegen/templates/request-bodies.tmpl @@ -1,4 +1,4 @@ -{{range .}}{{$opid := .OperationId}} +{{range .OpDefs}}{{$opid := .OperationId}} {{range .Bodies}} // {{$opid}}RequestBody defines body for {{$opid}} for application/json ContentType. type {{$opid}}{{.NameTag}}RequestBody {{.TypeDef}} diff --git a/pkg/codegen/templates/templates.gen.go b/pkg/codegen/templates/templates.gen.go index d674c6d13..1aaa39f25 100644 --- a/pkg/codegen/templates/templates.gen.go +++ b/pkg/codegen/templates/templates.gen.go @@ -2,7 +2,77 @@ package templates import "text/template" -var templates = map[string]string{"additional-properties.tmpl": `{{range .Types}}{{$addType := .Schema.AdditionalPropertiesType.TypeDecl}} +var templates = map[string]string{"additional-properties.tmpl": `{{if .HasDecorators}} +func factory(fm map[string]func() interface{}, path, dk string, o map[string]interface{}) (interface{}, error) { + var dp interface{} + var dv string + var ok bool + + if dp, ok = o[dk]; !ok { + return nil, fmt.Errorf( "expecting OneOf object at path '%s' to to have a discriminator property '%s'", path, dk ) + } + + if dv, ok = dp.(string); !ok { + return nil, fmt.Errorf("expecting OneOf field '%s's' discriminator property '%s' value to be a string", path, dk) + } + + f, ok := fm[dv] + if !ok { + return nil, fmt.Errorf("Unknown discriminator value '%s' when handling OneOf field '%s'", path, dv) + } + return f(), nil +} + +{{range $key, $value := .DecoratedPaths}} +// Factory method for objects at path {{$key}} +func {{dottedStringToTypeName $key}}_Factory(o map[string]interface{}) (interface{}, error) { + fm := map[string]func() interface{} { {{range $v2 := $value.Factories}} + "{{ $v2.JSONName }}": New{{ $v2.SchemaName }}, + {{- end }} + } + return factory(fm, "{{$key}}", "{{$value.Discriminator}}", o) +} +{{end}} + + +func SchemaPathFactory(path string) (func(map[string]interface{}) (interface{}, error), error) { + // Map StringPath => Factory + pathFactoryMap := map[string]func(map[string]interface{}) (interface{}, error) { {{range $key, $value := .DecoratedPaths}} + "{{$key}}": {{dottedStringToTypeName $key}}_Factory, + {{- end}} + } + + return pathFactoryMap[path], nil +} + + +func TypeFactory(kind string) (interface{}, error) { + // Map StringPath => Factory + var factoryMap = map[string]func() interface{} { {{range $key, $value := .DecoratedSchemas}} + "{{$value.JSONName}}": New{{ $value.SchemaName }}, + {{- end}} + } + f, ok := factoryMap[kind] + if !ok { + return nil, fmt.Errorf("cannot find type %s", kind) + } + return f(), nil +} + +{{range $key, $value := .DecoratedSchemas}} +func New{{ $key }}() interface{} { + _d := "{{- $value.JSONName -}}"; return &{{ $key }} { {{ $value.DiscriminatorPascal }}: {{if ne true $value.Required }} &{{end}}_d } +} + +func (r {{ $key }}) Discriminator() string { + return "{{ $value.Discriminator }}" +} + +{{end -}} +{{end}} + + +{{range .Types}}{{$addType := .Schema.AdditionalPropertiesType.TypeDecl}} // Getter for additional properties for {{.TypeName}}. Returns the specified // element and whether it was found @@ -282,7 +352,12 @@ func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithRes if err != nil { return nil, err } - return &ClientWithResponses{client}, nil + return &ClientWithResponses{ + ClientInterface: &Client{ + Client: client, + Server: server, + }, + }, nil } // WithBaseURL overrides the baseURL. @@ -301,10 +376,26 @@ func WithBaseURL(baseURL string) ClientOption { } {{range .}}{{$opid := .OperationId}}{{$op := .}} +// NewClientWithResponsesAndRequestEditorFunc takes in a RequestEditorFn callback function and returns a ClientWithResponses with a default Client: +func NewClientWithResponsesAndRequestEditorFunc(server string, reqEditorFn RequestEditorFn) *ClientWithResponses { + return &ClientWithResponses{ + ClientInterface: &Client{ + Client: &http.Client{}, + Server: server, + RequestEditor: reqEditorFn, + }, + } +} + +func (c *ClientWithResponses) UpdateHttpClient(cli HTTPClientInterface) { + c.ClientInterface.(*Client).Client = cli +} + +{{range .OpDefs}}{{$opid := .OperationId}}{{$op := .}} type {{$opid | lcFirst}}Response struct { Body []byte HTTPResponse *http.Response - {{- range getResponseTypeDefinitions .}} + {{- range getResponseTypeDefinitions $ .}} {{.TypeName}} *{{.Schema.TypeDecl}} {{- end}} } @@ -327,7 +418,7 @@ func (r {{$opid | lcFirst}}Response) StatusCode() int { {{end}} -{{range .}} +{{range .OpDefs}} {{$opid := .OperationId -}} {{/* Generate client methods (with responses)*/}} @@ -356,7 +447,7 @@ func (c *ClientWithResponses) {{$opid}}{{.Suffix}}WithResponse(ctx context.Conte {{end}}{{/* operations */}} {{/* Generate parse functions for responses*/}} -{{range .}}{{$opid := .OperationId}} +{{range .OpDefs}}{{$opid := .OperationId}} // Parse{{genResponseTypeName $opid | ucFirst}} parses an HTTP response from a {{$opid}}WithResponse call func Parse{{genResponseTypeName $opid | ucFirst}}(rsp *http.Response) (*{{genResponseTypeName $opid}}, error) { @@ -368,21 +459,18 @@ func Parse{{genResponseTypeName $opid | ucFirst}}(rsp *http.Response) (*{{genRes response := {{genResponsePayload $opid}} - {{genResponseUnmarshal .}} + {{genResponseUnmarshal $ $opid .Spec.Responses }} return response, nil } -{{end}}{{/* range . $opid := .OperationId */}} +{{end}}{{/* range .OpDefs $opid := .OperationId */}} `, "client.tmpl": `// RequestEditorFn is the function signature for the RequestEditor callback function type RequestEditorFn func(req *http.Request, ctx context.Context) error -// Doer performs HTTP requests. -// -// The standard http.Client implements this interface. -type HttpRequestDoer interface { - Do(req *http.Request) (*http.Response, error) +type HTTPClientInterface interface { + Do(req *http.Request) (*http.Response, error) } // Client which conforms to the OpenAPI3 specification for this service. @@ -391,9 +479,8 @@ type Client struct { // https://api.deepmap.com for example. Server string - // Doer for performing requests, typically a *http.Client with any - // customized settings, such as certificate chains. - Client HttpRequestDoer + // HTTP client with any customized settings, such as certificate chains. + Client HTTPClientInterface // A callback for modifying requests which are generated before sending over // the network. @@ -442,7 +529,7 @@ func WithRequestEditorFn(fn RequestEditorFn) ClientOption { // The interface specification for the client above. type ClientInterface interface { -{{range . -}} +{{range .OpDefs -}} {{$hasParams := .RequiresParamObject -}} {{$pathParams := .PathParams -}} {{$opid := .OperationId -}} @@ -451,12 +538,12 @@ type ClientInterface interface { {{range .Bodies}} {{$opid}}{{.Suffix}}(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}, body {{$opid}}{{.NameTag}}RequestBody) (*http.Response, error) {{end}}{{/* range .Bodies */}} -{{end}}{{/* range . $opid := .OperationId */}} +{{end}}{{/* range .OpDefs $opid := .OperationId */}} } {{/* Generate client methods */}} -{{range . -}} +{{range .OpDefs -}} {{$hasParams := .RequiresParamObject -}} {{$pathParams := .PathParams -}} {{$opid := .OperationId -}} @@ -495,7 +582,7 @@ func (c *Client) {{$opid}}{{.Suffix}}(ctx context.Context{{genParamArgs $pathPar {{end}} {{/* Generate request builders */}} -{{range .}} +{{range .OpDefs}} {{$hasParams := .RequiresParamObject -}} {{$pathParams := .PathParams -}} {{$bodyRequired := .BodyRequired -}} @@ -531,7 +618,7 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr pathParam{{$paramIdx}} = string(pathParamBuf{{$paramIdx}}) {{end}} {{if .IsStyled}} - pathParam{{$paramIdx}}, err = runtime.StyleParam("{{.Style}}", {{.Explode}}, "{{.ParamName}}", {{.GoVariableName}}) + pathParam{{$paramIdx}}, err = runtime.StyleParam("{{.Style}}", {{.Explode}}, url.PathEscape, "{{.ParamName}}", {{.GoVariableName}}) if err != nil { return nil, err } @@ -561,7 +648,8 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr {{end}} {{if .IsStyled}} - if queryFrag, err := runtime.StyleParam("{{.Style}}", {{.Explode}}, "{{.ParamName}}", {{if not .Required}}*{{end}}params.{{.GoName}}); err != nil { + queryParam{{$paramIdx}}, err = runtime.StyleParam("{{.Style}}", {{.Explode}}, url.QueryEscape, "{{.ParamName}}", {{if not .Required}}*{{end}}params.{{.GoName}}) + if err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { return nil, err @@ -597,7 +685,10 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr headerParam{{$paramIdx}} = string(headerParamBuf{{$paramIdx}}) {{end}} {{if .IsStyled}} - headerParam{{$paramIdx}}, err = runtime.StyleParam("{{.Style}}", {{.Explode}}, "{{.ParamName}}", {{if not .Required}}*{{end}}params.{{.GoName}}) + passthrough := func(s string) string { + return s + } + headerParam{{$paramIdx}}, err = runtime.StyleParam("{{.Style}}", {{.Explode}}, passthrough, "{{.ParamName}}", {{if not .Required}}*{{end}}params.{{.GoName}}) if err != nil { return nil, err } @@ -621,7 +712,10 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr cookieParam{{$paramIdx}} = url.QueryEscape(string(cookieParamBuf{{$paramIdx}})) {{end}} {{if .IsStyled}} - cookieParam{{$paramIdx}}, err = runtime.StyleParam("simple", {{.Explode}}, "{{.ParamName}}", {{if not .Required}}*{{end}}params.{{.GoName}}) + passthrough := func(s string) string { + return s + } + cookieParam{{$paramIdx}}, err = runtime.StyleParam("simple", {{.Explode}}, passthrough, "{{.ParamName}}", {{if not .Required}}*{{end}}params.{{.GoName}}) if err != nil { return nil, err } @@ -641,12 +735,12 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr `, "imports.tmpl": `// Package {{.PackageName}} provides primitives to interact the openapi HTTP API. // -// Code generated by github.com/deepmap/oapi-codegen DO NOT EDIT. +// Code generated by github.com/weberr13/oapi-codegen DO NOT EDIT. package {{.PackageName}} {{if .Imports}} import ( -{{range .Imports}} {{ . }} +{{range .Imports}} {{.PackageName}} "{{.ImportPath}}" {{end}}) {{end}} `, @@ -659,28 +753,39 @@ var swaggerSpec = []string{ // GetSwagger returns the Swagger specification corresponding to the generated code // in this file. func GetSwagger() (*openapi3.Swagger, error) { + + spec, err := GetSwaggerSpec() + if err != nil { + return nil, err + } + swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData([]byte(spec)) + if err != nil { + return nil, fmt.Errorf("error loading Swagger: %s", err) + } + return swagger, nil +} + + +// GetSwaggerSpec returns the Swagger specification as string corresponding to the generated code +// in this file. +func GetSwaggerSpec() (string, error) { zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, "")) if err != nil { - return nil, fmt.Errorf("error base64 decoding spec: %s", err) + return "", 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) + return "", 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 "", fmt.Errorf("error decompressing spec: %s", err) } - - swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(buf.Bytes()) - if err != nil { - return nil, fmt.Errorf("error loading Swagger: %s", err) - } - return swagger, nil + return buf.String(), nil } `, - "param-types.tmpl": `{{range .}}{{$opid := .OperationId}} + "param-types.tmpl": `{{range .OpDefs}}{{$opid := .OperationId}} {{range .TypeDefinitions}} // {{.TypeName}} defines parameters for {{$opid}}. type {{.TypeName}} {{.Schema.TypeDecl}} @@ -706,11 +811,11 @@ func RegisterHandlers(router interface { Handler: si, } {{end}} -{{range .}}router.{{.Method}}("{{.Path | swaggerUriToEchoUri}}", wrapper.{{.OperationId}}) +{{range .OpDefs}}router.{{.Method}}("{{.Path | swaggerUriToEchoUri}}", wrapper.{{.OperationId}}) {{end}} } `, - "request-bodies.tmpl": `{{range .}}{{$opid := .OperationId}} + "request-bodies.tmpl": `{{range .OpDefs}}{{$opid := .OperationId}} {{range .Bodies}} // {{$opid}}RequestBody defines body for {{$opid}} for application/json ContentType. type {{$opid}}{{.NameTag}}RequestBody {{.TypeDef}} @@ -725,7 +830,7 @@ type ServerInterface interface { {{end}} } `, - "typedef.tmpl": `{{range .Types}} + "typedef.tmpl": `{{range .TypeDefs}} // {{.TypeName}} defines model for {{.JsonName}}. type {{.TypeName}} {{.Schema.TypeDecl}} {{end}} @@ -735,7 +840,7 @@ type ServerInterfaceWrapper struct { Handler ServerInterface } -{{range .}}{{$opid := .OperationId}}// {{$opid}} converts echo context to params. +{{range .OpDefs}}{{$opid := .OperationId}}// {{$opid}} converts echo context to params. func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error { var err error {{range .PathParams}}// ------------- Path parameter "{{.ParamName}}" ------------- @@ -750,7 +855,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error { } {{end}} {{if .IsStyled}} - err = runtime.BindStyledParameter("{{.Style}}",{{.Explode}}, "{{.ParamName}}", ctx.Param("{{.ParamName}}"), &{{$varName}}) + err = runtime.BindStyledParameter("{{.Style}}",{{.Explode}}, url.PathUnescape, "{{.ParamName}}", ctx.Param("{{.ParamName}}"), &{{$varName}}) if err != nil { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err)) } @@ -807,7 +912,10 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error { } {{end}} {{if .IsStyled}} - err = runtime.BindStyledParameter("{{.Style}}",{{.Explode}}, "{{.ParamName}}", valueList[0], &{{.GoName}}) + passthrough := func(s string) (string, error) { + return s, nil + } + err = runtime.BindStyledParameter("{{.Style}}",{{.Explode}}, passthrough, "{{.ParamName}}", valueList[0], &{{.GoName}}) if err != nil { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err)) } @@ -839,7 +947,10 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error { {{end}} {{if .IsStyled}} var value {{.TypeDef}} - err = runtime.BindStyledParameter("simple",{{.Explode}}, "{{.ParamName}}", cookie.Value, &value) + passthrough := func(s string) (string, error) { + return s, nil + } + err = runtime.BindStyledParameter("simple",{{.Explode}}, passthrough, "{{.ParamName}}", cookie.Value, &value) if err != nil { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err)) } diff --git a/pkg/codegen/templates/typedef.tmpl b/pkg/codegen/templates/typedef.tmpl index d93847ac1..60241f598 100644 --- a/pkg/codegen/templates/typedef.tmpl +++ b/pkg/codegen/templates/typedef.tmpl @@ -1,4 +1,4 @@ -{{range .Types}} +{{range .TypeDefs}} // {{.TypeName}} defines model for {{.JsonName}}. type {{.TypeName}} {{.Schema.TypeDecl}} {{end}} diff --git a/pkg/codegen/templates/wrappers.tmpl b/pkg/codegen/templates/wrappers.tmpl index d82ac0342..5f7fa70d8 100644 --- a/pkg/codegen/templates/wrappers.tmpl +++ b/pkg/codegen/templates/wrappers.tmpl @@ -3,7 +3,7 @@ type ServerInterfaceWrapper struct { Handler ServerInterface } -{{range .}}{{$opid := .OperationId}}// {{$opid}} converts echo context to params. +{{range .OpDefs}}{{$opid := .OperationId}}// {{$opid}} converts echo context to params. func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error { var err error {{range .PathParams}}// ------------- Path parameter "{{.ParamName}}" ------------- @@ -18,7 +18,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error { } {{end}} {{if .IsStyled}} - err = runtime.BindStyledParameter("{{.Style}}",{{.Explode}}, "{{.ParamName}}", ctx.Param("{{.ParamName}}"), &{{$varName}}) + err = runtime.BindStyledParameter("{{.Style}}",{{.Explode}}, url.PathUnescape, "{{.ParamName}}", ctx.Param("{{.ParamName}}"), &{{$varName}}) if err != nil { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err)) } @@ -75,7 +75,10 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error { } {{end}} {{if .IsStyled}} - err = runtime.BindStyledParameter("{{.Style}}",{{.Explode}}, "{{.ParamName}}", valueList[0], &{{.GoName}}) + passthrough := func(s string) (string, error) { + return s, nil + } + err = runtime.BindStyledParameter("{{.Style}}",{{.Explode}}, passthrough, "{{.ParamName}}", valueList[0], &{{.GoName}}) if err != nil { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err)) } @@ -107,7 +110,10 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error { {{end}} {{if .IsStyled}} var value {{.TypeDef}} - err = runtime.BindStyledParameter("simple",{{.Explode}}, "{{.ParamName}}", cookie.Value, &value) + passthrough := func(s string) (string, error) { + return s, nil + } + err = runtime.BindStyledParameter("simple",{{.Explode}}, passthrough, "{{.ParamName}}", cookie.Value, &value) if err != nil { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err)) } diff --git a/pkg/codegen/testdata/failedOneOfAnonymousSchema.yaml b/pkg/codegen/testdata/failedOneOfAnonymousSchema.yaml new file mode 100644 index 000000000..d3f391336 --- /dev/null +++ b/pkg/codegen/testdata/failedOneOfAnonymousSchema.yaml @@ -0,0 +1,90 @@ +openapi: 3.0.1 +info: + title: failed + version: 1.0.0 +servers: [] +paths: {} +components: + schemas: + Cat: + type: object + properties: + type: + type: string + + # refer to schema that has a oneOf + sound: + oneOf: + - $ref: '#/components/schemas/Meow' + - $ref: '#/components/schemas/Growl' + discriminator: + propertyName: type + mapping: + LOUD: '#/components/schemas/Meow' + WARN: '#/components/schemas/Growl' + + # nested anonymous schemas with oneOf are unsupported + echoChamberOneOf: + type: object + properties: + type: + type: string + sound: + oneOf: + - $ref: '#/components/schemas/Meow' + - $ref: '#/components/schemas/Purr' + discriminator: + propertyName: type + + + GeneralSound: + type: object + properties: + type: + type: string + sound: + type: string + + GeneralOneOfSound: + type: object + properties: + type: + type: string + sound: + oneOf: + - $ref: '#/components/schemas/Meow' + - $ref: '#/components/schemas/Purr' + - $ref: '#/components/schemas/Growl' + discriminator: + propertyName: type + mapping: + LOUD: '#/components/schemas/Meow' + WARN: '#/components/schemas/Growl' + + Meow: + type: object + properties: + type: + type: string + enum: [MEOW] + squeel: + type: string + + Purr: + type: object + properties: + type: + type: string + enum: [PURR] + heritage: + type: string + + Growl: + type: object + properties: + type: + type: string + enum: [GROWL] + severity: + type: string + diff --git a/pkg/codegen/testdata/failedOneOfMissingDiscriminator.yaml b/pkg/codegen/testdata/failedOneOfMissingDiscriminator.yaml new file mode 100644 index 000000000..36ec1ee07 --- /dev/null +++ b/pkg/codegen/testdata/failedOneOfMissingDiscriminator.yaml @@ -0,0 +1,152 @@ +openapi: 3.0.1 + +info: + title: OpenAPI-CodeGen Test + description: 'This is a test OpenAPI Spec' + version: 1.0.0 + +servers: +- url: https://test.oapi-codegen.com/v2 +- url: http://test.oapi-codegen.com/v2 + +paths: + /test/{name}: + get: + tags: + - test + summary: Get test + operationId: getTestByName + parameters: + - name: name + in: path + required: true + schema: + type: string + responses: + 200: + description: Success + content: + application/xml: + schema: + type: array + items: + $ref: '#/components/schemas/Test' + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Test' + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /cat: + put: + summary: deposit cats + operationId: putCats + requestBody: + description: list of feline creatures + required: true + content: + application-json: + schema: + $ref: '#/components/schemas/Cats' + + get: + tags: + - cat + summary: Get cat status + operationId: getCatStatus + responses: + 200: + description: Success + content: + application/json: + schema: + discriminator: + propertyName: "type" + oneOf: + - $ref: '#/components/schemas/CatAlive' + - $ref: '#/components/schemas/CatDead' + application/xml: + schema: + anyOf: + - $ref: '#/components/schemas/CatAlive' + - $ref: '#/components/schemas/CatDead' + application/yaml: + schema: + allOf: + - $ref: '#/components/schemas/CatAlive' + - $ref: '#/components/schemas/CatDead' + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + +components: + schemas: + + Test: + properties: + name: + type: string + cases: + type: array + items: + $ref: '#/components/schemas/TestCase' + + TestCase: + properties: + name: + type: string + command: + type: string + + Cats: + type: object + properties: + box: + $ref: '#/components/schemas/CatBox' + + CatBox: + type: object + discriminator: + propertyName: "type" + oneOf: + - $ref: '#/components/schemas/CatAlive' + - $ref: '#/components/schemas/CatDead' + + Error: + properties: + code: + type: integer + format: int32 + message: + type: string + + CatAlive: + properties: + name: + type: string + alive_since: + type: string + format: date-time + + CatDead: + properties: + type: + type: string + enum: + - cat_dead + name: + type: string + dead_since: + type: string + format: date-time + cause: + type: string + enum: [car, dog, oldage] diff --git a/pkg/codegen/testdata/included.yaml b/pkg/codegen/testdata/included.yaml new file mode 100644 index 000000000..6bb4fd2c0 --- /dev/null +++ b/pkg/codegen/testdata/included.yaml @@ -0,0 +1,19 @@ +openapi: 3.0.1 + +info: + title: OpenAPI-CodeGen Test + description: 'This is a test OpenAPI Spec' + version: 1.0.0 + +servers: +- url: http://test.oapi-codegen.com/v2 + +paths: {} + +components: + schemas: + Verifier: + properties: + name: + type: string + diff --git a/pkg/codegen/testdata/pets.golden b/pkg/codegen/testdata/pets.golden new file mode 100644 index 000000000..11d1a0571 --- /dev/null +++ b/pkg/codegen/testdata/pets.golden @@ -0,0 +1,784 @@ +// Package testswagger provides primitives to interact the openapi HTTP API. +// +// Code generated by github.com/weberr13/oapi-codegen DO NOT EDIT. +package testswagger + +import ( + "bytes" + "compress/gzip" + "context" + "encoding/base64" + "fmt" + "github.com/deepmap/oapi-codegen/pkg/runtime" + "github.com/getkin/kin-openapi/openapi3" + "github.com/labstack/echo/v4" + "github.com/weberr13/go-decode/decode" + "io" + "io/ioutil" + "net/http" + "strings" +) + +// Accommodation defines model for Accommodation. +type Accommodation struct { + Class interface{} `json:"class,omitempty"` + Title *string `json:"title,omitempty"` +} + +// Bark defines model for Bark. +type Bark struct { + Type *string `json:"type,omitempty"` + Volume *int `json:"volume,omitempty"` +} + +// Cat defines model for Cat. +type Cat struct { + FavSound interface{} `json:"favSound,omitempty"` + Mood *string `json:"mood,omitempty"` + Sound interface{} `json:"sound,omitempty"` + Type *string `json:"type,omitempty"` +} + +// Cheetah defines model for Cheetah. +type Cheetah struct { + Echo *SchemaWithSound `json:"echo,omitempty"` + EchoChamber *struct { + Sound *string `json:"sound,omitempty"` + Type *string `json:"type,omitempty"` + } `json:"echoChamber,omitempty"` + EchoOneOf *SchemaWithOneOfSound `json:"echoOneOf,omitempty"` + FavSound interface{} `json:"favSound,omitempty"` + Sound interface{} `json:"sound,omitempty"` + Type *string `json:"type,omitempty"` +} + +// Dog defines model for Dog. +type Dog struct { + Kind *string `json:"kind,omitempty"` + Sound interface{} `json:"sound,omitempty"` + Type *string `json:"type,omitempty"` +} + +// Error defines model for Error. +type Error struct { + Code *string `json:"code,omitempty"` + Message *string `json:"message,omitempty"` +} + +// Growl defines model for Growl. +type Growl struct { + Severity *string `json:"severity,omitempty"` + Type *string `json:"type,omitempty"` +} + +// House defines model for House. +type House struct { + Name *string `json:"name,omitempty"` + Rooms *int `json:"rooms,omitempty"` + Type *string `json:"type,omitempty"` +} + +// Kennel defines model for Kennel. +type Kennel struct { + Name *string `json:"name,omitempty"` + Rooms *int `json:"rooms,omitempty"` + Type *string `json:"type,omitempty"` +} + +// Meow defines model for Meow. +type Meow struct { + Squeel *string `json:"squeel,omitempty"` + Type *string `json:"type,omitempty"` +} + +// Palace defines model for Palace. +type Palace struct { + Halls *int `json:"Halls,omitempty"` + Name *string `json:"name,omitempty"` + Towers *int `json:"towers,omitempty"` + Type *string `json:"type,omitempty"` +} + +// PetOwner defines model for PetOwner. +type PetOwner struct { + Age *int `json:"age,omitempty"` + Dogs *[]Dog `json:"dogs,omitempty"` + Favorite interface{} `json:"favorite,omitempty"` + LivesIn interface{} `json:"livesIn,omitempty"` + Name *string `json:"name,omitempty"` + Owns *[]Accommodation `json:"owns,omitempty"` + PetLivesIn *Accommodation `json:"petLivesIn,omitempty"` +} + +// PetOwnerStatus defines model for PetOwnerStatus. +type PetOwnerStatus interface{} + +// Purr defines model for Purr. +type Purr struct { + Heritage *Accommodation `json:"heritage,omitempty"` + Type *string `json:"type,omitempty"` +} + +// SchemaWithOneOfSound defines model for SchemaWithOneOfSound. +type SchemaWithOneOfSound struct { + Sound interface{} `json:"sound,omitempty"` + Type *string `json:"type,omitempty"` +} + +// SchemaWithSound defines model for SchemaWithSound. +type SchemaWithSound struct { + Sound *string `json:"sound,omitempty"` + Type *string `json:"type,omitempty"` +} + +// Shack defines model for Shack. +type Shack struct { + Material *string `json:"material,omitempty"` + Name *string `json:"name,omitempty"` + Type *string `json:"type,omitempty"` +} + +func factory(fm map[string]func() interface{}, path, dk string, o map[string]interface{}) (interface{}, error) { + var dp interface{} + var dv string + var ok bool + + if dp, ok = o[dk]; !ok { + return nil, fmt.Errorf("expecting OneOf object at path '%s' to to have a discriminator property '%s'", path, dk) + } + + if dv, ok = dp.(string); !ok { + return nil, fmt.Errorf("expecting OneOf field '%s's' discriminator property '%s' value to be a string", path, dk) + } + + f, ok := fm[dv] + if !ok { + return nil, fmt.Errorf("Unknown discriminator value '%s' when handling OneOf field '%s'", path, dv) + } + return f(), nil +} + +// Factory method for objects at path Accommodation.class +func Accommodation_class_Factory(o map[string]interface{}) (interface{}, error) { + fm := map[string]func() interface{}{ + "BARK": NewKennel, + "House": NewHouse, + "Palace": NewPalace, + "Shack": NewShack, + } + return factory(fm, "Accommodation.class", "type", o) +} + +// Factory method for objects at path Cat.favSound +func Cat_favSound_Factory(o map[string]interface{}) (interface{}, error) { + fm := map[string]func() interface{}{ + "MEOW": NewMeow, + "PURR": NewPurr, + } + return factory(fm, "Cat.favSound", "type", o) +} + +// Factory method for objects at path Cat.sound +func Cat_sound_Factory(o map[string]interface{}) (interface{}, error) { + fm := map[string]func() interface{}{ + "LOUD": NewMeow, + "PURR": NewPurr, + "WARN": NewGrowl, + } + return factory(fm, "Cat.sound", "type", o) +} + +// Factory method for objects at path Cheetah.favSound +func Cheetah_favSound_Factory(o map[string]interface{}) (interface{}, error) { + fm := map[string]func() interface{}{ + "MEOW": NewMeow, + "PURR": NewPurr, + } + return factory(fm, "Cheetah.favSound", "type", o) +} + +// Factory method for objects at path Cheetah.sound +func Cheetah_sound_Factory(o map[string]interface{}) (interface{}, error) { + fm := map[string]func() interface{}{ + "LOUD": NewMeow, + "PURR": NewPurr, + "WARN": NewGrowl, + } + return factory(fm, "Cheetah.sound", "type", o) +} + +// Factory method for objects at path Dog.sound +func Dog_sound_Factory(o map[string]interface{}) (interface{}, error) { + fm := map[string]func() interface{}{ + "BARK": NewBark, + } + return factory(fm, "Dog.sound", "type", o) +} + +// Factory method for objects at path PetOwner.favorite +func PetOwner_favorite_Factory(o map[string]interface{}) (interface{}, error) { + fm := map[string]func() interface{}{ + "Cat": NewCat, + "Dog": NewDog, + } + return factory(fm, "PetOwner.favorite", "type", o) +} + +// Factory method for objects at path PetOwner.livesIn +func PetOwner_livesIn_Factory(o map[string]interface{}) (interface{}, error) { + fm := map[string]func() interface{}{ + "House": NewHouse, + "Palace": NewPalace, + } + return factory(fm, "PetOwner.livesIn", "type", o) +} + +// Factory method for objects at path SchemaWithOneOfSound.sound +func SchemaWithOneOfSound_sound_Factory(o map[string]interface{}) (interface{}, error) { + fm := map[string]func() interface{}{ + "LOUD": NewMeow, + "PURR": NewPurr, + "WARN": NewGrowl, + } + return factory(fm, "SchemaWithOneOfSound.sound", "type", o) +} + +func SchemaPathFactory(path string) (func(map[string]interface{}) (interface{}, error), error) { + // Map StringPath => Factory + pathFactoryMap := map[string]func(map[string]interface{}) (interface{}, error){ + "Accommodation.class": Accommodation_class_Factory, + "Cat.favSound": Cat_favSound_Factory, + "Cat.sound": Cat_sound_Factory, + "Cheetah.favSound": Cheetah_favSound_Factory, + "Cheetah.sound": Cheetah_sound_Factory, + "Dog.sound": Dog_sound_Factory, + "PetOwner.favorite": PetOwner_favorite_Factory, + "PetOwner.livesIn": PetOwner_livesIn_Factory, + "SchemaWithOneOfSound.sound": SchemaWithOneOfSound_sound_Factory, + } + + return pathFactoryMap[path], nil +} + +func TypeFactory(kind string) (interface{}, error) { + // Map StringPath => Factory + var factoryMap = map[string]func() interface{}{ + "BARK": NewBark, + "Cat": NewCat, + "Dog": NewDog, + "WARN": NewGrowl, + "House": NewHouse, + "BARK": NewKennel, + "MEOW": NewMeow, + "Palace": NewPalace, + "PURR": NewPurr, + "Shack": NewShack, + } + f, ok := factoryMap[kind] + if !ok { + return nil, fmt.Errorf("cannot find type %s", kind) + } + return f(), nil +} + +func NewBark() interface{} { + _d := "BARK" + return &Bark{Type: &_d} +} + +func (r Bark) Discriminator() string { + return "type" +} + +func NewCat() interface{} { + _d := "Cat" + return &Cat{Type: &_d} +} + +func (r Cat) Discriminator() string { + return "type" +} + +func NewDog() interface{} { + _d := "Dog" + return &Dog{Type: &_d} +} + +func (r Dog) Discriminator() string { + return "type" +} + +func NewGrowl() interface{} { + _d := "WARN" + return &Growl{Type: &_d} +} + +func (r Growl) Discriminator() string { + return "type" +} + +func NewHouse() interface{} { + _d := "House" + return &House{Type: &_d} +} + +func (r House) Discriminator() string { + return "type" +} + +func NewKennel() interface{} { + _d := "BARK" + return &Kennel{Type: &_d} +} + +func (r Kennel) Discriminator() string { + return "type" +} + +func NewMeow() interface{} { + _d := "MEOW" + return &Meow{Type: &_d} +} + +func (r Meow) Discriminator() string { + return "type" +} + +func NewPalace() interface{} { + _d := "Palace" + return &Palace{Type: &_d} +} + +func (r Palace) Discriminator() string { + return "type" +} + +func NewPurr() interface{} { + _d := "PURR" + return &Purr{Type: &_d} +} + +func (r Purr) Discriminator() string { + return "type" +} + +func NewShack() interface{} { + _d := "Shack" + return &Shack{Type: &_d} +} + +func (r Shack) Discriminator() string { + return "type" +} + +// RequestEditorFn is the function signature for the RequestEditor callback function +type RequestEditorFn func(req *http.Request, ctx context.Context) 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. + Server string + + // HTTP client with any customized settings, such as certificate chains. + Client http.Client + + // A callback for modifying requests which are generated before sending over + // the network. + RequestEditor RequestEditorFn +} + +// The interface specification for the client above. +type ClientInterface interface { + // PutOwner request with any body + PutOwnerWithBody(ctx context.Context, contentType string, body io.Reader) (*http.Response, error) + + // GetOwnerStatus request + GetOwnerStatus(ctx context.Context) (*http.Response, error) + + // TestOwnerStatus request + TestOwnerStatus(ctx context.Context) (*http.Response, error) +} + +func (c *Client) PutOwnerWithBody(ctx context.Context, contentType string, body io.Reader) (*http.Response, error) { + req, err := NewPutOwnerRequestWithBody(c.Server, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if c.RequestEditor != nil { + err = c.RequestEditor(req, ctx) + if err != nil { + return nil, err + } + } + return c.Client.Do(req) +} + +func (c *Client) GetOwnerStatus(ctx context.Context) (*http.Response, error) { + req, err := NewGetOwnerStatusRequest(c.Server) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if c.RequestEditor != nil { + err = c.RequestEditor(req, ctx) + if err != nil { + return nil, err + } + } + return c.Client.Do(req) +} + +func (c *Client) TestOwnerStatus(ctx context.Context) (*http.Response, error) { + req, err := NewTestOwnerStatusRequest(c.Server) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if c.RequestEditor != nil { + err = c.RequestEditor(req, ctx) + if err != nil { + return nil, err + } + } + return c.Client.Do(req) +} + +// NewPutOwnerRequestWithBody generates requests for PutOwner with any type of body +func NewPutOwnerRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { + var err error + + queryUrl := fmt.Sprintf("%s/owner", server) + + req, err := http.NewRequest("PUT", queryUrl, body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + return req, nil +} + +// NewGetOwnerStatusRequest generates requests for GetOwnerStatus +func NewGetOwnerStatusRequest(server string) (*http.Request, error) { + var err error + + queryUrl := fmt.Sprintf("%s/owner/pets", server) + + req, err := http.NewRequest("GET", queryUrl, nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewTestOwnerStatusRequest generates requests for TestOwnerStatus +func NewTestOwnerStatusRequest(server string) (*http.Request, error) { + var err error + + queryUrl := fmt.Sprintf("%s/owner/testStatus", server) + + req, err := http.NewRequest("GET", queryUrl, nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// ClientWithResponses builds on ClientInterface to offer response payloads +type ClientWithResponses struct { + ClientInterface +} + +// NewClientWithResponses returns a ClientWithResponses with a default Client: +func NewClientWithResponses(server string) *ClientWithResponses { + return &ClientWithResponses{ + ClientInterface: &Client{ + Client: http.Client{}, + Server: server, + }, + } +} + +// NewClientWithResponsesAndRequestEditorFunc takes in a RequestEditorFn callback function and returns a ClientWithResponses with a default Client: +func NewClientWithResponsesAndRequestEditorFunc(server string, reqEditorFn RequestEditorFn) *ClientWithResponses { + return &ClientWithResponses{ + ClientInterface: &Client{ + Client: http.Client{}, + Server: server, + RequestEditor: reqEditorFn, + }, + } +} + +type putOwnerResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r putOwnerResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r putOwnerResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type getOwnerStatusResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *PetOwnerStatus + XML200 *interface{} + YAML200 *interface{} + JSONDefault *Error +} + +// Status returns HTTPResponse.Status +func (r getOwnerStatusResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r getOwnerStatusResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type testOwnerStatusResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *interface{} +} + +// Status returns HTTPResponse.Status +func (r testOwnerStatusResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r testOwnerStatusResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +// PutOwnerWithBodyWithResponse request with arbitrary body returning *PutOwnerResponse +func (c *ClientWithResponses) PutOwnerWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader) (*putOwnerResponse, error) { + rsp, err := c.PutOwnerWithBody(ctx, contentType, body) + if err != nil { + return nil, err + } + return ParseputOwnerResponse(rsp) +} + +// GetOwnerStatusWithResponse request returning *GetOwnerStatusResponse +func (c *ClientWithResponses) GetOwnerStatusWithResponse(ctx context.Context) (*getOwnerStatusResponse, error) { + rsp, err := c.GetOwnerStatus(ctx) + if err != nil { + return nil, err + } + return ParsegetOwnerStatusResponse(rsp) +} + +// TestOwnerStatusWithResponse request returning *TestOwnerStatusResponse +func (c *ClientWithResponses) TestOwnerStatusWithResponse(ctx context.Context) (*testOwnerStatusResponse, error) { + rsp, err := c.TestOwnerStatus(ctx) + if err != nil { + return nil, err + } + return ParsetestOwnerStatusResponse(rsp) +} + +// ParseputOwnerResponse parses an HTTP response from a PutOwnerWithResponse call +func ParseputOwnerResponse(rsp *http.Response) (*putOwnerResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer rsp.Body.Close() + if err != nil { + return nil, err + } + + response := &putOwnerResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + } + + return response, nil +} + +// ParsegetOwnerStatusResponse parses an HTTP response from a GetOwnerStatusWithResponse call +func ParsegetOwnerStatusResponse(rsp *http.Response) (*getOwnerStatusResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer rsp.Body.Close() + if err != nil { + return nil, err + } + + response := &getOwnerStatusResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + response.JSON200 = &PetOwnerStatus{} + if _, err := decode.UnmarshalJSONInto(bodyBytes, response.JSON200, SchemaPathFactory); err != nil { + return nil, err + } + case strings.Contains(rsp.Header.Get("Content-Type"), "json"): + response.JSONDefault = &Error{} + if _, err := decode.UnmarshalJSONInto(bodyBytes, response.JSONDefault, SchemaPathFactory); err != nil { + return nil, err + } + } + + return response, nil +} + +// ParsetestOwnerStatusResponse parses an HTTP response from a TestOwnerStatusWithResponse call +func ParsetestOwnerStatusResponse(rsp *http.Response) (*testOwnerStatusResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer rsp.Body.Close() + if err != nil { + return nil, err + } + + response := &testOwnerStatusResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + res, err := decode.UnmarshalJSONInto(bodyBytes, &Dog{}, SchemaPathFactory) + if err != nil { + return nil, err + } + response.JSON200 = &res + } + + return response, nil +} + +// ServerInterface represents all server handlers. +type ServerInterface interface { + // create pet owners// (PUT /owner) + PutOwner(ctx echo.Context) error + // Get owner pets// (GET /owner/pets) + GetOwnerStatus(ctx echo.Context) error + // Test Owner Status as OneOf// (GET /owner/testStatus) + TestOwnerStatus(ctx echo.Context) error +} + +// ServerInterfaceWrapper converts echo contexts to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface +} + +// PutOwner converts echo context to params. +func (w *ServerInterfaceWrapper) PutOwner(ctx echo.Context) error { + var err error + + // Invoke the callback with all the unmarshalled arguments + err = w.Handler.PutOwner(ctx) + return err +} + +// GetOwnerStatus converts echo context to params. +func (w *ServerInterfaceWrapper) GetOwnerStatus(ctx echo.Context) error { + var err error + + // Invoke the callback with all the unmarshalled arguments + err = w.Handler.GetOwnerStatus(ctx) + return err +} + +// TestOwnerStatus converts echo context to params. +func (w *ServerInterfaceWrapper) TestOwnerStatus(ctx echo.Context) error { + var err error + + // Invoke the callback with all the unmarshalled arguments + err = w.Handler.TestOwnerStatus(ctx) + return err +} + +// RegisterHandlers adds each server route to the EchoRouter. +func RegisterHandlers(router runtime.EchoRouter, si ServerInterface) { + + wrapper := ServerInterfaceWrapper{ + Handler: si, + } + + router.PUT("/owner", wrapper.PutOwner) + router.GET("/owner/pets", wrapper.GetOwnerStatus) + router.GET("/owner/testStatus", wrapper.TestOwnerStatus) + +} + +// Base64 encoded, gzipped, json marshaled Swagger object +var swaggerSpec = []string{ + + "H4sIAAAAAAAC/+xYW2/iOBT+K9HZfcwWuvuwUt7awrTVMAXBVNWo4sGTHIinsZ2xHViE+O8r2ymXxiRh", + "imb3YZ5Aycm5fOf22WuIBcsFR64VRGtQcYqM2L9XcSwYEwnRVHDzIJciR6kp2tdxRpT9k1AVS8ooJ1rI", + "PbnVA2EIEehVjrAJQXAcziB6XsPvEmcQwW+dne1OabgzIhmJjXy92CQl8Uuj1J0oVLOuj8g5ZrCZbkLQ", + "VGdogrBeR6C0pHwOG/PKPRFfv2GsTUDXRL5UcXFia0BeMIie4fpq/BGm4VuFISxEVrB9W5RrnKP0G7sh", + "umprRhYTUfDk/Gn4hGLZCNyokNLBxoRI9oO+GgyHHyCED+P7/kNv8AVCmNx98cKgjgbASJ4boWgNg+Fj", + "r9bVEJ6uxg/HRG6lWGbG2M/CpEGo9Ge6TXSrertJETVJq2WAcSrMb23D2N8nqlNXMZvQfnaTEvYVZVXn", + "Ni2VhJ3gsbEwdNi29c6Kb1383xT4ryptm/OemFer6YXyg/lw+3jf69uh0B/d9cc9COHz8NT58C6Y7PA+", + "Nba+lMLTK7FI0NsqDJUi87baHd7VTsQFSqpXtc24BXY8fBp4cPTZc9uxYo8T5o9GCsGUb1+dhGG5bc9q", + "tmHX+tywbVLF+nuBzrlGpD/1h08tbZWcpmLtjmSZo1A4I0WmIfo79ER5FBktligPFVyG78vOCPVwyX0L", + "4bCO97QnYm4FqEaXp7q2M9NhZ5dISVblnBeSajx/nxve1DTorFNmFGR0geqen9+LdkT0lftO65Iulrw9", + "3Icc3gN8jnqwC/oEVXXFM9FEF+o929JkrX5ZloX082rDrsxKV6RmNJet8QOJ2I2T0eN43HKceMnScQL3", + "i7G0xrMJyvdwYXdirehmRKOkJDuY4qCpZeUeOnR8GbR1xTyifGZPDOVx13SughAWKJU97MPlRfeia1OY", + "Iyc5hQj+uuheXEIIOdGpdb0jtpuisIdTE5ct8PsEIvPQrZIQJH4vUOlrkawcX+Iauf2E5HlGY/vRH9+U", + "u2dw2WzqqO2msgElaIo8d1cVkFGlAzELZphRjkEskehCoipdoRITiLQs0PDLgjEiVxCBFcMgRx3YyJRF", + "z0XZydFdkMzRE+r8cPAZKyoXXLkU/9ntHo+682NRl5aMg/vK/mHZoS7CV+cdhG8Mrshbi2cfvdX0Too4", + "RqUs+XhtmTPh6xi+x+bri/2CuX2tlCB3/aOJoULP4Bpjulc+GpXerUVvERmRM1bRf0ajavJ1gN5nVDqw", + "AQcu4oCowN0WeJA0n6JcWL77PN38GwAA//9ZRzp4uBQAAA==", +} + +// GetSwagger returns the Swagger specification corresponding to the generated code +// in this file. +func GetSwagger() (*openapi3.Swagger, 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) + } + + swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(buf.Bytes()) + if err != nil { + return nil, fmt.Errorf("error loading Swagger: %s", err) + } + return swagger, nil +} diff --git a/pkg/codegen/testdata/pets.yaml b/pkg/codegen/testdata/pets.yaml new file mode 100644 index 000000000..7a2a0dc54 --- /dev/null +++ b/pkg/codegen/testdata/pets.yaml @@ -0,0 +1,343 @@ +openapi: 3.0.1 +info: + title: Pets + version: 1.0.0 +servers: [] +paths: + /owner: + put: + summary: create pet owners + operationId: putOwner + requestBody: + description: list of feline creatures + required: true + content: + application-json: + schema: + $ref: '#/components/schemas/PetOwner' + + + /owner/testStatus: + get: + tags: + - owner + summary: Test Owner Status as OneOf + operationId: testOwnerStatus + responses: + 200: + description: Success + content: + application/json: + schema: +# $ref: '#/components/schemas/PetOwnerStatus' + discriminator: + propertyName: "type" + oneOf: + - $ref: '#/components/schemas/Cat' + - $ref: '#/components/schemas/Dog' + + /owner/pets: + get: + tags: + - owner + summary: Get owner pets + operationId: getOwnerStatus + responses: + 200: + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/PetOwnerStatus' +# discriminator: +# propertyName: "type" +# oneOf: +# - $ref: '#/components/schemas/Cat' +# - $ref: '#/components/schemas/Dog' + application/xml: + schema: + anyOf: + - $ref: '#/components/schemas/Cat' + - $ref: '#/components/schemas/Dog' + application/yaml: + schema: + oneOf: + - $ref: '#/components/schemas/Cat' + - $ref: '#/components/schemas/Dog' + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + +components: + schemas: + PetOwnerStatus: + discriminator: + propertyName: "type" + mapping: + LOUD: '#/components/schemas/Cat' + WARN: '#/components/schemas/Dog' + oneOf: + - $ref: '#/components/schemas/Cat' + - $ref: '#/components/schemas/Dog' + + + PetOwner: + type: object + properties: + name: + type: string + age: + type: integer + default: 7 + favorite: + oneOf: + - $ref: '#/components/schemas/Cat' + - $ref: '#/components/schemas/Dog' + discriminator: + propertyName: type + + + dogs: + type: array + default: [] + items: + $ref: '#/components/schemas/Dog' + + livesIn: + oneOf: + - $ref: '#/components/schemas/House' + - $ref: '#/components/schemas/Palace' + discriminator: + propertyName: type + + petLivesIn: + $ref: '#/components/schemas/Accommodation' + + owns: + type: array + items: + $ref: '#/components/schemas/Accommodation' + + Cheetah: + type: object + properties: + type: + type: string + default: black + + # refer to schema that has a oneOf + sound: + oneOf: + - $ref: '#/components/schemas/Meow' + - $ref: '#/components/schemas/Purr' + - $ref: '#/components/schemas/Growl' + discriminator: + propertyName: type + mapping: + LOUD: '#/components/schemas/Meow' + WARN: '#/components/schemas/Growl' + + # refer to schema that has the same property name as the oneOf above + echo: + $ref: '#/components/schemas/SchemaWithSound' + + # refer to schema that is a oneOf and has the same property name as the oneOf above + echoOneOf: + $ref: '#/components/schemas/SchemaWithOneOfSound' + + echoChamber: + type: object + properties: + type: + type: string + sound: + type: string + + favSound: + oneOf: + - $ref: '#/components/schemas/Meow' + - $ref: '#/components/schemas/Purr' + discriminator: + propertyName: type + + SchemaWithSound: + type: object + properties: + type: + type: string + sound: + type: string + + SchemaWithOneOfSound: + type: object + properties: + type: + type: string + sound: + oneOf: + - $ref: '#/components/schemas/Meow' + - $ref: '#/components/schemas/Purr' + - $ref: '#/components/schemas/Growl' + discriminator: + propertyName: type + mapping: + LOUD: '#/components/schemas/Meow' + WARN: '#/components/schemas/Growl' + + + + Dog: + type: object + properties: + type: + type: string + + kind: + type: string + enum: [GUIDE,SHEPHERD,TOY] + + sound: + oneOf: + - $ref: '#/components/schemas/Bark' + discriminator: + propertyName: type + + Cat: + type: object + properties: + type: + type: string + + mood: + type: string + enum: [ALOOF, FRIENDLY, SHY] + + sound: + oneOf: + - $ref: '#/components/schemas/Meow' + - $ref: '#/components/schemas/Purr' + - $ref: '#/components/schemas/Growl' + discriminator: + propertyName: type + mapping: + LOUD: '#/components/schemas/Meow' + WARN: '#/components/schemas/Growl' + + favSound: + oneOf: + - $ref: '#/components/schemas/Meow' + - $ref: '#/components/schemas/Purr' + discriminator: + propertyName: type + + Bark: + type: object + properties: + type: + type: string + enum: [BARK] + volume: + type: integer + + Meow: + type: object + properties: + type: + type: string + enum: [MEOW] + squeel: + type: string + + Purr: + type: object + properties: + type: + type: string + enum: [PURR] + heritage: + $ref: '#/components/schemas/Accommodation' + + Growl: + type: object + properties: + type: + type: string + enum: [GROWL] + severity: + type: string + + Accommodation: + type: object + properties: + title: + type: string + class: + oneOf: + - $ref: '#/components/schemas/Palace' + - $ref: '#/components/schemas/Shack' + - $ref: '#/components/schemas/House' + - $ref: '#/components/schemas/Kennel' + discriminator: + propertyName: type + + + Kennel: + type: object + properties: + type: + type: string + enum: [BARK] + name: + type: string + rooms: + type: integer + + + House: + type: object + properties: + type: + type: string + name: + type: string + rooms: + type: integer + + + Shack: + type: object + properties: + type: + type: string + name: + type: string + material: + type: string + default: timber + + + Palace: + type: object + properties: + type: + type: string + name: + type: string + Halls: + type: integer + default: 7 + towers: + type: integer + default: 1 + + Error: + type: object + properties: + code: + type: string + message: + type: string + diff --git a/pkg/codegen/testdata/testOpenAPIDefinition.golden b/pkg/codegen/testdata/testOpenAPIDefinition.golden new file mode 100644 index 000000000..3c2fa1e4d --- /dev/null +++ b/pkg/codegen/testdata/testOpenAPIDefinition.golden @@ -0,0 +1,399 @@ +// Package testswagger provides primitives to interact the openapi HTTP API. +// +// Code generated by github.com/weberr13/oapi-codegen DO NOT EDIT. +package testswagger + +import ( + "bytes" + "compress/gzip" + "context" + "encoding/base64" + "encoding/json" + "encoding/xml" + "fmt" + "github.com/deepmap/oapi-codegen/pkg/runtime" + "github.com/getkin/kin-openapi/openapi3" + "github.com/labstack/echo/v4" + "gopkg.in/yaml.v2" + "io/ioutil" + "net/http" + "strings" + "time" +) + +// CatAlive defines model for CatAlive. +type CatAlive struct { + AliveSince *time.Time `json:"alive_since,omitempty"` + Name *string `json:"name,omitempty"` +} + +// CatDead defines model for CatDead. +type CatDead struct { + Cause *string `json:"cause,omitempty"` + DeadSince *time.Time `json:"dead_since,omitempty"` + Name *string `json:"name,omitempty"` +} + +// Error defines model for Error. +type Error struct { + Code *int32 `json:"code,omitempty"` + Message *string `json:"message,omitempty"` +} + +// Test defines model for Test. +type Test struct { + Cases *[]TestCase `json:"cases,omitempty"` + Name *string `json:"name,omitempty"` +} + +// TestCase defines model for TestCase. +type TestCase struct { + Command *string `json:"command,omitempty"` + Name *string `json:"name,omitempty"` +} + +// RequestEditorFn is the function signature for the RequestEditor callback function +type RequestEditorFn func(req *http.Request, ctx context.Context) 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. + Server string + + // HTTP client with any customized settings, such as certificate chains. + Client http.Client + + // A callback for modifying requests which are generated before sending over + // the network. + RequestEditor RequestEditorFn +} + +// The interface specification for the client above. +type ClientInterface interface { + // GetCatStatus request + GetCatStatus(ctx context.Context) (*http.Response, error) + + // GetTestByName request + GetTestByName(ctx context.Context, name string) (*http.Response, error) +} + +func (c *Client) GetCatStatus(ctx context.Context) (*http.Response, error) { + req, err := NewGetCatStatusRequest(c.Server) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if c.RequestEditor != nil { + err = c.RequestEditor(req, ctx) + if err != nil { + return nil, err + } + } + return c.Client.Do(req) +} + +func (c *Client) GetTestByName(ctx context.Context, name string) (*http.Response, error) { + req, err := NewGetTestByNameRequest(c.Server, name) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if c.RequestEditor != nil { + err = c.RequestEditor(req, ctx) + if err != nil { + return nil, err + } + } + return c.Client.Do(req) +} + +// NewGetCatStatusRequest generates requests for GetCatStatus +func NewGetCatStatusRequest(server string) (*http.Request, error) { + var err error + + queryUrl := fmt.Sprintf("%s/cat", server) + + req, err := http.NewRequest("GET", queryUrl, nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetTestByNameRequest generates requests for GetTestByName +func NewGetTestByNameRequest(server string, name string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParam("simple", false, "name", name) + if err != nil { + return nil, err + } + + queryUrl := fmt.Sprintf("%s/test/%s", server, pathParam0) + + req, err := http.NewRequest("GET", queryUrl, nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// ClientWithResponses builds on ClientInterface to offer response payloads +type ClientWithResponses struct { + ClientInterface +} + +// NewClientWithResponses returns a ClientWithResponses with a default Client: +func NewClientWithResponses(server string) *ClientWithResponses { + return &ClientWithResponses{ + ClientInterface: &Client{ + Client: http.Client{}, + Server: server, + }, + } +} + +// NewClientWithResponsesAndRequestEditorFunc takes in a RequestEditorFn callback function and returns a ClientWithResponses with a default Client: +func NewClientWithResponsesAndRequestEditorFunc(server string, reqEditorFn RequestEditorFn) *ClientWithResponses { + return &ClientWithResponses{ + ClientInterface: &Client{ + Client: http.Client{}, + Server: server, + RequestEditor: reqEditorFn, + }, + } +} + +type getCatStatusResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *interface{} + XML200 *interface{} + YAML200 *struct { + // Embedded struct due to allOf(#/components/schemas/CatAlive) + CatAlive + // Embedded struct due to allOf(#/components/schemas/CatDead) + CatDead + } + JSONDefault *Error +} + +// Status returns HTTPResponse.Status +func (r getCatStatusResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r getCatStatusResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type getTestByNameResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *[]Test + XML200 *[]Test + JSONDefault *Error +} + +// Status returns HTTPResponse.Status +func (r getTestByNameResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r getTestByNameResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +// GetCatStatusWithResponse request returning *GetCatStatusResponse +func (c *ClientWithResponses) GetCatStatusWithResponse(ctx context.Context) (*getCatStatusResponse, error) { + rsp, err := c.GetCatStatus(ctx) + if err != nil { + return nil, err + } + return ParsegetCatStatusResponse(rsp) +} + +// GetTestByNameWithResponse request returning *GetTestByNameResponse +func (c *ClientWithResponses) GetTestByNameWithResponse(ctx context.Context, name string) (*getTestByNameResponse, error) { + rsp, err := c.GetTestByName(ctx, name) + if err != nil { + return nil, err + } + return ParsegetTestByNameResponse(rsp) +} + +// ParsegetCatStatusResponse parses an HTTP response from a GetCatStatusWithResponse call +func ParsegetCatStatusResponse(rsp *http.Response) (*getCatStatusResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer rsp.Body.Close() + if err != nil { + return nil, err + } + + response := &getCatStatusResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "yaml") && rsp.StatusCode == 200: + response.YAML200 = &struct { + // Embedded struct due to allOf(#/components/schemas/CatAlive) + CatAlive + // Embedded struct due to allOf(#/components/schemas/CatDead) + CatDead + }{} + if err := yaml.Unmarshal(bodyBytes, response.YAML200); err != nil { + return nil, err + } + case strings.Contains(rsp.Header.Get("Content-Type"), "json"): + response.JSONDefault = &Error{} + if err := json.Unmarshal(bodyBytes, response.JSONDefault); err != nil { + return nil, err + } + } + + return response, nil +} + +// ParsegetTestByNameResponse parses an HTTP response from a GetTestByNameWithResponse call +func ParsegetTestByNameResponse(rsp *http.Response) (*getTestByNameResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer rsp.Body.Close() + if err != nil { + return nil, err + } + + response := &getTestByNameResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + response.JSON200 = &[]Test{} + if err := json.Unmarshal(bodyBytes, response.JSON200); err != nil { + return nil, err + } + case strings.Contains(rsp.Header.Get("Content-Type"), "xml") && rsp.StatusCode == 200: + response.XML200 = &[]Test{} + if err := xml.Unmarshal(bodyBytes, response.XML200); err != nil { + return nil, err + } + case strings.Contains(rsp.Header.Get("Content-Type"), "json"): + response.JSONDefault = &Error{} + if err := json.Unmarshal(bodyBytes, response.JSONDefault); err != nil { + return nil, err + } + } + + return response, nil +} + +// ServerInterface represents all server handlers. +type ServerInterface interface { + // Get cat status// (GET /cat) + GetCatStatus(ctx echo.Context) error + // Get test// (GET /test/{name}) + GetTestByName(ctx echo.Context, name string) error +} + +// ServerInterfaceWrapper converts echo contexts to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface +} + +// GetCatStatus converts echo context to params. +func (w *ServerInterfaceWrapper) GetCatStatus(ctx echo.Context) error { + var err error + + // Invoke the callback with all the unmarshalled arguments + err = w.Handler.GetCatStatus(ctx) + return err +} + +// GetTestByName converts echo context to params. +func (w *ServerInterfaceWrapper) GetTestByName(ctx echo.Context) error { + var err error + // ------------- Path parameter "name" ------------- + var name string + + err = runtime.BindStyledParameter("simple", false, "name", ctx.Param("name"), &name) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter name: %s", err)) + } + + // Invoke the callback with all the unmarshalled arguments + err = w.Handler.GetTestByName(ctx, name) + return err +} + +// RegisterHandlers adds each server route to the EchoRouter. +func RegisterHandlers(router runtime.EchoRouter, si ServerInterface) { + + wrapper := ServerInterfaceWrapper{ + Handler: si, + } + + router.GET("/cat", wrapper.GetCatStatus) + router.GET("/test/:name", wrapper.GetTestByName) + +} + +// Base64 encoded, gzipped, json marshaled Swagger object +var swaggerSpec = []string{ + + "H4sIAAAAAAAC/8xVyW7bMBD9FWHao2I5yY231C2CXJoCyS0wigE5llmISzkjo0agfy9I2VkFu0XaoifR", + "XN6b5b3xPejgYvDkhUHdA+s1OSzLBcpFZzeU1zGFSEkslRPM21/Zel0OVyE5FFBgUOhErCOoQbaRQAFL", + "sr6FoQaPrtx+cTAMdWb6SGheE2nsuTwi3ztQd6AxQQ0mtFBD6Ay2BMsJLkNo/mB8n1IKaSK6YJ7jWy/n", + "Z4/Y1gu1lDK4I+Yc7DT+LbFMJc/jwgq5snifaAUK3jWPPWt2DWsyxgKZMtuOAlPC7ZHUHp5NZOccejPx", + "7gBghrR+FfKhIdbJRrHBg4LbteXKcoWVEEt1HclffLmqbiLpXDErXUbabZ8sgqFL8lWpTA0bSjzCnM7m", + "s3kOIUTyGC0oOJ/NZ6dQQ0RZl8gbjaWcLZVPTgpzFFcGVN5coNwISs9QQyKOwe8KfTafj5l7IV/eYoyd", + "1eV1841zBHuLFGRP1ytQd4c78+CjoT56sdhgWOYyPqX+4brnzOi3/4Z5i6+ou+5vURfnPhXNTa81MY+W", + "XmHfyW/15xDv6OkJzv1BDdw7h2kLCi5JKo1S8V42gi2P80ig1KzJqm7uszGGQ9rLgv6w/YxlBkVM6Ego", + "camnzfRZxbB32PjJKv3e20QGlKSe6icpvnTg8o2S/uVZ83rOHNPsW6D/a2XIOKT2mig/RzUzpc2+u33q", + "QMFaJLJqilxmAaM9yf8iLfmZDq7ZnBW/PF49eHM5/AwAAP//A0Q9R74HAAA=", +} + +// GetSwagger returns the Swagger specification corresponding to the generated code +// in this file. +func GetSwagger() (*openapi3.Swagger, 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) + } + + swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(buf.Bytes()) + if err != nil { + return nil, fmt.Errorf("error loading Swagger: %s", err) + } + return swagger, nil +} diff --git a/pkg/codegen/testdata/testOpenAPIDefinition.yaml b/pkg/codegen/testdata/testOpenAPIDefinition.yaml new file mode 100644 index 000000000..bf46cd37e --- /dev/null +++ b/pkg/codegen/testdata/testOpenAPIDefinition.yaml @@ -0,0 +1,122 @@ +openapi: 3.0.1 + +info: + title: OpenAPI-CodeGen Test + description: 'This is a test OpenAPI Spec' + version: 1.0.0 + +servers: +- url: https://test.oapi-codegen.com/v2 +- url: http://test.oapi-codegen.com/v2 + +paths: + /test/{name}: + get: + tags: + - test + summary: Get test + operationId: getTestByName + parameters: + - name: name + in: path + required: true + schema: + type: string + responses: + 200: + description: Success + content: + application/xml: + schema: + type: array + items: + $ref: '#/components/schemas/Test' + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Test' + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /cat: + + get: + tags: + - cat + summary: Get cat status + operationId: getCatStatus + responses: + 200: + description: Success + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/CatAlive' + - $ref: '#/components/schemas/CatDead' + application/xml: + schema: + anyOf: + - $ref: '#/components/schemas/CatAlive' + - $ref: '#/components/schemas/CatDead' + application/yaml: + schema: + allOf: + - $ref: '#/components/schemas/CatAlive' + - $ref: '#/components/schemas/CatDead' + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + +components: + schemas: + + Test: + properties: + name: + type: string + cases: + type: array + items: + $ref: '#/components/schemas/TestCase' + + TestCase: + properties: + name: + type: string + command: + type: string + + Error: + properties: + code: + type: integer + format: int32 + message: + type: string + + CatAlive: + properties: + name: + type: string + alive_since: + type: string + format: date-time + + CatDead: + properties: + name: + type: string + dead_since: + type: string + format: date-time + cause: + type: string + enum: [car, dog, oldage] diff --git a/pkg/codegen/testdata/testOpenAPIDefinitionWithOneOfDiscriminatorsAndEnums.golden b/pkg/codegen/testdata/testOpenAPIDefinitionWithOneOfDiscriminatorsAndEnums.golden new file mode 100644 index 000000000..4e3f02d7c --- /dev/null +++ b/pkg/codegen/testdata/testOpenAPIDefinitionWithOneOfDiscriminatorsAndEnums.golden @@ -0,0 +1,627 @@ +// Package testswagger provides primitives to interact the openapi HTTP API. +// +// Code generated by github.com/weberr13/oapi-codegen DO NOT EDIT. +package testswagger + +import ( + "bytes" + "compress/gzip" + "context" + "encoding/base64" + "encoding/xml" + "fmt" + "github.com/deepmap/oapi-codegen/pkg/runtime" + "github.com/getkin/kin-openapi/openapi3" + "github.com/labstack/echo/v4" + "github.com/weberr13/go-decode/decode" + "gopkg.in/yaml.v2" + "io" + "io/ioutil" + "net/http" + "strings" + "time" +) + +// CatAlive defines model for CatAlive. +type CatAlive struct { + AliveSince *time.Time `json:"alive_since,omitempty"` + Name *string `json:"name,omitempty"` + Type *string `json:"type,omitempty"` +} + +// CatBreed defines model for CatBreed. +type CatBreed interface{} + +// CatDead defines model for CatDead. +type CatDead struct { + Cause *string `json:"cause,omitempty"` + DeadSince *time.Time `json:"dead_since,omitempty"` + Name *string `json:"name,omitempty"` + Type *string `json:"type,omitempty"` +} + +// Cats defines model for Cats. +type Cats struct { + Box interface{} `json:"box,omitempty"` + Breed CatBreed `json:"breed,omitempty"` +} + +// Error defines model for Error. +type Error struct { + Code *int32 `json:"code,omitempty"` + Message *string `json:"message,omitempty"` +} + +// MixedBreed defines model for MixedBreed. +type MixedBreed struct { + FurColor *string `json:"furColor,omitempty"` + FurLength *string `json:"furLength,omitempty"` + Type *string `json:"type,omitempty"` +} + +// Purebred defines model for Purebred. +type Purebred struct { + Breed *string `json:"breed,omitempty"` + Breeder *string `json:"breeder,omitempty"` + Type *string `json:"type,omitempty"` +} + +// Test defines model for Test. +type Test struct { + Cases *[]TestCase `json:"cases,omitempty"` + Name *string `json:"name,omitempty"` +} + +// TestCase defines model for TestCase. +type TestCase struct { + Command *string `json:"command,omitempty"` + Name *string `json:"name,omitempty"` +} + +func factory(fm map[string]func() interface{}, path, dk string, o map[string]interface{}) (interface{}, error) { + var dp interface{} + var dv string + var ok bool + + if dp, ok = o[dk]; !ok { + return nil, fmt.Errorf("expecting OneOf object at path '%s' to to have a discriminator property '%s'", path, dk) + } + + if dv, ok = dp.(string); !ok { + return nil, fmt.Errorf("expecting OneOf field '%s's' discriminator property '%s' value to be a string", path, dk) + } + + f, ok := fm[dv] + if !ok { + return nil, fmt.Errorf("Unknown discriminator value '%s' when handling OneOf field '%s'", path, dv) + } + return f(), nil +} + +// Factory method for objects at path Cats.box +func Cats_box_Factory(o map[string]interface{}) (interface{}, error) { + fm := map[string]func() interface{}{ + "cat_alive": NewCatAlive, + "cat_dead": NewCatDead, + } + return factory(fm, "Cats.box", "type", o) +} + +// Factory method for objects at path Cats.breed +func Cats_breed_Factory(o map[string]interface{}) (interface{}, error) { + fm := map[string]func() interface{}{ + "mixed_breed": NewMixedBreed, + "pure_breed": NewPurebred, + } + return factory(fm, "Cats.breed", "type", o) +} + +func SchemaPathFactory(path string) (func(map[string]interface{}) (interface{}, error), error) { + // Map StringPath => Factory + pathFactoryMap := map[string]func(map[string]interface{}) (interface{}, error){ + "Cats.box": Cats_box_Factory, + "Cats.breed": Cats_breed_Factory, + } + + return pathFactoryMap[path], nil +} + +func TypeFactory(kind string) (interface{}, error) { + // Map StringPath => Factory + var factoryMap = map[string]func() interface{}{ + "cat_alive": NewCatAlive, + "cat_dead": NewCatDead, + "mixed_breed": NewMixedBreed, + "pure_breed": NewPurebred, + } + f, ok := factoryMap[kind] + if !ok { + return nil, fmt.Errorf("cannot find type %s", kind) + } + return f(), nil +} + +func NewCatAlive() interface{} { + _d := "cat_alive" + return &CatAlive{Type: &_d} +} + +func (r CatAlive) Discriminator() string { + return "type" +} + +func NewCatDead() interface{} { + _d := "cat_dead" + return &CatDead{Type: &_d} +} + +func (r CatDead) Discriminator() string { + return "type" +} + +func NewMixedBreed() interface{} { + _d := "mixed_breed" + return &MixedBreed{Type: &_d} +} + +func (r MixedBreed) Discriminator() string { + return "type" +} + +func NewPurebred() interface{} { + _d := "pure_breed" + return &Purebred{Type: &_d} +} + +func (r Purebred) Discriminator() string { + return "type" +} + +// RequestEditorFn is the function signature for the RequestEditor callback function +type RequestEditorFn func(req *http.Request, ctx context.Context) 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. + Server string + + // HTTP client with any customized settings, such as certificate chains. + Client http.Client + + // A callback for modifying requests which are generated before sending over + // the network. + RequestEditor RequestEditorFn +} + +// The interface specification for the client above. +type ClientInterface interface { + // GetCatStatus request + GetCatStatus(ctx context.Context) (*http.Response, error) + + // PutCats request with any body + PutCatsWithBody(ctx context.Context, contentType string, body io.Reader) (*http.Response, error) + + // GetTestByName request + GetTestByName(ctx context.Context, name string) (*http.Response, error) +} + +func (c *Client) GetCatStatus(ctx context.Context) (*http.Response, error) { + req, err := NewGetCatStatusRequest(c.Server) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if c.RequestEditor != nil { + err = c.RequestEditor(req, ctx) + if err != nil { + return nil, err + } + } + return c.Client.Do(req) +} + +func (c *Client) PutCatsWithBody(ctx context.Context, contentType string, body io.Reader) (*http.Response, error) { + req, err := NewPutCatsRequestWithBody(c.Server, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if c.RequestEditor != nil { + err = c.RequestEditor(req, ctx) + if err != nil { + return nil, err + } + } + return c.Client.Do(req) +} + +func (c *Client) GetTestByName(ctx context.Context, name string) (*http.Response, error) { + req, err := NewGetTestByNameRequest(c.Server, name) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if c.RequestEditor != nil { + err = c.RequestEditor(req, ctx) + if err != nil { + return nil, err + } + } + return c.Client.Do(req) +} + +// NewGetCatStatusRequest generates requests for GetCatStatus +func NewGetCatStatusRequest(server string) (*http.Request, error) { + var err error + + queryUrl := fmt.Sprintf("%s/cat", server) + + req, err := http.NewRequest("GET", queryUrl, nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewPutCatsRequestWithBody generates requests for PutCats with any type of body +func NewPutCatsRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { + var err error + + queryUrl := fmt.Sprintf("%s/cat", server) + + req, err := http.NewRequest("PUT", queryUrl, body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + return req, nil +} + +// NewGetTestByNameRequest generates requests for GetTestByName +func NewGetTestByNameRequest(server string, name string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParam("simple", false, "name", name) + if err != nil { + return nil, err + } + + queryUrl := fmt.Sprintf("%s/test/%s", server, pathParam0) + + req, err := http.NewRequest("GET", queryUrl, nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// ClientWithResponses builds on ClientInterface to offer response payloads +type ClientWithResponses struct { + ClientInterface +} + +// NewClientWithResponses returns a ClientWithResponses with a default Client: +func NewClientWithResponses(server string) *ClientWithResponses { + return &ClientWithResponses{ + ClientInterface: &Client{ + Client: http.Client{}, + Server: server, + }, + } +} + +// NewClientWithResponsesAndRequestEditorFunc takes in a RequestEditorFn callback function and returns a ClientWithResponses with a default Client: +func NewClientWithResponsesAndRequestEditorFunc(server string, reqEditorFn RequestEditorFn) *ClientWithResponses { + return &ClientWithResponses{ + ClientInterface: &Client{ + Client: http.Client{}, + Server: server, + RequestEditor: reqEditorFn, + }, + } +} + +type getCatStatusResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *interface{} + XML200 *interface{} + YAML200 *struct { + // Embedded struct due to allOf(#/components/schemas/CatAlive) + CatAlive + // Embedded struct due to allOf(#/components/schemas/CatDead) + CatDead + } + JSONDefault *Error +} + +// Status returns HTTPResponse.Status +func (r getCatStatusResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r getCatStatusResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type putCatsResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r putCatsResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r putCatsResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type getTestByNameResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *[]Test + XML200 *[]Test + JSONDefault *Error +} + +// Status returns HTTPResponse.Status +func (r getTestByNameResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r getTestByNameResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +// GetCatStatusWithResponse request returning *GetCatStatusResponse +func (c *ClientWithResponses) GetCatStatusWithResponse(ctx context.Context) (*getCatStatusResponse, error) { + rsp, err := c.GetCatStatus(ctx) + if err != nil { + return nil, err + } + return ParsegetCatStatusResponse(rsp) +} + +// PutCatsWithBodyWithResponse request with arbitrary body returning *PutCatsResponse +func (c *ClientWithResponses) PutCatsWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader) (*putCatsResponse, error) { + rsp, err := c.PutCatsWithBody(ctx, contentType, body) + if err != nil { + return nil, err + } + return ParseputCatsResponse(rsp) +} + +// GetTestByNameWithResponse request returning *GetTestByNameResponse +func (c *ClientWithResponses) GetTestByNameWithResponse(ctx context.Context, name string) (*getTestByNameResponse, error) { + rsp, err := c.GetTestByName(ctx, name) + if err != nil { + return nil, err + } + return ParsegetTestByNameResponse(rsp) +} + +// ParsegetCatStatusResponse parses an HTTP response from a GetCatStatusWithResponse call +func ParsegetCatStatusResponse(rsp *http.Response) (*getCatStatusResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer rsp.Body.Close() + if err != nil { + return nil, err + } + + response := &getCatStatusResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + res, err := decode.UnmarshalJSONInto(bodyBytes, &CatDead{}, SchemaPathFactory) + if err != nil { + return nil, err + } + response.JSON200 = &res + case strings.Contains(rsp.Header.Get("Content-Type"), "yaml") && rsp.StatusCode == 200: + response.YAML200 = &struct { + // Embedded struct due to allOf(#/components/schemas/CatAlive) + CatAlive + // Embedded struct due to allOf(#/components/schemas/CatDead) + CatDead + }{} + if err := yaml.Unmarshal(bodyBytes, response.YAML200); err != nil { + return nil, err + } + case strings.Contains(rsp.Header.Get("Content-Type"), "json"): + response.JSONDefault = &Error{} + if _, err := decode.UnmarshalJSONInto(bodyBytes, response.JSONDefault, SchemaPathFactory); err != nil { + return nil, err + } + } + + return response, nil +} + +// ParseputCatsResponse parses an HTTP response from a PutCatsWithResponse call +func ParseputCatsResponse(rsp *http.Response) (*putCatsResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer rsp.Body.Close() + if err != nil { + return nil, err + } + + response := &putCatsResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + } + + return response, nil +} + +// ParsegetTestByNameResponse parses an HTTP response from a GetTestByNameWithResponse call +func ParsegetTestByNameResponse(rsp *http.Response) (*getTestByNameResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer rsp.Body.Close() + if err != nil { + return nil, err + } + + response := &getTestByNameResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + response.JSON200 = &[]Test{} + if _, err := decode.UnmarshalJSONInto(bodyBytes, response.JSON200, SchemaPathFactory); err != nil { + return nil, err + } + case strings.Contains(rsp.Header.Get("Content-Type"), "xml") && rsp.StatusCode == 200: + response.XML200 = &[]Test{} + if err := xml.Unmarshal(bodyBytes, response.XML200); err != nil { + return nil, err + } + case strings.Contains(rsp.Header.Get("Content-Type"), "json"): + response.JSONDefault = &Error{} + if _, err := decode.UnmarshalJSONInto(bodyBytes, response.JSONDefault, SchemaPathFactory); err != nil { + return nil, err + } + } + + return response, nil +} + +// ServerInterface represents all server handlers. +type ServerInterface interface { + // Get cat status// (GET /cat) + GetCatStatus(ctx echo.Context) error + // deposit cats// (PUT /cat) + PutCats(ctx echo.Context) error + // Get test// (GET /test/{name}) + GetTestByName(ctx echo.Context, name string) error +} + +// ServerInterfaceWrapper converts echo contexts to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface +} + +// GetCatStatus converts echo context to params. +func (w *ServerInterfaceWrapper) GetCatStatus(ctx echo.Context) error { + var err error + + // Invoke the callback with all the unmarshalled arguments + err = w.Handler.GetCatStatus(ctx) + return err +} + +// PutCats converts echo context to params. +func (w *ServerInterfaceWrapper) PutCats(ctx echo.Context) error { + var err error + + // Invoke the callback with all the unmarshalled arguments + err = w.Handler.PutCats(ctx) + return err +} + +// GetTestByName converts echo context to params. +func (w *ServerInterfaceWrapper) GetTestByName(ctx echo.Context) error { + var err error + // ------------- Path parameter "name" ------------- + var name string + + err = runtime.BindStyledParameter("simple", false, "name", ctx.Param("name"), &name) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter name: %s", err)) + } + + // Invoke the callback with all the unmarshalled arguments + err = w.Handler.GetTestByName(ctx, name) + return err +} + +// RegisterHandlers adds each server route to the EchoRouter. +func RegisterHandlers(router runtime.EchoRouter, si ServerInterface) { + + wrapper := ServerInterfaceWrapper{ + Handler: si, + } + + router.GET("/cat", wrapper.GetCatStatus) + router.PUT("/cat", wrapper.PutCats) + router.GET("/test/:name", wrapper.GetTestByName) + +} + +// Base64 encoded, gzipped, json marshaled Swagger object +var swaggerSpec = []string{ + + "H4sIAAAAAAAC/8xWTW/bRhD9K8S0R1pUnBtvsVoEAdomgHMLDGNMDqkNuB/dmRUsCPzvxS7FSDJpyUGa", + "wCfR+zHzZt57s95BZbWzhowwlDvgak0a0+cK5V2nNhS/nbeOvChKOxiX71mZKm021msUKKFGoStRmiAH", + "2TqCEli8Mi30ORjU6fRkY1jYAZmgofwCFcp9ygB3kzB9n0dcN56ojndqxZVXWhkU64+Abv9J2YbrfQ7W", + "0McGyi87+N1TAyX8VhzqLvZFF5+CpwdPNfT5+YN/q0eqBxD9AaR9+EqVwADxD8J62rkKAz8p1kMOtW0h", + "B9vV2M5VnUNNWP/UhscEz/ebp5U82Mf/n4BvkrtEwNjg/q7P4WFUw4Ube8L6GcL+9P4E/kiXrU8broy8", + "vT40WxmhlnyMoIk5sjdteEx4JJhJkib4le2G9BOumuD/ItPK+kVM6pjmfujHPJnfJD4ldEQ3yZJ2yL8I", + "gQuezgL4TCxzvuDhQwlpvsRljLFCpgMAQO9xe0b1Y+p0bYZnrdHMV/9swBhSmcYmG1C0gRNlDZTwea04", + "U5xhJsSSfXRk3n36kN06qqJ2lHQx0n75amVrek8mS53JYUOehzBvFsvFMpnHkUGnoIS3i+XiDeTgUNYJ", + "eVFhamdL6ScWhRHFhxrKuLhCuRWUwJCDJ3bW7Bt9vVwOlRshk+6ic52q0u3iK0cE43PwOoze5ycQH3V3", + "ihDN9tdk3uIkddf9rNRp+B+L6zZUFTEPr0KDoZPv4vFc3mEKzuQcN3LgoDX6LZTwniSrUDIe5SXY8v45", + "gTiWXZiRpAuS3pOoxn8DsdzYevt8AVffV0AKPYO/UyyZbbKGOmUoqzyhBE8jDJUGovhAJxXW5CyrVCWn", + "4oto52IXJ0J/znTRyTeDMaJVPWoS8pwEoiKeaF8YR8vw8xRJflTy09Fz94NefvGQnQ7YSyb8kdCvWuoy", + "TOdR5OnPwZ5MfjOyG3wHJaxFHJdFksvColNX8R+JlsyisrrYXKcBcDh69uRd/18AAAD//3dwHcOjCwAA", +} + +// GetSwagger returns the Swagger specification corresponding to the generated code +// in this file. +func GetSwagger() (*openapi3.Swagger, 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) + } + + swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(buf.Bytes()) + if err != nil { + return nil, fmt.Errorf("error loading Swagger: %s", err) + } + return swagger, nil +} diff --git a/pkg/codegen/testdata/testOpenAPIDefinitionWithOneOfDiscriminatorsAndEnums.yaml b/pkg/codegen/testdata/testOpenAPIDefinitionWithOneOfDiscriminatorsAndEnums.yaml new file mode 100644 index 000000000..94c8c9cf7 --- /dev/null +++ b/pkg/codegen/testdata/testOpenAPIDefinitionWithOneOfDiscriminatorsAndEnums.yaml @@ -0,0 +1,184 @@ +openapi: 3.0.1 + +info: + title: OpenAPI-CodeGen Test + description: 'This is a test OpenAPI Spec' + version: 1.0.0 + +servers: +- url: https://test.oapi-codegen.com/v2 +- url: http://test.oapi-codegen.com/v2 + +paths: + /test/{name}: + get: + tags: + - test + summary: Get test + operationId: getTestByName + parameters: + - name: name + in: path + required: true + schema: + type: string + responses: + 200: + description: Success + content: + application/xml: + schema: + type: array + items: + $ref: '#/components/schemas/Test' + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Test' + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /cat: + put: + summary: deposit cats + operationId: putCats + requestBody: + description: list of feline creatures + required: true + content: + application-json: + schema: + $ref: '#/components/schemas/Cats' + + get: + tags: + - cat + summary: Get cat status + operationId: getCatStatus + responses: + 200: + description: Success + content: + application/json: + schema: + discriminator: + propertyName: "type" + oneOf: + - $ref: '#/components/schemas/CatAlive' + - $ref: '#/components/schemas/CatDead' + application/xml: + schema: + anyOf: + - $ref: '#/components/schemas/CatAlive' + - $ref: '#/components/schemas/CatDead' + application/yaml: + schema: + allOf: + - $ref: '#/components/schemas/CatAlive' + - $ref: '#/components/schemas/CatDead' + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + +components: + schemas: + + Test: + properties: + name: + type: string + cases: + type: array + items: + $ref: '#/components/schemas/TestCase' + + TestCase: + properties: + name: + type: string + command: + type: string + + Cats: + type: object + properties: + breed: + $ref: '#/components/schemas/CatBreed' + box: + discriminator: + propertyName: "type" + oneOf: + - $ref: '#/components/schemas/CatAlive' + - $ref: '#/components/schemas/CatDead' + + CatBreed: + type: object + discriminator: + propertyName: "type" + oneOf: + - $ref: '#/components/schemas/Purebred' + - $ref: '#/components/schemas/MixedBreed' + + Error: + properties: + code: + type: integer + format: int32 + message: + type: string + + Purebred: + properties: + type: + type: string + enum: + - pure_breed + breed: + type: string + breeder: + type: string + + MixedBreed: + properties: + type: + type: string + enum: + - mixed_breed + furColor: + type: string + furLength: + type: string + + CatAlive: + properties: + type: + type: string + enum: + - cat_alive + name: + type: string + alive_since: + type: string + format: date-time + + CatDead: + properties: + type: + type: string + enum: + - cat_dead + name: + type: string + dead_since: + type: string + format: date-time + cause: + type: string + enum: [car, dog, oldage] diff --git a/pkg/codegen/testdata/testResolvingSpec.json.golden b/pkg/codegen/testdata/testResolvingSpec.json.golden new file mode 100644 index 000000000..7d0b699cf --- /dev/null +++ b/pkg/codegen/testdata/testResolvingSpec.json.golden @@ -0,0 +1,114 @@ +{ + "components": { + "schemas": { + "Test": { + "properties": { + "cases": { + "items": { + "properties": { + "command": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "type": "array" + }, + "name": { + "type": "string" + }, + "verifier": { + "properties": { + "name": { + "type": "string" + } + } + } + } + }, + "TestCase": { + "properties": { + "command": { + "type": "string" + }, + "name": { + "type": "string" + } + } + } + } + }, + "info": { + "description": "This is a test OpenAPI Spec", + "title": "OpenAPI-CodeGen Test", + "version": "1.0.0" + }, + "openapi": "3.0.1", + "paths": { + "/test/{name}": { + "get": { + "operationId": "getTestByName", + "parameters": [ + { + "in": "path", + "name": "name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "cases": { + "items": { + "properties": { + "command": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "type": "array" + }, + "name": { + "type": "string" + }, + "verifier": { + "properties": { + "name": { + "type": "string" + } + } + } + } + } + } + }, + "description": "Success" + } + }, + "summary": "Get test", + "tags": [ + "test" + ] + } + } + }, + "servers": [ + { + "url": "https://test.oapi-codegen.com/v2" + }, + { + "url": "http://test.oapi-codegen.com/v2" + } + ] +} diff --git a/pkg/codegen/testdata/testResolvingSpec.yaml b/pkg/codegen/testdata/testResolvingSpec.yaml new file mode 100644 index 000000000..0f393ab25 --- /dev/null +++ b/pkg/codegen/testdata/testResolvingSpec.yaml @@ -0,0 +1,52 @@ +openapi: 3.0.1 + +info: + title: OpenAPI-CodeGen Test + description: 'This is a test OpenAPI Spec' + version: 1.0.0 + +servers: +- url: https://test.oapi-codegen.com/v2 +- url: http://test.oapi-codegen.com/v2 + +paths: + /test/{name}: + get: + tags: + - test + summary: Get test + operationId: getTestByName + parameters: + - name: name + in: path + required: true + schema: + type: string + responses: + 200: + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/Test' + +components: + schemas: + Test: + properties: + name: + type: string + verifier: + $ref: 'http://localhost:23456/included.yaml#/components/schemas/Verifier' + cases: + type: array + items: + $ref: '#/components/schemas/TestCase' + + TestCase: + properties: + name: + type: string + command: + type: string + diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index 2a35b0341..b6259a60f 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -15,6 +15,10 @@ package codegen import ( "fmt" + + "github.com/getkin/kin-openapi/openapi3" + "github.com/pkg/errors" + "regexp" "sort" "strings" @@ -26,8 +30,12 @@ import ( var pathParamRE *regexp.Regexp +// list of valid word characters in an identifier (excluding '/') used by ToCamelCase +var separatorRE *regexp.Regexp + func init() { pathParamRE = regexp.MustCompile("{[.;?]?([^{}*]+)\\*?}") + separatorRE = regexp.MustCompile(`[^.+:;_~ (){}\[\]\-]+`) } // Uppercase the first character in a string. This assumes UTF-8, so we have @@ -65,7 +73,7 @@ func ToCamelCase(str string) string { if unicode.IsUpper(v) { n += string(v) } - if unicode.IsDigit(v) { + if unicode.IsDigit(v) { n += string(v) } if unicode.IsLower(v) { @@ -76,7 +84,7 @@ func ToCamelCase(str string) string { } } - if strings.ContainsRune(separators, v) { + if strings.ContainsRune(separators, v) { capNext = true } else { capNext = false @@ -197,20 +205,38 @@ func StringInArray(str string, array []string) bool { // #/components/schemas/Foo -> Foo // #/components/parameters/Bar -> Bar // #/components/responses/Baz -> Baz -// Remote components (document.json#/Foo) are not yet supported -// URL components (http://deepmap.com/schemas/document.json#Foo) are not yet -// supported -// We only support flat components for now, so no components in a schema under -// components. -func RefPathToGoType(refPath string) (string, error) { - pathParts := strings.Split(refPath, "/") - if pathParts[0] != "#" { - return "", errors.New("Only local document components are supported") +// +// To specify remote paths there must also be a typeImport map with the types +// mapped to import paths. +// https://foo.com/bar#/components/parameters/Bar -> packagename.Bar +// foo.json#/components/parameters/Bar -> packagename.Bar +func RefPathToGoType(refPath string, importedTypes map[string]TypeImportSpec) (string, error) { + s := strings.Split(refPath, "#") + if len(s) < 2 { + return "", errors.New("Missing fragment marker - this does not seem like a local or remote reference") + } else if len(s) > 2 { + return "", errors.New("Extra fragment marker") } + + pathParts := strings.Split(s[len(s)-1], "/") + if len(pathParts) != 4 { return "", errors.New("Parameter nesting is deeper than supported") } - return SchemaNameToTypeName(pathParts[3]), nil + schemaName := SchemaNameToTypeName(pathParts[len(pathParts)-1]) + + if s[0] != "" { + if importedTypes == nil { + return "", errors.New("detected remote document component but no TypeImports specified") + } + importedType, ok := importedTypes[schemaName] + if !ok { + return "", errors.New("detected remote document component not specified in TypeImports") + } + + return importedType.PackageName + "." + schemaName, nil + } + return schemaName, nil } // This function converts a swagger style path URI with parameters to a @@ -259,6 +285,12 @@ func ReplacePathParamsWithStr(uri string) string { return pathParamRE.ReplaceAllString(uri, "%s") } +// Replaces path parameters with Par1, Par2... +func ReplacePathParamsWithParNStr(uri string) string { + p := 0 + return pathParamRE.ReplaceAllStringFunc(uri, func(_ string) string { p++; return fmt.Sprintf("Par%d", p) }) +} + // Reorders the given parameter definitions to match those in the path URI. func SortParamsByPath(path string, in []ParameterDefinition) ([]ParameterDefinition, error) { pathParams := OrderedParamsFromUri(path) @@ -372,3 +404,13 @@ func StringToGoComment(in string) string { in = strings.TrimSuffix(in, "\n// ") return in } + +// This converts a path, like Object/field1/nestedField into a dot separated single string +func DotSeparatedPath(path []string) string { + return strings.Join(path, ".") +} + +// DotSeparatedPath converts a dot separated path string, like Object.field1 into a go identifier +func DottedStringToTypeName(path string) string { + return strings.ReplaceAll(path, ".", "_") +} diff --git a/pkg/codegen/utils_test.go b/pkg/codegen/utils_test.go index 589283248..c2efd48df 100644 --- a/pkg/codegen/utils_test.go +++ b/pkg/codegen/utils_test.go @@ -23,9 +23,20 @@ import ( func TestStringOps(t *testing.T) { // Test that each substitution works assert.Equal(t, "WordWordWORDWordWordWordWordWordWordWordWordWordWord", ToCamelCase("word.word-WORD+Word_word~word(Word)Word{Word}Word[Word]Word:Word;"), "Camel case conversion failed") + tests := []struct { + in, out, msg string + }{ + {in: "word.word-WORD_word~word", out: "WordWordWORDWordWord", msg: "Camel case conversion failed"}, + {in: "number-1234", out: "Number1234", msg: "Number Camelcasing not working."}, + {in: "path~to~res", out: "PathToRes", msg: "Failed converting path separator"}, + {in: "path-{pathName}", out: "PathPathName", msg: "Failed converting path parameter"}, + {in: "0-a.b+c:d;e_f~g(h)i{j}k[l]m", out: "0ABCDEFGHIJKLM", msg: "Separator test failed"}, + {in: "0-A.B+C:D;E_F~G(H)I{J}K[L]M", out: "0ABCDEFGHIJKLM", msg: "Separator test failed"}, + } - // Make sure numbers don't interact in a funny way. - assert.Equal(t, "Number1234", ToCamelCase("number-1234"), "Number Camelcasing not working.") + for _, test := range tests { + assert.Equal(t, test.out, ToCamelCase(test.in), test.msg) + } } func TestSortedSchemaKeys(t *testing.T) { @@ -134,22 +145,97 @@ func TestSortedRequestBodyKeys(t *testing.T) { } func TestRefPathToGoType(t *testing.T) { - goType, err := RefPathToGoType("#/components/schemas/Foo") - assert.Equal(t, "Foo", goType) - assert.NoError(t, err, "Expecting no error") - - goType, err = RefPathToGoType("#/components/parameters/foo_bar") - assert.Equal(t, "FooBar", goType) - assert.NoError(t, err, "Expecting no error") - - _, err = RefPathToGoType("http://deepmap.com/doc.json#/components/parameters/foo_bar") - assert.Errorf(t, err, "Expected an error on URL reference") - - _, err = RefPathToGoType("doc.json#/components/parameters/foo_bar") - assert.Errorf(t, err, "Expected an error on remote reference") + testTable := map[string]struct { + path string + importedTypes map[string]TypeImportSpec + goType string + isErr bool + }{ + "Pascal case": { + "#/components/schemas/Foo", + nil, + "Foo", + false, + }, + "Snake case": { + "#/components/parameters/foo_bar", + nil, + "FooBar", + false, + }, + "remote ref, no typemap": { + "http://deepmap.com/doc.json#/components/parameters/foo_bar", + nil, + "", + true, + }, + "path ref, no typemap": { + "doc.json#/components/parameters/foo_bar", + nil, + "", + true, + }, + "remote ref, matches typemap": { + "http://deepmap.com/doc.json#/components/parameters/foo_bar", + map[string]TypeImportSpec{"FooBar": TypeImportSpec{Name: "FooBar", PackageName: "mypkg", ImportPath: "github.com/me/mypkg"}}, + "mypkg.FooBar", + false, + }, + "remote ref, matches typemap, using PackageName": { + "http://deepmap.com/doc.json#/components/parameters/foo_bar", + map[string]TypeImportSpec{"FooBar": TypeImportSpec{Name: "FooBar", PackageName: "that_pkg", ImportPath: "github.com/me/mypkg"}}, + "that_pkg.FooBar", + false, + }, + "path ref, matches typemap": { + "doc.json#/components/parameters/foo_bar", + map[string]TypeImportSpec{"FooBar": TypeImportSpec{Name: "FooBar", PackageName: "mypkg", ImportPath: "github.com/me/mypkg"}}, + "mypkg.FooBar", + false, + }, + "remote ref, no match in typemap": { + "http://deepmap.com/doc.json#/components/parameters/foo_bar", + map[string]TypeImportSpec{"Foo": TypeImportSpec{Name: "Foo", PackageName: "mypkg", ImportPath: "github.com/me/mypkg"}}, + "", + true, + }, + "path ref, no match in typemap": { + "doc.json#/components/parameters/foo_bar", + map[string]TypeImportSpec{"Foo": TypeImportSpec{Name: "Foo", PackageName: "mypkg", ImportPath: "github.com/me/mypkg"}}, + "", + true, + }, + "reference depth incorrect": { + "#/components/parameters/foo/components/bar", + nil, + "", + true, + }, + "invalid path, too many #": { + "#/components/parameters/foo#", + nil, + "", + true, + }, + "invalid path, no #": { + "/components/parameters/foo", + nil, + "", + true, + }, + } + for name, test := range testTable { + t.Run(name, func(t *testing.T) { + goType, err := RefPathToGoType(test.path, test.importedTypes) + assert.Equal(t, test.goType, goType) + if test.isErr { + assert.Error(t, err, "Expected an error") + } else { + assert.NoError(t, err, "Expecting no error") + } + }) + } - _, err = RefPathToGoType("#/components/parameters/foo/components/bar") - assert.Errorf(t, err, "Expected an error on reference depth") } func TestSwaggerUriToEchoUri(t *testing.T) { @@ -231,5 +317,9 @@ Line assert.EqualValues(t, testCase.expected, result, testCase.message) }) } +} +func TestReplacePathParamsWithParNStr(t *testing.T) { + result := ReplacePathParamsWithParNStr("GET /path/{param1}/{.param2}/{;param3*}/foo") + assert.EqualValues(t, "GET /path/Par1/Par2/Par3/foo", result) } diff --git a/pkg/middleware/oapi_validate.go b/pkg/middleware/oapi_validate.go index 2cf2af643..a9745f7c5 100644 --- a/pkg/middleware/oapi_validate.go +++ b/pkg/middleware/oapi_validate.go @@ -135,8 +135,8 @@ func ValidateRequestFromContext(ctx echo.Context, router *openapi3filter.Router, // 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 &echo.HTTPError{ - Code: http.StatusInternalServerError, - Message: fmt.Sprintf("error validating request: %s", err), + Code: http.StatusInternalServerError, + Message: fmt.Sprintf("error validating request: %s", err), Internal: err, } } diff --git a/pkg/middleware/oapi_validate_test.go b/pkg/middleware/oapi_validate_test.go index aede2ff10..3679ea809 100644 --- a/pkg/middleware/oapi_validate_test.go +++ b/pkg/middleware/oapi_validate_test.go @@ -26,7 +26,7 @@ import ( "github.com/labstack/echo/v4" "github.com/stretchr/testify/assert" - "github.com/deepmap/oapi-codegen/pkg/testutil" + "github.com/weberr13/oapi-codegen/pkg/testutil" ) var testSchema = `openapi: "3.0.0" diff --git a/pkg/runtime/bindparam.go b/pkg/runtime/bindparam.go index 18a41300a..7556b8f62 100644 --- a/pkg/runtime/bindparam.go +++ b/pkg/runtime/bindparam.go @@ -28,8 +28,8 @@ import ( // This function binds a parameter as described in the Path Parameters // section here to a Go object: // https://swagger.io/docs/specification/serialization/ -func BindStyledParameter(style string, explode bool, paramName string, - value string, dest interface{}) error { +func BindStyledParameter(style string, explode bool, unescape func(string) (string, error), + paramName string, value string, dest interface{}) error { if value == "" { return echo.NewHTTPError(http.StatusBadRequest, "parameter '%s' is empty, can't bind its value", paramName) @@ -49,7 +49,7 @@ func BindStyledParameter(style string, explode bool, paramName string, return echo.NewHTTPError(http.StatusBadRequest, err.Error()) } - err = bindSplitPartsToDestinationStruct(paramName, parts, explode, dest) + err = bindSplitPartsToDestinationStruct(paramName, parts, explode, unescape, dest) if err != nil { return echo.NewHTTPError(http.StatusBadRequest, err.Error()) } @@ -63,7 +63,7 @@ func BindStyledParameter(style string, explode bool, paramName string, return fmt.Errorf("error splitting input '%s' into parts: %s", value, err) } - err = bindSplitPartsToDestinationArray(parts, dest) + err = bindSplitPartsToDestinationArray(unescape, parts, dest) if err != nil { return echo.NewHTTPError(http.StatusBadRequest, err.Error()) } @@ -71,7 +71,7 @@ func BindStyledParameter(style string, explode bool, paramName string, } // Try to bind the remaining types as a base type. - return BindStringToObject(value, dest) + return BindStringToObject(unescape, value, dest) } // This is a complex set of operations, but each given parameter style can be @@ -167,7 +167,7 @@ func splitStyledParameter(style string, explode bool, object bool, paramName str // Given a set of values as a slice, create a slice to hold them all, and // assign to each one by one. -func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error { +func bindSplitPartsToDestinationArray(unescape func(string) (string, error), parts []string, dest interface{}) error { // Everything comes in by pointer, dereference it v := reflect.Indirect(reflect.ValueOf(dest)) @@ -179,7 +179,7 @@ func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error { // hold all the parts. newArray := reflect.MakeSlice(t, len(parts), len(parts)) for i, p := range parts { - err := BindStringToObject(p, newArray.Index(i).Addr().Interface()) + err := BindStringToObject(unescape, p, newArray.Index(i).Addr().Interface()) if err != nil { return fmt.Errorf("error setting array element: %s", err) } @@ -200,7 +200,8 @@ func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error { // We punt the hard work of binding these values to the object to the json // library. We'll turn those arrays into JSON strings, and unmarshal // into the struct. -func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error { +func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, + unescape func(string) (string, error), dest interface{}) error { // We've got a destination object, we'll create a JSON representation // of the input value, and let the json library deal with the unmarshaling var fields []string @@ -220,7 +221,13 @@ func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode fields = make([]string, len(parts)/2) for i := 0; i < len(parts); i += 2 { key := parts[i] - value := parts[i+1] + if unescape == nil { + return fmt.Errorf("no unescape function provided") + } + value, err := unescape(parts[i+1]) + if err != nil { + return fmt.Errorf("error unescaping string parameter element: %s", parts[i+1]) + } fields[i/2] = "\"" + key + "\":\"" + value + "\"" } } @@ -313,7 +320,7 @@ func BindQueryParameter(style string, explode bool, required bool, paramName str return nil } } - err = bindSplitPartsToDestinationArray(values, output) + err = bindSplitPartsToDestinationArray(url.QueryUnescape, values, output) case reflect.Struct: // This case is really annoying, and error prone, but the // form style object binding doesn't tell us which arguments @@ -335,7 +342,7 @@ func BindQueryParameter(style string, explode bool, required bool, paramName str return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("multiple values for single value parameter '%s'", paramName)) } - err = BindStringToObject(values[0], output) + err = BindStringToObject(url.QueryUnescape, values[0], output) } if err != nil { return err @@ -365,9 +372,9 @@ func BindQueryParameter(style string, explode bool, required bool, paramName str var err error switch k { case reflect.Slice: - err = bindSplitPartsToDestinationArray(parts, output) + err = bindSplitPartsToDestinationArray(url.QueryUnescape, parts, output) case reflect.Struct: - err = bindSplitPartsToDestinationStruct(paramName, parts, explode, output) + err = bindSplitPartsToDestinationStruct(paramName, parts, explode, url.QueryUnescape, output) default: if len(parts) == 0 { if required { @@ -381,7 +388,7 @@ func BindQueryParameter(style string, explode bool, required bool, paramName str return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("multiple values for single value parameter '%s'", paramName)) } - err = BindStringToObject(parts[0], output) + err = BindStringToObject(url.QueryUnescape, parts[0], output) } if err != nil { return err @@ -404,7 +411,12 @@ func BindQueryParameter(style string, explode bool, required bool, paramName str } k = strings.TrimSuffix(split[1], "]") - objectMap[k] = v[0] + val, err := url.QueryUnescape(v[0]) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, + fmt.Sprintf("parameter '%s=%s' could not be unescaped", k, v)) + } + objectMap[k] = val } // Marshal and unmarshal the objectMap into dest @@ -473,7 +485,7 @@ func bindParamsToExplodedObject(paramName string, values url.Values, dest interf return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("field '%s' specified multiple times for param '%s'", fieldName, paramName)) } - err := BindStringToObject(fieldVal[0], v.Field(i).Addr().Interface()) + err := BindStringToObject(url.QueryUnescape, fieldVal[0], v.Field(i).Addr().Interface()) if err != nil { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("could not bind query arg '%s' to request object: %s", paramName, err)) diff --git a/pkg/runtime/bindparam_test.go b/pkg/runtime/bindparam_test.go index fcb827557..817b851d3 100644 --- a/pkg/runtime/bindparam_test.go +++ b/pkg/runtime/bindparam_test.go @@ -270,4 +270,97 @@ func TestBindQueryParameter(t *testing.T) { assert.NoError(t, err) assert.Equal(t, expected, birthday) }) + // ------------------------ deepObject style --------------------------------- + type ID struct { + FirstName *string `json:"firstName"` + LastName *string `json:"lastName"` + Role string `json:"role"` + } + + expectedName := "Alex" + expectedDeepObject := &ID{FirstName: &expectedName, Role: "admin?"} + + actualDeepObject := new(ID) + paramName := "id" + queryParams := url.Values{ + "id[firstName]": {"Alex"}, + "id[role]": {"admin%3F"}, + "foo": {"bar"}, + } + + err := BindQueryParameter("deepObject", true, false, paramName, queryParams, &actualDeepObject) + assert.NoError(t, err) + assert.Equal(t, expectedDeepObject, actualDeepObject) + + // ------------------------ form style --------------------------------- + // ----- slice, exploded=true ----- + expectedSlice := &[]string{"Alex", "Ben?", "Carl"} + + actualSlice := &[]string{} + paramName = "name" + queryParams = url.Values{ + "name": {"Alex", "Ben%3F", "Carl"}, + } + + err = BindQueryParameter("form", true, false, paramName, queryParams, &actualSlice) + assert.NoError(t, err) + assert.Equal(t, expectedSlice, actualSlice) + + // ----- slice, exploded=false ----- + expectedSlice = &[]string{"Ben?"} + + actualSlice = &[]string{} + paramName = "name" + queryParams = url.Values{ + "name": {"Ben%3F"}, + } + + err = BindQueryParameter("form", false, false, paramName, queryParams, &actualSlice) + assert.NoError(t, err) + assert.Equal(t, expectedSlice, actualSlice) + + // ----- struct, exploded=true ----- + type Name struct { + FirstName string `json:"firstName"` + LastName string `json:"lastName"` + } + + expectedStruct := &Name{FirstName: "Alex", LastName: "$mith"} + + actualStruct := new(Name) + paramName = "name" + queryParams = url.Values{ + "firstName": {"Alex"}, + "lastName": {"%24mith"}, + } + + err = BindQueryParameter("form", true, false, paramName, queryParams, &actualStruct) + assert.NoError(t, err) + assert.Equal(t, expectedStruct, actualStruct) + + // ----- struct, exploded=false ----- + expectedStruct = &Name{FirstName: "Alex", LastName: "$mith"} + + actualStruct = new(Name) + paramName = "name" + queryParams = url.Values{ + "name": {"firstname,Alex,lastName,%24mith"}, + } + + err = BindQueryParameter("form", false, false, paramName, queryParams, &actualStruct) + assert.NoError(t, err) + assert.Equal(t, expectedStruct, actualStruct) + + // ----- default ----- + expectedString := "$mith" + + actualString := new(string) + paramName = "name" + queryParams = url.Values{ + "name": {"%24mith"}, + } + + err = BindQueryParameter("form", true, false, paramName, queryParams, &actualString) + assert.NoError(t, err) + assert.Equal(t, &expectedString, actualString) } diff --git a/pkg/runtime/bindstring.go b/pkg/runtime/bindstring.go index f3397a2b0..c3a93c1f9 100644 --- a/pkg/runtime/bindstring.go +++ b/pkg/runtime/bindstring.go @@ -29,7 +29,7 @@ import ( // type aliases. This function was the easy way out, the better way, since we // know the destination type each place that we use this, is to generate code // to read each specific type. -func BindStringToObject(src string, dst interface{}) error { +func BindStringToObject(unescape func(string) (string, error), src string, dst interface{}) error { var err error v := reflect.ValueOf(dst) @@ -55,7 +55,16 @@ func BindStringToObject(src string, dst interface{}) error { v.SetInt(val) } case reflect.String: - v.SetString(src) + if unescape == nil { + return fmt.Errorf("no unescape function provided") + } + + var escaped string + escaped, err = unescape(src) + if err != nil { + return fmt.Errorf("error unescaping string parameter element: %s", src) + } + v.SetString(escaped) err = nil case reflect.Float64, reflect.Float32: var val float64 diff --git a/pkg/runtime/bindstring_test.go b/pkg/runtime/bindstring_test.go index 193f54e5b..95be392ed 100644 --- a/pkg/runtime/bindstring_test.go +++ b/pkg/runtime/bindstring_test.go @@ -14,79 +14,104 @@ package runtime import ( + "net/url" "testing" "time" "github.com/stretchr/testify/assert" ) +func unescapePassThrough(s string) (string, error) { + return s, nil +} + func TestBindStringToObject(t *testing.T) { + var s string + assert.NoError(t, BindStringToObject(url.PathUnescape, "foo", &s)) + assert.Equal(t, "foo", s) + assert.NoError(t, BindStringToObject(url.QueryUnescape, "foo", &s)) + assert.Equal(t, "foo", s) + assert.NoError(t, BindStringToObject(unescapePassThrough, "foo", &s)) + assert.Equal(t, "foo", s) + assert.NoError(t, BindStringToObject(url.PathUnescape, "foo%3Fbar", &s)) + assert.Equal(t, "foo?bar", s) + assert.NoError(t, BindStringToObject(url.QueryUnescape, "foo%3Fbar", &s)) + assert.Equal(t, "foo?bar", s) + assert.NoError(t, BindStringToObject(unescapePassThrough, "foo%3Fbar", &s)) + assert.Equal(t, "foo%3Fbar", s) + assert.NoError(t, BindStringToObject(url.PathUnescape, "foo+bar", &s)) + assert.Equal(t, "foo+bar", s) + assert.NoError(t, BindStringToObject(url.QueryUnescape, "foo+bar", &s)) + assert.Equal(t, "foo bar", s) + assert.NoError(t, BindStringToObject(unescapePassThrough, "foo+bar", &s)) + assert.Equal(t, "foo+bar", s) + var i int - assert.NoError(t, BindStringToObject("5", &i)) + assert.NoError(t, BindStringToObject(url.PathUnescape, "5", &i)) assert.Equal(t, 5, i) // Let's make sure we error out on things that can't be the correct // type. Since we're using reflect package setters, we'll have similar // unassignable type errors. - assert.Error(t, BindStringToObject("5.7", &i)) - assert.Error(t, BindStringToObject("foo", &i)) - assert.Error(t, BindStringToObject("1,2,3", &i)) + assert.Error(t, BindStringToObject(url.PathUnescape, "5.7", &i)) + assert.Error(t, BindStringToObject(url.PathUnescape, "foo", &i)) + assert.Error(t, BindStringToObject(url.PathUnescape, "1,2,3", &i)) var i64 int64 - assert.NoError(t, BindStringToObject("124", &i64)) + assert.NoError(t, BindStringToObject(url.PathUnescape, "124", &i64)) assert.Equal(t, int64(124), i64) - assert.Error(t, BindStringToObject("5.7", &i64)) - assert.Error(t, BindStringToObject("foo", &i64)) - assert.Error(t, BindStringToObject("1,2,3", &i64)) + assert.Error(t, BindStringToObject(url.PathUnescape, "5.7", &i64)) + assert.Error(t, BindStringToObject(url.PathUnescape, "foo", &i64)) + assert.Error(t, BindStringToObject(url.PathUnescape, "1,2,3", &i64)) var i32 int32 - assert.NoError(t, BindStringToObject("12", &i32)) + assert.NoError(t, BindStringToObject(url.PathUnescape, "12", &i32)) assert.Equal(t, int32(12), i32) - assert.Error(t, BindStringToObject("5.7", &i32)) - assert.Error(t, BindStringToObject("foo", &i32)) - assert.Error(t, BindStringToObject("1,2,3", &i32)) + assert.Error(t, BindStringToObject(url.PathUnescape, "5.7", &i32)) + assert.Error(t, BindStringToObject(url.PathUnescape, "foo", &i32)) + assert.Error(t, BindStringToObject(url.PathUnescape, "1,2,3", &i32)) var b bool - assert.NoError(t, BindStringToObject("True", &b)) + assert.NoError(t, BindStringToObject(url.PathUnescape, "True", &b)) assert.Equal(t, true, b) - assert.NoError(t, BindStringToObject("true", &b)) + assert.NoError(t, BindStringToObject(url.PathUnescape, "true", &b)) assert.Equal(t, true, b) - assert.NoError(t, BindStringToObject("1", &b)) + assert.NoError(t, BindStringToObject(url.PathUnescape, "1", &b)) assert.Equal(t, true, b) var f64 float64 - assert.NoError(t, BindStringToObject("1.25", &f64)) + assert.NoError(t, BindStringToObject(url.PathUnescape, "1.25", &f64)) assert.Equal(t, float64(1.25), f64) - assert.Error(t, BindStringToObject("foo", &f64)) - assert.Error(t, BindStringToObject("1,2,3", &f64)) + assert.Error(t, BindStringToObject(url.PathUnescape, "foo", &f64)) + assert.Error(t, BindStringToObject(url.PathUnescape, "1,2,3", &f64)) var f32 float32 - assert.NoError(t, BindStringToObject("3.125", &f32)) + assert.NoError(t, BindStringToObject(url.PathUnescape, "3.125", &f32)) assert.Equal(t, float32(3.125), f32) - assert.Error(t, BindStringToObject("foo", &f32)) - assert.Error(t, BindStringToObject("1,2,3", &f32)) + assert.Error(t, BindStringToObject(url.PathUnescape, "foo", &f32)) + assert.Error(t, BindStringToObject(url.PathUnescape, "1,2,3", &f32)) // This checks whether binding works through a type alias. type SomeType int var st SomeType - assert.NoError(t, BindStringToObject("5", &st)) + assert.NoError(t, BindStringToObject(url.PathUnescape, "5", &st)) assert.Equal(t, SomeType(5), st) // Check time binding now := time.Now().UTC() strTime := now.Format(time.RFC3339Nano) var parsedTime time.Time - assert.NoError(t, BindStringToObject(strTime, &parsedTime)) + assert.NoError(t, BindStringToObject(url.PathUnescape, strTime, &parsedTime)) parsedTime = parsedTime.UTC() assert.EqualValues(t, now, parsedTime) now = now.Truncate(time.Second) strTime = now.Format(time.RFC3339) - assert.NoError(t, BindStringToObject(strTime, &parsedTime)) + assert.NoError(t, BindStringToObject(url.PathUnescape, strTime, &parsedTime)) parsedTime = parsedTime.UTC() assert.EqualValues(t, now, parsedTime) } diff --git a/pkg/runtime/styleparam.go b/pkg/runtime/styleparam.go index 3edcce67d..5d940b394 100644 --- a/pkg/runtime/styleparam.go +++ b/pkg/runtime/styleparam.go @@ -25,7 +25,7 @@ import ( // Given an input value, such as a primitive type, array or object, turn it // into a parameter based on style/explode definition. -func StyleParam(style string, explode bool, paramName string, value interface{}) (string, error) { +func StyleParam(style string, explode bool, escape func(string) string, paramName string, value interface{}) (string, error) { t := reflect.TypeOf(value) v := reflect.ValueOf(value) @@ -46,17 +46,17 @@ func StyleParam(style string, explode bool, paramName string, value interface{}) for i := 0; i < n; i++ { sliceVal[i] = v.Index(i).Interface() } - return styleSlice(style, explode, paramName, sliceVal) + return styleSlice(style, explode, escape, paramName, sliceVal) case reflect.Struct: - return styleStruct(style, explode, paramName, value) + return styleStruct(style, explode, escape, paramName, value) case reflect.Map: return styleMap(style, explode, paramName, value) default: - return stylePrimitive(style, explode, paramName, value) + return stylePrimitive(style, explode, escape, paramName, value) } } -func styleSlice(style string, explode bool, paramName string, values []interface{}) (string, error) { +func styleSlice(style string, explode bool, escape func(string) string, paramName string, values []interface{}) (string, error) { var prefix string var separator string @@ -106,7 +106,7 @@ func styleSlice(style string, explode bool, paramName string, values []interface var err error parts := make([]string, len(values)) for i, v := range values { - parts[i], err = primitiveToString(v) + parts[i], err = primitiveToString(escape, v) if err != nil { return "", fmt.Errorf("error formatting '%s': %s", paramName, err) } @@ -125,7 +125,7 @@ func sortedKeys(strMap map[string]string) []string { return keys } -func styleStruct(style string, explode bool, paramName string, value interface{}) (string, error) { +func styleStruct(style string, explode bool, escape func(string) string, paramName string, value interface{}) (string, error) { // This is a special case. The struct may be a time, in which case, marshal // it in RFC3339 format. if timeVal, ok := value.(*time.Time); ok { @@ -157,7 +157,7 @@ func styleStruct(style string, explode bool, paramName string, value interface{} if f.Type().Kind() == reflect.Ptr && f.IsNil() { continue } - str, err := primitiveToString(f.Interface()) + str, err := primitiveToString(escape, f.Interface()) if err != nil { return "", fmt.Errorf("error formatting '%s': %s", paramName, err) } @@ -252,8 +252,8 @@ func processFieldDict(style string, explode bool, paramName string, fieldDict ma return prefix + strings.Join(parts, separator), nil } -func stylePrimitive(style string, explode bool, paramName string, value interface{}) (string, error) { - strVal, err := primitiveToString(value) +func stylePrimitive(style string, explode bool, escape func(string) string, paramName string, value interface{}) (string, error) { + strVal, err := primitiveToString(escape, value) if err != nil { return "", err } @@ -275,7 +275,7 @@ func stylePrimitive(style string, explode bool, paramName string, value interfac // Converts a primitive value to a string. We need to do this based on the // Kind of an interface, not the Type to work with aliased types. -func primitiveToString(value interface{}) (string, error) { +func primitiveToString(escape func(string) string, value interface{}) (string, error) { var output string // Values may come in by pointer for optionals, so make sure to dereferene. @@ -295,7 +295,10 @@ func primitiveToString(value interface{}) (string, error) { output = "false" } case reflect.String: - output = v.String() + if escape == nil { + return "", fmt.Errorf("no escape function provided") + } + output = escape(v.String()) default: return "", fmt.Errorf("unsupported type %s", reflect.TypeOf(value).String()) } diff --git a/pkg/runtime/styleparam_test.go b/pkg/runtime/styleparam_test.go index d908b59e2..72c2be2f4 100644 --- a/pkg/runtime/styleparam_test.go +++ b/pkg/runtime/styleparam_test.go @@ -14,14 +14,23 @@ package runtime import ( + "net/url" "testing" "github.com/stretchr/testify/assert" ) +func escapePassThrough(s string) string { + return s +} + func TestStyleParam(t *testing.T) { primitive := 5 + unescapedPrimitive := "foo=bar" + array := []int{3, 4, 5} + unescapedArray := []string{"test?", "Sm!th", "J+mes", "foo=bar"} + type TestObject struct { FirstName string `json:"firstName"` Role string `json:"role"` @@ -34,29 +43,66 @@ func TestStyleParam(t *testing.T) { dict["firstName"] = "Alex" dict["role"] = "admin" + unescapedObject := TestObject{ + FirstName: "Al=x", + Role: "adm;n", + } + // ---------------------------- Simple Style ------------------------------- - result, err := StyleParam("simple", false, "id", primitive) + result, err := StyleParam("simple", false, escapePassThrough, "id", primitive) assert.NoError(t, err) assert.EqualValues(t, "5", result) - result, err = StyleParam("simple", true, "id", primitive) + result, err = StyleParam("simple", true, escapePassThrough, "id", primitive) assert.NoError(t, err) assert.EqualValues(t, "5", result) - result, err = StyleParam("simple", false, "id", array) + result, err = StyleParam("simple", false, url.PathEscape, "id", unescapedPrimitive) + assert.NoError(t, err) + assert.EqualValues(t, "foo=bar", result) + + result, err = StyleParam("simple", true, url.PathEscape, "id", unescapedPrimitive) + assert.NoError(t, err) + assert.EqualValues(t, "foo=bar", result) + + result, err = StyleParam("simple", false, url.QueryEscape, "id", unescapedPrimitive) + assert.NoError(t, err) + assert.EqualValues(t, "foo%3Dbar", result) + + result, err = StyleParam("simple", true, url.QueryEscape, "id", unescapedPrimitive) + assert.NoError(t, err) + assert.EqualValues(t, "foo%3Dbar", result) + + result, err = StyleParam("simple", false, escapePassThrough, "id", array) assert.NoError(t, err) assert.EqualValues(t, "3,4,5", result) - result, err = StyleParam("simple", true, "id", array) + result, err = StyleParam("simple", true, escapePassThrough, "id", array) assert.NoError(t, err) assert.EqualValues(t, "3,4,5", result) - result, err = StyleParam("simple", false, "id", object) + result, err = StyleParam("simple", false, url.PathEscape, "id", unescapedArray) + assert.NoError(t, err) + assert.EqualValues(t, "test%3F,Sm%21th,J+mes,foo=bar", result) + + result, err = StyleParam("simple", true, url.PathEscape, "id", unescapedArray) + assert.NoError(t, err) + assert.EqualValues(t, "test%3F,Sm%21th,J+mes,foo=bar", result) + + result, err = StyleParam("simple", false, url.QueryEscape, "id", unescapedArray) + assert.NoError(t, err) + assert.EqualValues(t, "test%3F,Sm%21th,J%2Bmes,foo%3Dbar", result) + + result, err = StyleParam("simple", true, url.QueryEscape, "id", unescapedArray) + assert.NoError(t, err) + assert.EqualValues(t, "test%3F,Sm%21th,J%2Bmes,foo%3Dbar", result) + + result, err = StyleParam("simple", false, escapePassThrough, "id", object) assert.NoError(t, err) assert.EqualValues(t, "firstName,Alex,role,admin", result) - result, err = StyleParam("simple", true, "id", object) + result, err = StyleParam("simple", true, escapePassThrough, "id", object) assert.NoError(t, err) assert.EqualValues(t, "firstName=Alex,role=admin", result) @@ -67,30 +113,77 @@ func TestStyleParam(t *testing.T) { result, err = StyleParam("simple", true, "id", dict) assert.NoError(t, err) assert.EqualValues(t, "firstName=Alex,role=admin", result) + result, err = StyleParam("simple", false, url.PathEscape, "id", unescapedObject) + assert.NoError(t, err) + assert.EqualValues(t, "firstName,Al=x,role,adm%3Bn", result) + + result, err = StyleParam("simple", true, url.PathEscape, "id", unescapedObject) + assert.NoError(t, err) + assert.EqualValues(t, "firstName=Al=x,role=adm%3Bn", result) + + result, err = StyleParam("simple", false, url.QueryEscape, "id", unescapedObject) + assert.NoError(t, err) + assert.EqualValues(t, "firstName,Al%3Dx,role,adm%3Bn", result) + + result, err = StyleParam("simple", true, url.QueryEscape, "id", unescapedObject) + assert.NoError(t, err) + assert.EqualValues(t, "firstName=Al%3Dx,role=adm%3Bn", result) // ----------------------------- Label Style ------------------------------- - result, err = StyleParam("label", false, "id", primitive) + result, err = StyleParam("label", false, escapePassThrough, "id", primitive) assert.NoError(t, err) assert.EqualValues(t, ".5", result) - result, err = StyleParam("label", true, "id", primitive) + result, err = StyleParam("label", true, escapePassThrough, "id", primitive) assert.NoError(t, err) assert.EqualValues(t, ".5", result) - result, err = StyleParam("label", false, "id", array) + result, err = StyleParam("label", false, url.PathEscape, "id", unescapedPrimitive) + assert.NoError(t, err) + assert.EqualValues(t, ".foo=bar", result) + + result, err = StyleParam("label", true, url.PathEscape, "id", unescapedPrimitive) + assert.NoError(t, err) + assert.EqualValues(t, ".foo=bar", result) + + result, err = StyleParam("label", false, url.QueryEscape, "id", unescapedPrimitive) + assert.NoError(t, err) + assert.EqualValues(t, ".foo%3Dbar", result) + + result, err = StyleParam("label", true, url.QueryEscape, "id", unescapedPrimitive) + assert.NoError(t, err) + assert.EqualValues(t, ".foo%3Dbar", result) + + result, err = StyleParam("label", false, escapePassThrough, "id", array) assert.NoError(t, err) assert.EqualValues(t, ".3,4,5", result) - result, err = StyleParam("label", true, "id", array) + result, err = StyleParam("label", true, escapePassThrough, "id", array) assert.NoError(t, err) assert.EqualValues(t, ".3.4.5", result) - result, err = StyleParam("label", false, "id", object) + result, err = StyleParam("label", false, url.PathEscape, "id", unescapedArray) + assert.NoError(t, err) + assert.EqualValues(t, ".test%3F,Sm%21th,J+mes,foo=bar", result) + + result, err = StyleParam("label", true, url.PathEscape, "id", unescapedArray) + assert.NoError(t, err) + assert.EqualValues(t, ".test%3F.Sm%21th.J+mes.foo=bar", result) + + result, err = StyleParam("label", false, url.QueryEscape, "id", unescapedArray) + assert.NoError(t, err) + assert.EqualValues(t, ".test%3F,Sm%21th,J%2Bmes,foo%3Dbar", result) + + result, err = StyleParam("label", true, url.QueryEscape, "id", unescapedArray) + assert.NoError(t, err) + assert.EqualValues(t, ".test%3F.Sm%21th.J%2Bmes.foo%3Dbar", result) + + result, err = StyleParam("label", false, escapePassThrough, "id", object) assert.NoError(t, err) assert.EqualValues(t, ".firstName,Alex,role,admin", result) - result, err = StyleParam("label", true, "id", object) + result, err = StyleParam("label", true, escapePassThrough, "id", object) assert.NoError(t, err) assert.EqualValues(t, ".firstName=Alex.role=admin", result) @@ -101,30 +194,77 @@ func TestStyleParam(t *testing.T) { result, err = StyleParam("label", true, "id", dict) assert.NoError(t, err) assert.EqualValues(t, ".firstName=Alex.role=admin", result) + result, err = StyleParam("label", false, url.PathEscape, "id", unescapedObject) + assert.NoError(t, err) + assert.EqualValues(t, ".firstName,Al=x,role,adm%3Bn", result) + + result, err = StyleParam("label", true, url.PathEscape, "id", unescapedObject) + assert.NoError(t, err) + assert.EqualValues(t, ".firstName=Al=x.role=adm%3Bn", result) + + result, err = StyleParam("label", false, url.QueryEscape, "id", unescapedObject) + assert.NoError(t, err) + assert.EqualValues(t, ".firstName,Al%3Dx,role,adm%3Bn", result) + + result, err = StyleParam("label", true, url.QueryEscape, "id", unescapedObject) + assert.NoError(t, err) + assert.EqualValues(t, ".firstName=Al%3Dx.role=adm%3Bn", result) // ----------------------------- Matrix Style ------------------------------ - result, err = StyleParam("matrix", false, "id", primitive) + result, err = StyleParam("matrix", false, escapePassThrough, "id", primitive) assert.NoError(t, err) assert.EqualValues(t, ";id=5", result) - result, err = StyleParam("matrix", true, "id", primitive) + result, err = StyleParam("matrix", true, escapePassThrough, "id", primitive) assert.NoError(t, err) assert.EqualValues(t, ";id=5", result) - result, err = StyleParam("matrix", false, "id", array) + result, err = StyleParam("matrix", false, url.PathEscape, "id", unescapedPrimitive) + assert.NoError(t, err) + assert.EqualValues(t, ";id=foo=bar", result) + + result, err = StyleParam("matrix", true, url.PathEscape, "id", unescapedPrimitive) + assert.NoError(t, err) + assert.EqualValues(t, ";id=foo=bar", result) + + result, err = StyleParam("matrix", false, url.QueryEscape, "id", unescapedPrimitive) + assert.NoError(t, err) + assert.EqualValues(t, ";id=foo%3Dbar", result) + + result, err = StyleParam("matrix", true, url.QueryEscape, "id", unescapedPrimitive) + assert.NoError(t, err) + assert.EqualValues(t, ";id=foo%3Dbar", result) + + result, err = StyleParam("matrix", false, escapePassThrough, "id", array) assert.NoError(t, err) assert.EqualValues(t, ";id=3,4,5", result) - result, err = StyleParam("matrix", true, "id", array) + result, err = StyleParam("matrix", true, escapePassThrough, "id", array) assert.NoError(t, err) assert.EqualValues(t, ";id=3;id=4;id=5", result) - result, err = StyleParam("matrix", false, "id", object) + result, err = StyleParam("matrix", false, url.PathEscape, "id", unescapedArray) + assert.NoError(t, err) + assert.EqualValues(t, ";id=test%3F,Sm%21th,J+mes,foo=bar", result) + + result, err = StyleParam("matrix", true, url.PathEscape, "id", unescapedArray) + assert.NoError(t, err) + assert.EqualValues(t, ";id=test%3F;id=Sm%21th;id=J+mes;id=foo=bar", result) + + result, err = StyleParam("matrix", false, url.QueryEscape, "id", unescapedArray) + assert.NoError(t, err) + assert.EqualValues(t, ";id=test%3F,Sm%21th,J%2Bmes,foo%3Dbar", result) + + result, err = StyleParam("matrix", true, url.QueryEscape, "id", unescapedArray) + assert.NoError(t, err) + assert.EqualValues(t, ";id=test%3F;id=Sm%21th;id=J%2Bmes;id=foo%3Dbar", result) + + result, err = StyleParam("matrix", false, escapePassThrough, "id", object) assert.NoError(t, err) assert.EqualValues(t, ";id=firstName,Alex,role,admin", result) - result, err = StyleParam("matrix", true, "id", object) + result, err = StyleParam("matrix", true, escapePassThrough, "id", object) assert.NoError(t, err) assert.EqualValues(t, ";firstName=Alex;role=admin", result) @@ -135,29 +275,76 @@ func TestStyleParam(t *testing.T) { result, err = StyleParam("matrix", true, "id", dict) assert.NoError(t, err) assert.EqualValues(t, ";firstName=Alex;role=admin", result) + result, err = StyleParam("matrix", false, url.PathEscape, "id", unescapedObject) + assert.NoError(t, err) + assert.EqualValues(t, ";id=firstName,Al=x,role,adm%3Bn", result) + + result, err = StyleParam("matrix", true, url.PathEscape, "id", unescapedObject) + assert.NoError(t, err) + assert.EqualValues(t, ";firstName=Al=x;role=adm%3Bn", result) + + result, err = StyleParam("matrix", false, url.QueryEscape, "id", unescapedObject) + assert.NoError(t, err) + assert.EqualValues(t, ";id=firstName,Al%3Dx,role,adm%3Bn", result) + + result, err = StyleParam("matrix", true, url.QueryEscape, "id", unescapedObject) + assert.NoError(t, err) + assert.EqualValues(t, ";firstName=Al%3Dx;role=adm%3Bn", result) // ------------------------------ Form Style ------------------------------- - result, err = StyleParam("form", false, "id", primitive) + result, err = StyleParam("form", false, escapePassThrough, "id", primitive) assert.NoError(t, err) assert.EqualValues(t, "id=5", result) - result, err = StyleParam("form", true, "id", primitive) + result, err = StyleParam("form", true, escapePassThrough, "id", primitive) assert.NoError(t, err) assert.EqualValues(t, "id=5", result) - result, err = StyleParam("form", false, "id", array) + result, err = StyleParam("form", false, url.PathEscape, "id", unescapedPrimitive) + assert.NoError(t, err) + assert.EqualValues(t, "id=foo=bar", result) + + result, err = StyleParam("form", true, url.PathEscape, "id", unescapedPrimitive) + assert.NoError(t, err) + assert.EqualValues(t, "id=foo=bar", result) + + result, err = StyleParam("form", false, url.QueryEscape, "id", unescapedPrimitive) + assert.NoError(t, err) + assert.EqualValues(t, "id=foo%3Dbar", result) + + result, err = StyleParam("form", true, url.QueryEscape, "id", unescapedPrimitive) + assert.NoError(t, err) + assert.EqualValues(t, "id=foo%3Dbar", result) + + result, err = StyleParam("form", false, escapePassThrough, "id", array) assert.NoError(t, err) assert.EqualValues(t, "id=3,4,5", result) - result, err = StyleParam("form", true, "id", array) + result, err = StyleParam("form", true, escapePassThrough, "id", array) assert.NoError(t, err) assert.EqualValues(t, "id=3&id=4&id=5", result) - result, err = StyleParam("form", false, "id", object) + result, err = StyleParam("form", false, url.PathEscape, "id", unescapedArray) + assert.NoError(t, err) + assert.EqualValues(t, "id=test%3F,Sm%21th,J+mes,foo=bar", result) + + result, err = StyleParam("form", true, url.PathEscape, "id", unescapedArray) + assert.NoError(t, err) + assert.EqualValues(t, "id=test%3F&id=Sm%21th&id=J+mes&id=foo=bar", result) + + result, err = StyleParam("form", false, url.QueryEscape, "id", unescapedArray) + assert.NoError(t, err) + assert.EqualValues(t, "id=test%3F,Sm%21th,J%2Bmes,foo%3Dbar", result) + + result, err = StyleParam("form", true, url.QueryEscape, "id", unescapedArray) + assert.NoError(t, err) + assert.EqualValues(t, "id=test%3F&id=Sm%21th&id=J%2Bmes&id=foo%3Dbar", result) + + result, err = StyleParam("form", false, escapePassThrough, "id", object) assert.NoError(t, err) assert.EqualValues(t, "id=firstName,Alex,role,admin", result) - result, err = StyleParam("form", true, "id", object) + result, err = StyleParam("form", true, escapePassThrough, "id", object) assert.NoError(t, err) assert.EqualValues(t, "firstName=Alex&role=admin", result) @@ -168,27 +355,58 @@ func TestStyleParam(t *testing.T) { result, err = StyleParam("form", true, "id", dict) assert.NoError(t, err) assert.EqualValues(t, "firstName=Alex&role=admin", result) + result, err = StyleParam("form", false, url.PathEscape, "id", unescapedObject) + assert.NoError(t, err) + assert.EqualValues(t, "id=firstName,Al=x,role,adm%3Bn", result) + + result, err = StyleParam("form", true, url.PathEscape, "id", unescapedObject) + assert.NoError(t, err) + assert.EqualValues(t, "firstName=Al=x&role=adm%3Bn", result) + + result, err = StyleParam("form", false, url.QueryEscape, "id", unescapedObject) + assert.NoError(t, err) + assert.EqualValues(t, "id=firstName,Al%3Dx,role,adm%3Bn", result) + + result, err = StyleParam("form", true, url.QueryEscape, "id", unescapedObject) + assert.NoError(t, err) + assert.EqualValues(t, "firstName=Al%3Dx&role=adm%3Bn", result) // ------------------------ spaceDelimited Style -------------------------- - result, err = StyleParam("spaceDelimited", false, "id", primitive) + _, err = StyleParam("spaceDelimited", false, escapePassThrough, "id", primitive) assert.Error(t, err) - result, err = StyleParam("spaceDelimited", true, "id", primitive) + _, err = StyleParam("spaceDelimited", true, escapePassThrough, "id", primitive) assert.Error(t, err) - result, err = StyleParam("spaceDelimited", false, "id", array) + result, err = StyleParam("spaceDelimited", false, escapePassThrough, "id", array) assert.NoError(t, err) assert.EqualValues(t, "id=3 4 5", result) - result, err = StyleParam("spaceDelimited", true, "id", array) + result, err = StyleParam("spaceDelimited", true, escapePassThrough, "id", array) assert.NoError(t, err) assert.EqualValues(t, "id=3&id=4&id=5", result) - result, err = StyleParam("spaceDelimited", false, "id", object) + result, err = StyleParam("spaceDelimited", false, url.PathEscape, "id", unescapedArray) + assert.NoError(t, err) + assert.EqualValues(t, "id=test%3F Sm%21th J+mes foo=bar", result) + + result, err = StyleParam("spaceDelimited", true, url.PathEscape, "id", unescapedArray) + assert.NoError(t, err) + assert.EqualValues(t, "id=test%3F&id=Sm%21th&id=J+mes&id=foo=bar", result) + + result, err = StyleParam("spaceDelimited", false, url.QueryEscape, "id", unescapedArray) + assert.NoError(t, err) + assert.EqualValues(t, "id=test%3F Sm%21th J%2Bmes foo%3Dbar", result) + + result, err = StyleParam("spaceDelimited", true, url.QueryEscape, "id", unescapedArray) + assert.NoError(t, err) + assert.EqualValues(t, "id=test%3F&id=Sm%21th&id=J%2Bmes&id=foo%3Dbar", result) + + _, err = StyleParam("spaceDelimited", false, escapePassThrough, "id", object) assert.Error(t, err) - result, err = StyleParam("spaceDelimited", true, "id", object) + _, err = StyleParam("spaceDelimited", true, escapePassThrough, "id", object) assert.Error(t, err) result, err = StyleParam("spaceDelimited", false, "id", dict) @@ -198,24 +416,40 @@ func TestStyleParam(t *testing.T) { assert.Error(t, err) // ------------------------- pipeDelimited Style -------------------------- - result, err = StyleParam("pipeDelimited", false, "id", primitive) + _, err = StyleParam("pipeDelimited", false, escapePassThrough, "id", primitive) assert.Error(t, err) - result, err = StyleParam("pipeDelimited", true, "id", primitive) + _, err = StyleParam("pipeDelimited", true, escapePassThrough, "id", primitive) assert.Error(t, err) - result, err = StyleParam("pipeDelimited", false, "id", array) + result, err = StyleParam("pipeDelimited", false, escapePassThrough, "id", array) assert.NoError(t, err) assert.EqualValues(t, "id=3|4|5", result) - result, err = StyleParam("pipeDelimited", true, "id", array) + result, err = StyleParam("pipeDelimited", true, escapePassThrough, "id", array) assert.NoError(t, err) assert.EqualValues(t, "id=3&id=4&id=5", result) - result, err = StyleParam("pipeDelimited", false, "id", object) + result, err = StyleParam("pipeDelimited", false, url.PathEscape, "id", unescapedArray) + assert.NoError(t, err) + assert.EqualValues(t, "id=test%3F|Sm%21th|J+mes|foo=bar", result) + + result, err = StyleParam("pipeDelimited", true, url.PathEscape, "id", unescapedArray) + assert.NoError(t, err) + assert.EqualValues(t, "id=test%3F&id=Sm%21th&id=J+mes&id=foo=bar", result) + + result, err = StyleParam("pipeDelimited", false, url.QueryEscape, "id", unescapedArray) + assert.NoError(t, err) + assert.EqualValues(t, "id=test%3F|Sm%21th|J%2Bmes|foo%3Dbar", result) + + result, err = StyleParam("pipeDelimited", true, url.QueryEscape, "id", unescapedArray) + assert.NoError(t, err) + assert.EqualValues(t, "id=test%3F&id=Sm%21th&id=J%2Bmes&id=foo%3Dbar", result) + + _, err = StyleParam("pipeDelimited", false, escapePassThrough, "id", object) assert.Error(t, err) - result, err = StyleParam("pipeDelimited", true, "id", object) + _, err = StyleParam("pipeDelimited", true, escapePassThrough, "id", object) assert.Error(t, err) result, err = StyleParam("pipeDelimited", false, "id", dict) @@ -225,43 +459,50 @@ func TestStyleParam(t *testing.T) { assert.Error(t, err) // --------------------------- deepObject Style --------------------------- - result, err = StyleParam("deepObject", false, "id", primitive) + _, err = StyleParam("deepObject", false, escapePassThrough, "id", primitive) assert.Error(t, err) - result, err = StyleParam("deepObject", true, "id", primitive) + _, err = StyleParam("deepObject", true, escapePassThrough, "id", primitive) assert.Error(t, err) - result, err = StyleParam("deepObject", false, "id", array) + _, err = StyleParam("deepObject", false, escapePassThrough, "id", array) assert.Error(t, err) - result, err = StyleParam("deepObject", true, "id", array) + _, err = StyleParam("deepObject", true, escapePassThrough, "id", array) assert.Error(t, err) - result, err = StyleParam("deepObject", false, "id", object) + _, err = StyleParam("deepObject", false, escapePassThrough, "id", object) assert.Error(t, err) - result, err = StyleParam("deepObject", true, "id", object) + result, err = StyleParam("deepObject", true, escapePassThrough, "id", object) assert.NoError(t, err) assert.EqualValues(t, "id[firstName]=Alex&id[role]=admin", result) result, err = StyleParam("deepObject", true, "id", dict) assert.NoError(t, err) assert.EqualValues(t, "id[firstName]=Alex&id[role]=admin", result) + result, err = StyleParam("deepObject", true, url.PathEscape, "id", unescapedObject) + assert.NoError(t, err) + assert.EqualValues(t, "id[firstName]=Al=x&id[role]=adm%3Bn", result) + + result, err = StyleParam("deepObject", true, url.QueryEscape, "id", unescapedObject) + assert.NoError(t, err) + assert.EqualValues(t, "id[firstName]=Al%3Dx&id[role]=adm%3Bn", result) // Misc tests // Test type aliases type StrType string - result, err = StyleParam("simple", false, "foo", StrType("test")) + result, err = StyleParam("simple", false, escapePassThrough, "foo", StrType("test")) assert.NoError(t, err) assert.EqualValues(t, "test", result) type IntType int32 - result, err = StyleParam("simple", false, "foo", IntType(7)) + result, err = StyleParam("simple", false, escapePassThrough, "foo", IntType(7)) assert.NoError(t, err) assert.EqualValues(t, "7", result) type FloatType float64 - result, err = StyleParam("simple", false, "foo", FloatType(7.5)) + result, err = StyleParam("simple", false, escapePassThrough, "foo", FloatType(7.5)) assert.NoError(t, err) assert.EqualValues(t, "7.5", result) @@ -276,13 +517,13 @@ func TestStyleParam(t *testing.T) { FirstName: &name, Role: &role, } - result, err = StyleParam("simple", false, "id", object2) + result, err = StyleParam("simple", false, escapePassThrough, "id", object2) assert.NoError(t, err) assert.EqualValues(t, "firstName,Alex,role,admin", result) // Nullable fields need to be excluded when null object2.Role = nil - result, err = StyleParam("simple", false, "id", object2) + result, err = StyleParam("simple", false, escapePassThrough, "id", object2) assert.NoError(t, err) assert.EqualValues(t, "firstName,Alex", result) } diff --git a/pkg/types/date_test.go b/pkg/types/date_test.go index 1369b1c4f..18bfd4b98 100644 --- a/pkg/types/date_test.go +++ b/pkg/types/date_test.go @@ -11,7 +11,7 @@ import ( func TestDate_MarshalJSON(t *testing.T) { testDate := time.Date(2019, 4, 1, 0, 0, 0, 0, time.UTC) b := struct { - DateField Date `json:"date"` + DateField Date `json:"date"` }{ DateField: Date{testDate}, } @@ -24,7 +24,7 @@ func TestDate_UnmarshalJSON(t *testing.T) { testDate := time.Date(2019, 4, 1, 0, 0, 0, 0, time.UTC) jsonStr := `{"date":"2019-04-01"}` b := struct { - DateField Date `json:"date"` + DateField Date `json:"date"` }{} err := json.Unmarshal([]byte(jsonStr), &b) assert.NoError(t, err) diff --git a/pkg/util/loader.go b/pkg/util/loader.go index 318342a6d..dbc814365 100644 --- a/pkg/util/loader.go +++ b/pkg/util/loader.go @@ -1,16 +1,19 @@ package util import ( + "crypto/tls" "encoding/json" "fmt" "io/ioutil" + "net/http" + "net/url" "path/filepath" "strings" "github.com/getkin/kin-openapi/openapi3" ) -func LoadSwagger(filePath string) (*openapi3.Swagger, error) { +func LoadSwagger(filePath string, allowRefs bool, insecure bool, clearRefs bool) (*openapi3.Swagger, error) { data, err := ioutil.ReadFile(filePath) if err != nil { return nil, err @@ -21,7 +24,12 @@ func LoadSwagger(filePath string) (*openapi3.Swagger, error) { ext = strings.ToLower(ext) switch ext { case ".yaml", ".yml": - swagger, err = openapi3.NewSwaggerLoader().LoadSwaggerFromData(data) + sl := openapi3.NewSwaggerLoader(openapi3.WithClearResolvedRefs(clearRefs)) + sl.IsExternalRefsAllowed = allowRefs + if insecure { + sl.LoadSwaggerFromURIFunc = insecureReadUrl + } + swagger, err = sl.LoadSwaggerFromFile(filePath) case ".json": swagger = &openapi3.Swagger{} err = json.Unmarshal(data, swagger) @@ -33,3 +41,58 @@ func LoadSwagger(filePath string) (*openapi3.Swagger, error) { } return swagger, nil } + +func LoadSwaggerFromURL(url *url.URL, allowRefs, insecure bool) (*openapi3.Swagger, error) { + var err error + var swagger *openapi3.Swagger + + ext := filepath.Ext(url.Path) + ext = strings.ToLower(ext) + switch ext { + case ".yaml", ".yml": + sl := openapi3.NewSwaggerLoader() + sl.IsExternalRefsAllowed = allowRefs + if insecure { + sl.LoadSwaggerFromURIFunc = insecureReadUrl + } + swagger, err = sl.LoadSwaggerFromURI(url) + + // enable support for loading remote JSON files later + //case ".json": + // swagger = &openapi3.Swagger{} + // err = json.Unmarshal(data, swagger) + default: + return nil, fmt.Errorf("%s is not a supported extension, use .yaml, .yml when specifying remote schemas", ext) + } + if err != nil { + return nil, err + } + return swagger, nil +} + +func insecureReadUrl(sl *openapi3.SwaggerLoader, location *url.URL) (*openapi3.Swagger, error) { + if location.Scheme != "" && location.Host != "" { + tr := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + cl := &http.Client{Transport: tr} + resp, err := cl.Get(location.String()) + if err != nil { + return nil, err + } + data, err := ioutil.ReadAll(resp.Body) + defer resp.Body.Close() + if err != nil { + return nil, err + } + return sl.LoadSwaggerFromDataWithPath(data, location) + } + if location.Scheme != "" || location.Host != "" || location.RawQuery != "" { + return nil, fmt.Errorf("Unsupported URI: '%s'", location.String()) + } + data, err := ioutil.ReadFile(location.Path) + if err != nil { + return nil, err + } + return sl.LoadSwaggerFromDataWithPath(data, location) +}