diff --git a/README.md b/README.md
index 295edf35a1..572c8b3458 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,4 @@
-OpenAPI Client and Server Code Generator
-----------------------------------------
+## OpenAPI Client and Server Code Generator
⚠️ This README may be for the latest development version, which may contain
unreleased changes. Please ensure you're looking at the README for the latest
@@ -16,7 +15,8 @@ you can focus on implementing the business logic for your service.
We have chosen to focus on [Echo](https://github.com/labstack/echo) as
our default HTTP routing engine, due to its speed and simplicity for the generated
-stubs, and [Chi](https://github.com/go-chi/chi), and [Gin](https://github.com/gin-gonic/gin)
+stubs. [Chi](https://github.com/go-chi/chi), [Gin](https://github.com/gin-gonic/gin),
+[gorilla/mux](https://github.com/gorilla/mux), and [Fiber](https://github.com/gofiber/fiber)
have also been added by contributors as additional routers. We chose Echo because
the `Context` object is a mockable interface, and it allows for some advanced
testing.
@@ -40,17 +40,17 @@ into objects which match the OpenAPI 3.0 definition. The code generator in this
directory does a lot of that for you. You would run it like so:
go install github.com/deepmap/oapi-codegen/cmd/oapi-codegen@latest
- oapi-codegen petstore-expanded.yaml > petstore.gen.go
+ oapi-codegen -package petstore petstore-expanded.yaml > petstore.gen.go
Let's go through that `petstore.gen.go` file to show you everything which was
generated.
-
## Generated Server Boilerplate
The `/components/schemas` section in OpenAPI defines reusable objects, so Go
types are generated for these. The Pet Store example defines `Error`, `Pet`,
`Pets` and `NewPet`, so we do the same in Go:
+
```go
// Error defines model for Error.
type Error struct {
@@ -121,11 +121,12 @@ will be passed as arguments to your function, since they are mandatory.
Remaining arguments can be passed in headers, query arguments or cookies. Those
will be written to a `params` object. Look at the `FindPets` function above, it
takes as input `FindPetsParams`, which is defined as follows:
- ```go
+
+```go
// Parameters object for FindPets
type FindPetsParams struct {
- Tags *[]string `json:"tags,omitempty"`
- Limit *int32 `json:"limit,omitempty"`
+ Tags *[]string `json:"tags,omitempty"`
+ Limit *int32 `json:"limit,omitempty"`
}
```
@@ -135,6 +136,7 @@ specified, the pointer will be non-`nil`, and you can read its value.
If you changed the OpenAPI specification to make the parameter required, the
`FindPetsParams` structure will contain the type by value:
+
```go
type FindPetsParams struct {
Tags *[]string `json:"tags,omitempty"`
@@ -143,6 +145,7 @@ type FindPetsParams struct {
```
### Registering handlers
+
There are a few ways of registering your http handler based on the type of server generated i.e. `-generate server` or `-generate chi-server`
Echo
@@ -152,6 +155,7 @@ Code generated using `-generate server`.
The usage of `Echo` is out of scope of this doc, but once you have an
echo instance, we generate a utility function to help you associate your handlers
with this autogenerated code. For the pet store, it looks like this:
+
```go
func RegisterHandlers(router codegen.EchoRouter, si ServerInterface) {
wrapper := ServerInterfaceWrapper{
@@ -168,6 +172,7 @@ The wrapper functions referenced above contain generated code which pulls
parameters off the `Echo` request context, and unmarshals them into Go objects.
You would register the generated handlers as follows:
+
```go
func SetupHandler() {
var myApi PetStoreImpl // This implements the pet store interface
@@ -196,6 +201,7 @@ func SetupHandler() {
r.Mount("/", Handler(&myApi))
}
```
+
Gin
@@ -205,6 +211,7 @@ Code generated using `-generate gin`.
The usage of `gin` is out of scope of this doc, but once you have an
gin instance, we generate a utility function to help you associate your handlers
with this autogenerated code. For the pet store, it looks like this:
+
```go
// RegisterHandlersWithOptions creates http.Handler with additional options
func RegisterHandlersWithOptions(router *gin.Engine, si ServerInterface, options GinServerOptions) *gin.Engine {
@@ -241,6 +248,7 @@ func SetupHandler() {
r = api.RegisterHandlers(r, petStore)
}
```
+
net/http
@@ -266,8 +274,8 @@ Alternatively, [Gorilla](https://github.com/gorilla/mux) is also 100% compatible
#### Strict server generation
-oapi-codegen also supports generating RPC inspired strict server, that will parse request bodies and encode responses.
-The main points of this code is to automate some parsing, abstract user code from server specific code,
+oapi-codegen also supports generating RPC inspired strict server, that will parse request bodies and encode responses.
+The main points of this code is to automate some parsing, abstract user code from server specific code,
and also to force user code to comply with the schema.
It supports binding of `application/json` and `application/x-www-form-urlencoded` to a struct, for `multipart` requests
it generates a `multipart.Reader`, which can be used to either manually iterating over parts or using `runtime.BindMultipart`
@@ -279,6 +287,7 @@ Content-Type header, status code and will marshal the response data. You can als
cause an `Internal Server Error` response.
Short example:
+
```go
type PetStoreImpl struct {}
func (*PetStoreImpl) GetPets(ctx context.Context, request GetPetsRequestObject) (GetPetsResponseObject, error) {
@@ -287,10 +296,12 @@ func (*PetStoreImpl) GetPets(ctx context.Context, request GetPetsRequestObject)
return GetPets200JSONResponse(result), nil
}
```
-For a complete example see `/examples/petstore-expanded/strict`.
+
+For a complete example see [`examples/petstore-expanded/strict`](https://github.com/deepmap/oapi-codegen/tree/master/examples/petstore-expanded/strict).
Code is generated with a configuration flag `generate: strict-server: true` along with any other server (echo, chi, gin and gorilla are supported).
The generated strict wrapper can then be used as an implementation for `ServerInterface`. Setup example:
+
```go
func SetupHandler() {
var myApi PetStoreImpl
@@ -317,20 +328,22 @@ defaults to `false` and we don't generate this boilerplate. If you would like
an object to accept `additionalProperties`, specify a schema for `additionalProperties`.
Say we declared `NewPet` above like so:
+
```yaml
- NewPet:
- required:
- - name
- properties:
- name:
- type: string
- tag:
- type: string
- additionalProperties:
- type: string
+NewPet:
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ tag:
+ type: string
+ additionalProperties:
+ type: string
```
The Go code for `NewPet` would now look like this:
+
```go
// NewPet defines model for NewPet.
type NewPet struct {
@@ -342,6 +355,7 @@ type NewPet struct {
The additionalProperties, of type `string` become `map[string]string`, which maps
field names to instances of the `additionalProperties` schema.
+
```go
// Getter for additional properties for NewPet. Returns the specified
// element and whether it was found
@@ -359,23 +373,25 @@ func (a NewPet) MarshalJSON() ([]byte, error) {...}w
There are many special cases for `additionalProperties`, such as having to
define types for inner fields which themselves support additionalProperties, and
-all of them are tested via the `internal/test/components` schemas and tests. Please
+all of them are tested via the [`internal/test/components`](https://github.com/deepmap/oapi-codegen/tree/master/internal/test/components) schemas and tests. Please
look through those tests for more usage examples.
#### oneOf/anyOf/allOf support
- `oneOf` and `anyOf` are implemented using delayed parsing with the help of `json.RawMessage`.
-The following schema will result in a type that has methods such as `AsCat`, `AsDog`, `FromCat`, `FromDog`, `MergeCat`, `MergeDog`. If the schema also includes a discriminator the generated code will also have methods such as `Discriminator`, `ValueByDiscriminator` and will force discriminator value in `From` methods.
+ The following schema will result in a type that has methods such as `AsCat`, `AsDog`, `FromCat`, `FromDog`, `MergeCat`, `MergeDog`. If the schema also includes a discriminator the generated code will also have methods such as `Discriminator`, `ValueByDiscriminator` and will force discriminator value in `From` methods.
+
```yaml
schema:
oneOf:
- $ref: '#/components/schemas/Cat'
- $ref: '#/components/schemas/Dog'
```
+
- `allOf` is supported, by taking the union of all the fields in all the
- component schemas. This is the most useful of these operations, and is
- commonly used to merge objects with an identifier, as in the
- `petstore-expanded` example.
+ component schemas. This is the most useful of these operations, and is
+ commonly used to merge objects with an identifier, as in the
+ `petstore-expanded` example.
## Generated Client Boilerplate
@@ -427,21 +443,21 @@ takes the same arguments. It's difficult to handle any arbitrary body that
Swagger supports, so we've done some special casing for bodies, and you may get
more than one function for an operation with a request body.
-1) If you have more than one request body type, meaning more than one media
- type, you will have a generic handler of this form:
+1. If you have more than one request body type, meaning more than one media
+ type, you will have a generic handler of this form:
- AddPet(ctx context.Context, contentType string, body io.Reader)
+ AddPet(ctx context.Context, contentType string, body io.Reader)
-2) If you have only a JSON request body, you will get:
+2. If you have only a JSON request body, you will get:
- AddPet(ctx context.Context, body NewPet)
+ AddPet(ctx context.Context, body NewPet)
-3) If you have multiple request body types, which include a JSON type you will
- get two functions. We've chosen to give the JSON version a shorter name, as
- we work with JSON and don't want to wear out our keyboards.
+3. If you have multiple request body types, which include a JSON type you will
+ get two functions. We've chosen to give the JSON version a shorter name, as
+ we work with JSON and don't want to wear out our keyboards.
- AddPet(ctx context.Context, body NewPet)
- AddPetWithBody(ctx context.Context, contentType string, body io.Reader)
+ AddPet(ctx context.Context, body NewPet)
+ AddPetWithBody(ctx context.Context, contentType string, body io.Reader)
The Client object above is fairly flexible, since you can pass in your own
`http.Client` and a request editing callback. You can use that callback to add
@@ -473,30 +489,30 @@ will correspond to your request schema. They map one-to-one to the functions on
the client, except that we always generate the generic non-JSON body handler.
There are some caveats to using this code.
+
- exploded, form style query arguments, which are the default argument format
- in OpenAPI 3.0 are undecidable. Say that I have two objects, one composed of
- the fields `(name=bob, id=5)` and another which has `(name=shoe, color=brown)`.
- The first parameter is named `person` and the second is named `item`. The
- default marshaling style for query args would result in
- `/path/?name=bob,id=5&name=shoe,color=brown`. In order to tell what belongs
- to which object, we'd have to look at all the parameters and try to deduce it,
- but we're lazy, so we didn't. Don't use exploded form style arguments if
- you're passing around objects which have similar field names. If you
- used unexploded form parameters, you'd have
- `/path/?person=name,bob,id,5&item=name,shoe,color,brown`, which an be
- parsed unambiguously.
+ in OpenAPI 3.0 are undecidable. Say that I have two objects, one composed of
+ the fields `(name=bob, id=5)` and another which has `(name=shoe, color=brown)`.
+ The first parameter is named `person` and the second is named `item`. The
+ default marshaling style for query args would result in
+ `/path/?name=bob,id=5&name=shoe,color=brown`. In order to tell what belongs
+ to which object, we'd have to look at all the parameters and try to deduce it,
+ but we're lazy, so we didn't. Don't use exploded form style arguments if
+ you're passing around objects which have similar field names. If you
+ used unexploded form parameters, you'd have
+ `/path/?person=name,bob,id,5&item=name,shoe,color,brown`, which an be
+ parsed unambiguously.
- Parameters can be defined via `schema` or via `content`. Use the `content` form
- for anything other than trivial objects, they can marshal to arbitrary JSON
- structures. When you send them as cookie (`in: cookie`) arguments, we will
- URL encode them, since JSON delimiters aren't allowed in cookies.
+ for anything other than trivial objects, they can marshal to arbitrary JSON
+ structures. When you send them as cookie (`in: cookie`) arguments, we will
+ URL encode them, since JSON delimiters aren't allowed in cookies.
## Using SecurityProviders
If you generate client-code, you can use some default-provided security providers
which help you to use the various OpenAPI 3 Authentication mechanism.
-
```go
import (
"github.com/deepmap/oapi-codegen/pkg/securityprovider"
@@ -556,54 +572,63 @@ which help you to use the various OpenAPI 3 Authentication mechanism.
will override any default value. This extended property isn't supported in all parts of
OpenAPI, so please refer to the spec as to where it's allowed. Swagger validation tools will
flag incorrect usage of this property.
+- `x-go-type-name`: This property allows for assigning a Go type name to some part of a schema,
+ such as generating a type name for an anonymous object inside another object, or renaming
+ an enum. It differs from `x-go-type`, in that it doesn't completely replace some type reference,
+ but simply names it.
- `x-go-json-ignore`: sets tag to `-` to ignore the field in json completely.
- `x-oapi-codegen-extra-tags`: adds extra Go field tags to the generated struct field. This is
useful for interfacing with tag based ORM or validation libraries. The extra tags that
- are added are in addition to the regular json tags that are generated. If you specify your
- own `json` tag, you will override the default one.
-
- ```yaml
- components:
- schemas:
- Object:
- properties:
- name:
- type: string
- x-oapi-codegen-extra-tags:
- tag1: value1
- tag2: value2
- ```
- In the example above, field `name` will be declared as:
-
+ are added are in addition to the regular json tags that are generated. If you specify your
+ own `json` tag, you will override the default one.
+
+ ```yaml
+ components:
+ schemas:
+ Object:
+ properties:
+ name:
+ type: string
+ x-oapi-codegen-extra-tags:
+ tag1: value1
+ tag2: value2
+ ```
+
+ In the example above, field `name` will be declared as:
+
```
Name string `json:"name" tag1:"value1" tag2:"value2"`
```
+
- `x-go-type-import`: adds extra Go imports to your generated code. It can help you, when you want to
- choose your own import package for `x-go-type`.
+ choose your own import package for `x-go-type`.
```yaml
- schemas:
- Pet:
- properties:
- age:
- x-go-type: myuuid.UUID
- x-go-type-import:
- name: myuuid
- path: github.com/google/uuid
+ schemas:
+ Pet:
+ properties:
+ age:
+ x-go-type: myuuid.UUID
+ x-go-type-import:
+ name: myuuid
+ path: github.com/google/uuid
```
+
After code generation you will get this:
+
```go
import (
...
myuuid "github.com/google/uuid"
)
-
+
//Pet defines model for Pet.
type Pet struct {
Age *myuuid.UUID `json:"age,omitempty"`
}
```
+
`name` is an optional parameter. Example:
```yaml
@@ -623,15 +648,44 @@ which help you to use the various OpenAPI 3 Authentication mechanism.
```go
import (
- "github.com/google/uuid"
+ "github.com/google/uuid"
)
// Pet defines model for Pet.
type Pet struct {
- Age uuid.UUID `json:"age"`
+ Age uuid.UUID `json:"age"`
}
```
+- `x-enum-varnames`: supplies other enum names for the corresponding values. (alias: `x-enumNames`)
+
+ ```yaml
+ components:
+ schemas:
+ Object:
+ properties:
+ category:
+ type: integer
+ enum: [0, 1, 2]
+ x-enum-varnames:
+ - notice
+ - warning
+ - urgent
+ ```
+
+ After code generation you will get this result:
+
+ ```go
+ // Defines values for ObjectCategory.
+ const (
+ Notice ObjectCategory = 0
+ Urgent ObjectCategory = 2
+ Warning ObjectCategory = 1
+ )
+
+ // ObjectCategory defines model for Object.Category.
+ type ObjectCategory int
+ ```
## Using `oapi-codegen`
@@ -641,23 +695,25 @@ those via the `-generate` flag. It defaults to `types,client,server,spec`, but
you can specify any combination of those.
- `types`: generate all type definitions for all types in the OpenAPI spec. This
- will be everything under `#components`, as well as request parameter, request
- body, and response type objects.
+ will be everything under `#components`, as well as request parameter, request
+ body, and response type objects.
- `server`: generate the Echo server boilerplate. `server` requires the types in the
- same package to compile.
+ same package to compile.
- `chi-server`: generate the Chi server boilerplate. This code is dependent on
- that produced by the `types` target.
+ that produced by the `types` target.
+- `fiber`: generate the Fiber server boilerplate. This code is dependent
+ on that produced by the `types` target.
- `client`: generate the client boilerplate. It, too, requires the types to be
- present in its package.
+ present in its package.
- `spec`: embed the OpenAPI spec into the generated code as a gzipped blob.
This is then usable with the `OapiRequestValidator`, or to be used by other
methods that need access to the parsed OpenAPI specification
- `skip-fmt`: skip running `goimports` on the generated code. This is useful for debugging
- the generated file in case the spec contains weird strings.
+ the generated file in case the spec contains weird strings.
- `skip-prune`: skip pruning unused components from the spec prior to generating
- the code.
+ the code.
- `import-mapping`: specifies a map of references external OpenAPI specs to go
- Go include paths. Please see below.
+ Go include paths. Please see below.
So, for example, if you would like to produce only the server code, you could
run `oapi-codegen -generate types,server`. You could generate `types` and
@@ -682,7 +738,7 @@ them pretty unwieldy, so you can specify all of the options in a configuration
file via the `--config` option. Please see the test under
[`/internal/test/externalref/`](https://github.com/deepmap/oapi-codegen/blob/master/internal/test/externalref/externalref.cfg.yaml)
for an example. The structure of the file is as follows:
-
+
```yaml
package: externalref
generate:
@@ -696,7 +752,7 @@ output-options:
skip-prune: true
```
-Have a look at [`cmd/oapi-codegen/oapi-codegen.go`](https://github.com/deepmap/oapi-codegen/blob/master/cmd/oapi-codegen/oapi-codegen.go#L48)
+Have a look at [`cmd/oapi-codegen/oapi-codegen.go`](https://github.com/deepmap/oapi-codegen/blob/master/cmd/oapi-codegen/oapi-codegen.go#L48)
to see all the fields on the configuration structure.
### Import Mappings
@@ -727,10 +783,9 @@ This code is still young, and not complete, since we're filling it in as we
need it. We've not yet implemented several things:
- `patternProperties` isn't yet supported and will exit with an error. Pattern
- properties were defined in JSONSchema, and the `kin-openapi` Swagger object
- knows how to parse them, but they're not part of OpenAPI 3.0, so we've left
- them out, as support is very complicated.
-
+ properties were defined in JSONSchema, and the `kin-openapi` Swagger object
+ knows how to parse them, but they're not part of OpenAPI 3.0, so we've left
+ them out, as support is very complicated.
## Making changes to code generation
@@ -745,7 +800,7 @@ All this command does is inline the files ending in `.tmpl` into the specified
Go file.
Afterwards you should run `go generate ./...`, and the templates will be updated
- accordingly.
+accordingly.
Alternatively, you can provide custom templates to override built-in ones using
the `-templates` flag specifying a path to a directory containing templates
@@ -760,3 +815,55 @@ on-the-fly at run time. Example:
-templates my-templates/ \
-generate types,client \
petstore-expanded.yaml
+
+When using the configuration file, it is possible to provide templates directly
+as text, as a local path, or as a URL. If the data provided to the
+configuration file is more than one line, the local path and URL checks will be
+ignored and will be treated as raw template text. If one line, the string
+will be used to check for a local file, followed by checking performing a HTTP
+GET request. If the file lookup returns any error other than not found, or the
+HTTP request returns a non 200 response code, the generator will error.
+
+⚠️ Warning: If using urls that tracks against git repositories such as
+`raw.githubusercontent.com`, it is strongly encouraged to use a tag or a hash
+instead of a branch like `main`. Tracking a branch can lead to unexpected API
+drift, and loss of the ability to reproduce a build.
+
+Examples:
+
+```yaml
+output: api.gen.go
+package: api
+output-options:
+ user-templates:
+ # using a local file
+ client-with-responses.tmpl: /home/username/workspace/templatesProject/my-client-with-responses.tmpl
+
+ # The following are referencing a versuion of the default
+ # client-with-responses.tmpl file, but loaded in through
+ # github's raw.githubusercontent.com. The general form
+ # to use raw.githubusercontent.com is as follows
+ # https://raw.githubusercontent.com////path/to/template/template.tmpl
+
+ # using raw.githubusercontent.com with a hash
+ client-with-responses.tmpl: https://raw.githubusercontent.com/deepmap/oapi-codegen/7b010099dcf1192b3bfaa3898b5f375bb9590ddf/pkg/codegen/templates/client-with-responses.tmpl
+ # using raw.githubusercontent.com with a tag
+ client-with-responses.tmpl: https://raw.githubusercontent.com/deepmap/oapi-codegen/v1.12.4/pkg/codegen/templates/client-with-responses.tmpl
+ # using raw.githubusercontent.com with a branch
+ client-with-responses.tmpl: https://raw.githubusercontent.com/deepmap/oapi-codegen/master/pkg/codegen/templates/client-with-responses.tmpl
+
+ #This example is directly embedding the template into the config file.
+ client-with-responses.tmpl: |
+ // ClientWithResponses builds on ClientInterface to offer response payloads
+ type ClientWithResponses struct {
+ ClientInterface
+ }
+ ...
+ # template shortened for brevity
+
+```
+
+Using the configuration file to load in templates **will** load in templates
+with names other than those defined by the built in templates. These user
+templates will not be called unless the user overrides a built in template to
+call them however.
diff --git a/cmd/oapi-codegen/oapi-codegen.go b/cmd/oapi-codegen/oapi-codegen.go
index 957b90fef6..ae81acfca9 100644
--- a/cmd/oapi-codegen/oapi-codegen.go
+++ b/cmd/oapi-codegen/oapi-codegen.go
@@ -17,7 +17,9 @@ import (
"flag"
"fmt"
"os"
+ "os/exec"
"path"
+ "path/filepath"
"runtime/debug"
"strings"
@@ -40,17 +42,18 @@ var (
flagPrintVersion bool
flagPackageName string
flagPrintUsage bool
+ flagGenerate string
+ flagTemplatesDir string
- // The options below are deprecated, and they will be removed in a future
+ // Deprecated: The options below will be removed in a future
// release. Please use the new config file format.
- flagGenerate string
flagIncludeTags string
flagExcludeTags string
- flagTemplatesDir string
flagImportMapping string
flagExcludeSchemas string
flagResponseTypeSuffix string
flagAliasTypes bool
+ flagInitalismOverrides bool
)
type configuration struct {
@@ -76,26 +79,27 @@ type oldConfiguration struct {
}
func main() {
- flag.StringVar(&flagOutputFile, "o", "", "Where to output generated code, stdout is default")
- flag.BoolVar(&flagOldConfigStyle, "old-config-style", false, "whether to use the older style config file format")
- flag.BoolVar(&flagOutputConfig, "output-config", false, "when true, outputs a configuration file for oapi-codegen using current settings")
- flag.StringVar(&flagConfigFile, "config", "", "a YAML config file that controls oapi-codegen behavior")
- flag.BoolVar(&flagPrintVersion, "version", false, "when specified, print version and exit")
- flag.StringVar(&flagPackageName, "package", "", "The package name for generated code")
- flag.BoolVar(&flagPrintUsage, "help", false, "show this help and exit")
- flag.BoolVar(&flagPrintUsage, "h", false, "same as -help")
+ flag.StringVar(&flagOutputFile, "o", "", "Where to output generated code, stdout is default.")
+ flag.BoolVar(&flagOldConfigStyle, "old-config-style", false, "Whether to use the older style config file format.")
+ flag.BoolVar(&flagOutputConfig, "output-config", false, "When true, outputs a configuration file for oapi-codegen using current settings.")
+ flag.StringVar(&flagConfigFile, "config", "", "A YAML config file that controls oapi-codegen behavior.")
+ flag.BoolVar(&flagPrintVersion, "version", false, "When specified, print version and exit.")
+ flag.StringVar(&flagPackageName, "package", "", "The package name for generated code.")
+ flag.BoolVar(&flagPrintUsage, "help", false, "Show this help and exit.")
+ flag.BoolVar(&flagPrintUsage, "h", false, "Same as -help.")
// All flags below are deprecated, and will be removed in a future release. Please do not
// update their behavior.
flag.StringVar(&flagGenerate, "generate", "types,client,server,spec",
- `Comma-separated list of code to generate; valid options: "types", "client", "chi-server", "server", "gin", "gorilla", "spec", "skip-fmt", "skip-prune"`)
+ `Comma-separated list of code to generate; valid options: "types", "client", "chi-server", "server", "gin", "gorilla", "spec", "skip-fmt", "skip-prune", "fiber".`)
flag.StringVar(&flagIncludeTags, "include-tags", "", "Only include operations with the given tags. Comma-separated list of tags.")
flag.StringVar(&flagExcludeTags, "exclude-tags", "", "Exclude operations that are tagged with the given tags. Comma-separated list of tags.")
- flag.StringVar(&flagTemplatesDir, "templates", "", "Path to directory containing user templates")
- flag.StringVar(&flagImportMapping, "import-mapping", "", "A dict from the external reference to golang package path")
- flag.StringVar(&flagExcludeSchemas, "exclude-schemas", "", "A comma separated list of schemas which must be excluded from generation")
- flag.StringVar(&flagResponseTypeSuffix, "response-type-suffix", "", "the suffix used for responses types")
- flag.BoolVar(&flagAliasTypes, "alias-types", false, "Alias type declarations of possible")
+ flag.StringVar(&flagTemplatesDir, "templates", "", "Path to directory containing user templates.")
+ flag.StringVar(&flagImportMapping, "import-mapping", "", "A dict from the external reference to golang package path.")
+ flag.StringVar(&flagExcludeSchemas, "exclude-schemas", "", "A comma separated list of schemas which must be excluded from generation.")
+ flag.StringVar(&flagResponseTypeSuffix, "response-type-suffix", "", "The suffix used for responses types.")
+ flag.BoolVar(&flagAliasTypes, "alias-types", false, "Alias type declarations of possible.")
+ flag.BoolVar(&flagInitalismOverrides, "initialism-overrides", false, "Use initialism overrides.")
flag.Parse()
@@ -151,7 +155,7 @@ func main() {
t := true
oldConfigStyle = &t
} else if oldErr != nil && newErr != nil {
- errExit("error parsing configuration style as old version or new version: %v\n", err)
+ errExit("error parsing configuration style as old version or new version\n\nerror when parsing using old config version:\n%v\n\nerror when parsing using new config version:\n%v\n", oldErr, newErr)
}
// Else we fall through, and we still don't know, so we need to infer it from flags.
}
@@ -162,10 +166,8 @@ func main() {
// config style. It should work correctly if we go down the old path,
// even if we have a simple config file readable as both types.
deprecatedFlagNames := map[string]bool{
- "generate": true,
"include-tags": true,
"exclude-tags": true,
- "templates": true,
"import-mapping": true,
"exclude-schemas": true,
"response-type-suffix": true,
@@ -214,9 +216,8 @@ func main() {
OutputFile: flagOutputFile,
}
}
- var err error
- opts, err = updateConfigFromFlags(opts)
- if err != nil {
+
+ if err := updateConfigFromFlags(&opts); err != nil {
errExit("error processing flags: %v\n", err)
}
} else {
@@ -238,6 +239,10 @@ func main() {
// fields.
opts.Configuration = opts.UpdateDefaults()
+ if err := detectPackageName(&opts); err != nil {
+ errExit("%s\n", err)
+ }
+
// Now, ensure that the config options are valid.
if err := opts.Validate(); err != nil {
errExit("configuration error: %v\n", err)
@@ -288,7 +293,7 @@ func loadTemplateOverrides(templatesDir string) (map[string]string, error) {
for _, f := range files {
// Recursively load subdirectory files, using the path relative to the templates
// directory as the key. This allows for overriding the files in the service-specific
- // directories (e.g. echo, chi, etc.).
+ // directories (e.g. echo, chi, fiber, etc.).
if f.IsDir() {
subFiles, err := loadTemplateOverrides(path.Join(templatesDir, f.Name()))
if err != nil {
@@ -309,52 +314,93 @@ func loadTemplateOverrides(templatesDir string) (map[string]string, error) {
return templates, nil
}
+// detectPackageName detects and sets PackageName if not already set.
+func detectPackageName(cfg *configuration) error {
+ if cfg.PackageName != "" {
+ return nil
+ }
+
+ if cfg.OutputFile != "" {
+ // Determine from the package name of the output file.
+ dir := filepath.Dir(cfg.PackageName)
+ cmd := exec.Command("go", "list", "-f", "{{.Name}}", dir)
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ outStr := string(out)
+ switch {
+ case strings.Contains(outStr, "expected 'package', found 'EOF'"):
+ // Redirecting the output to current directory which hasn't
+ // written anything yet, ignore.
+ case strings.HasPrefix(outStr, "no Go files in"):
+ // No go files yet, ignore.
+ default:
+ // Unexpected failure report.
+ return fmt.Errorf("detect package name for %q output: %q: %w", dir, string(out), err)
+ }
+ } else {
+ cfg.PackageName = string(out)
+ return nil
+ }
+ }
+
+ // Fallback to determining from the spec file name.
+ parts := strings.Split(filepath.Base(flag.Arg(0)), ".")
+ cfg.PackageName = codegen.LowercaseFirstCharacter(codegen.ToCamelCase(parts[0]))
+
+ return nil
+}
+
// updateConfigFromFlags updates a loaded configuration from flags. Flags
-// override anything in the file. We generate errors for command line options
-// associated with the old style configuration
-func updateConfigFromFlags(cfg configuration) (configuration, error) {
+// override anything in the file. We generate errors for any unsupported
+// command line flags.
+func updateConfigFromFlags(cfg *configuration) error {
if flagPackageName != "" {
cfg.PackageName = flagPackageName
}
- var unsupportedFlags []string
-
if flagGenerate != "types,client,server,spec" {
- unsupportedFlags = append(unsupportedFlags, "--generate")
+ // Override generation and output options from generate command line flag.
+ if err := generationTargets(&cfg.Configuration, util.ParseCommandLineList(flagGenerate)); err != nil {
+ return err
+ }
}
if flagIncludeTags != "" {
- unsupportedFlags = append(unsupportedFlags, "--include-tags")
+ cfg.OutputOptions.IncludeTags = util.ParseCommandLineList(flagIncludeTags)
}
if flagExcludeTags != "" {
- unsupportedFlags = append(unsupportedFlags, "--exclude-tags")
+ cfg.OutputOptions.ExcludeTags = util.ParseCommandLineList(flagExcludeTags)
}
if flagTemplatesDir != "" {
- unsupportedFlags = append(unsupportedFlags, "--templates")
+ templates, err := loadTemplateOverrides(flagTemplatesDir)
+ if err != nil {
+ return fmt.Errorf("load templates from %q: %w", flagTemplatesDir, err)
+ }
+ cfg.OutputOptions.UserTemplates = templates
}
if flagImportMapping != "" {
- unsupportedFlags = append(unsupportedFlags, "--import-mapping")
+ var err error
+ cfg.ImportMapping, err = util.ParseCommandlineMap(flagImportMapping)
+ if err != nil {
+ return err
+ }
}
if flagExcludeSchemas != "" {
- unsupportedFlags = append(unsupportedFlags, "--exclude-schemas")
+ cfg.OutputOptions.ExcludeSchemas = util.ParseCommandLineList(flagExcludeSchemas)
}
if flagResponseTypeSuffix != "" {
- unsupportedFlags = append(unsupportedFlags, "--response-type-suffix")
+ cfg.OutputOptions.ResponseTypeSuffix = flagResponseTypeSuffix
}
if flagAliasTypes {
- unsupportedFlags = append(unsupportedFlags, "--alias-types")
- }
-
- if len(unsupportedFlags) > 0 {
- return configuration{}, fmt.Errorf("flags %s aren't supported in "+
- "new config style, please use --old-config-style or update your configuration ",
- strings.Join(unsupportedFlags, ", "))
+ return fmt.Errorf("--alias-types isn't supported any more")
}
if cfg.OutputFile == "" {
cfg.OutputFile = flagOutputFile
}
- return cfg, nil
+ cfg.OutputOptions.InitialismOverrides = flagInitalismOverrides
+
+ return nil
}
// updateOldConfigFromFlags parses the flags and the config file. Anything which is
@@ -392,6 +438,42 @@ func updateOldConfigFromFlags(cfg oldConfiguration) oldConfiguration {
return cfg
}
+// generationTargets sets cfg options based on the generation targets.
+func generationTargets(cfg *codegen.Configuration, targets []string) error {
+ opts := codegen.GenerateOptions{} // Blank to start with.
+ for _, opt := range targets {
+ switch opt {
+ case "chi-server", "chi":
+ opts.ChiServer = true
+ case "fiber-server", "fiber":
+ opts.FiberServer = true
+ case "server", "echo-server", "echo":
+ opts.EchoServer = true
+ case "gin", "gin-server":
+ opts.GinServer = true
+ case "gorilla", "gorilla-server":
+ opts.GorillaServer = true
+ case "strict-server":
+ opts.Strict = true
+ case "client":
+ opts.Client = true
+ case "types", "models":
+ opts.Models = true
+ case "spec", "embedded-spec":
+ opts.EmbeddedSpec = true
+ case "skip-fmt":
+ cfg.OutputOptions.SkipFmt = true
+ case "skip-prune":
+ cfg.OutputOptions.SkipPrune = true
+ default:
+ return fmt.Errorf("unknown generate option %q", opt)
+ }
+ }
+ cfg.Generate = opts
+
+ return nil
+}
+
func newConfigFromOldConfig(c oldConfiguration) configuration {
// Take flags into account.
cfg := updateOldConfigFromFlags(c)
@@ -403,33 +485,10 @@ func newConfigFromOldConfig(c oldConfiguration) configuration {
}
opts.OutputOptions.ResponseTypeSuffix = flagResponseTypeSuffix
- for _, g := range cfg.GenerateTargets {
- switch g {
- case "client":
- opts.Generate.Client = true
- case "chi-server":
- opts.Generate.ChiServer = true
- case "server":
- opts.Generate.EchoServer = true
- case "gin":
- opts.Generate.GinServer = true
- case "gorilla":
- opts.Generate.GorillaServer = true
- case "strict-server":
- opts.Generate.Strict = true
- case "types":
- opts.Generate.Models = true
- case "spec":
- opts.Generate.EmbeddedSpec = true
- case "skip-fmt":
- opts.OutputOptions.SkipFmt = true
- case "skip-prune":
- opts.OutputOptions.SkipPrune = true
- default:
- fmt.Printf("unknown generate option %s\n", g)
- flag.PrintDefaults()
- os.Exit(1)
- }
+ if err := generationTargets(&opts, cfg.GenerateTargets); err != nil {
+ fmt.Println(err)
+ flag.PrintDefaults()
+ os.Exit(1)
}
opts.OutputOptions.IncludeTags = cfg.IncludeTags
diff --git a/examples/authenticated-api/echo/api/api.gen.go b/examples/authenticated-api/echo/api/api.gen.go
index 1433f2d5fd..1d0fcb1ff2 100644
--- a/examples/authenticated-api/echo/api/api.gen.go
+++ b/examples/authenticated-api/echo/api/api.gen.go
@@ -425,7 +425,7 @@ type ServerInterfaceWrapper struct {
func (w *ServerInterfaceWrapper) ListThings(ctx echo.Context) error {
var err error
- ctx.Set(BearerAuthScopes, []string{""})
+ ctx.Set(BearerAuthScopes, []string{})
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.ListThings(ctx)
diff --git a/examples/authenticated-api/echo/server/fake_jws.go b/examples/authenticated-api/echo/server/fake_jws.go
index 928b2dc048..0cf44e0d90 100644
--- a/examples/authenticated-api/echo/server/fake_jws.go
+++ b/examples/authenticated-api/echo/server/fake_jws.go
@@ -74,7 +74,7 @@ func (f *FakeAuthenticator) ValidateJWS(jwsString string) (jwt.Token, error) {
jwt.WithAudience(FakeAudience), jwt.WithIssuer(FakeIssuer))
}
-// SignToken takes a JWT and signs it with our priviate key, returning a JWS.
+// SignToken takes a JWT and signs it with our private key, returning a JWS.
func (f *FakeAuthenticator) SignToken(t jwt.Token) ([]byte, error) {
hdr := jws.NewHeaders()
if err := hdr.Set(jws.AlgorithmKey, jwa.ES256); err != nil {
diff --git a/examples/authenticated-api/echo/server/jwt_authenticator.go b/examples/authenticated-api/echo/server/jwt_authenticator.go
index 4d6b334abd..2c1699b304 100644
--- a/examples/authenticated-api/echo/server/jwt_authenticator.go
+++ b/examples/authenticated-api/echo/server/jwt_authenticator.go
@@ -7,6 +7,7 @@ import (
"net/http"
"strings"
+ "github.com/deepmap/oapi-codegen/pkg/middleware"
"github.com/getkin/kin-openapi/openapi3filter"
"github.com/lestrrat-go/jwx/jwt"
)
@@ -17,6 +18,8 @@ type JWSValidator interface {
ValidateJWS(jws string) (jwt.Token, error)
}
+const JWTClaimsContextKey = "jwt_claims"
+
var (
ErrNoAuthHeader = errors.New("Authorization header is missing")
ErrInvalidAuthHeader = errors.New("Authorization header is malformed")
@@ -73,6 +76,12 @@ func Authenticate(v JWSValidator, ctx context.Context, input *openapi3filter.Aut
if err != nil {
return fmt.Errorf("token claims don't match: %w", err)
}
+
+ // Set the property on the echo context so the handler is able to
+ // access the claims data we generate in here.
+ eCtx := middleware.GetEchoContext(ctx)
+ eCtx.Set(JWTClaimsContextKey, token)
+
return nil
}
diff --git a/examples/petstore-expanded/fiber/api/petstore-server.gen.go b/examples/petstore-expanded/fiber/api/petstore-server.gen.go
new file mode 100644
index 0000000000..a55486c1da
--- /dev/null
+++ b/examples/petstore-expanded/fiber/api/petstore-server.gen.go
@@ -0,0 +1,246 @@
+// Package api provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT.
+package api
+
+import (
+ "bytes"
+ "compress/gzip"
+ "encoding/base64"
+ "fmt"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/deepmap/oapi-codegen/pkg/runtime"
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/gofiber/fiber/v2"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+ // Returns all pets
+ // (GET /pets)
+ FindPets(c *fiber.Ctx, params FindPetsParams) error
+ // Creates a new pet
+ // (POST /pets)
+ AddPet(c *fiber.Ctx) error
+ // Deletes a pet by ID
+ // (DELETE /pets/{id})
+ DeletePet(c *fiber.Ctx, id int64) error
+ // Returns a pet by ID
+ // (GET /pets/{id})
+ FindPetByID(c *fiber.Ctx, id int64) error
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+}
+
+type MiddlewareFunc fiber.Handler
+
+// FindPets operation middleware
+func (siw *ServerInterfaceWrapper) FindPets(c *fiber.Ctx) error {
+
+ var err error
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params FindPetsParams
+
+ var query url.Values
+ query, err = url.ParseQuery(string(c.Request().URI().QueryString()))
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for query string: %w", err).Error())
+ }
+
+ // ------------- Optional query parameter "tags" -------------
+
+ err = runtime.BindQueryParameter("form", true, false, "tags", query, ¶ms.Tags)
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter tags: %w", err).Error())
+ }
+
+ // ------------- Optional query parameter "limit" -------------
+
+ err = runtime.BindQueryParameter("form", true, false, "limit", query, ¶ms.Limit)
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter limit: %w", err).Error())
+ }
+
+ return siw.Handler.FindPets(c, params)
+}
+
+// AddPet operation middleware
+func (siw *ServerInterfaceWrapper) AddPet(c *fiber.Ctx) error {
+
+ return siw.Handler.AddPet(c)
+}
+
+// DeletePet operation middleware
+func (siw *ServerInterfaceWrapper) DeletePet(c *fiber.Ctx) error {
+
+ var err error
+
+ // ------------- Path parameter "id" -------------
+ var id int64
+
+ err = runtime.BindStyledParameter("simple", false, "id", c.Params("id"), &id)
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter id: %w", err).Error())
+ }
+
+ return siw.Handler.DeletePet(c, id)
+}
+
+// FindPetByID operation middleware
+func (siw *ServerInterfaceWrapper) FindPetByID(c *fiber.Ctx) error {
+
+ var err error
+
+ // ------------- Path parameter "id" -------------
+ var id int64
+
+ err = runtime.BindStyledParameter("simple", false, "id", c.Params("id"), &id)
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter id: %w", err).Error())
+ }
+
+ return siw.Handler.FindPetByID(c, id)
+}
+
+// FiberServerOptions provides options for the Fiber server.
+type FiberServerOptions struct {
+ BaseURL string
+ Middlewares []MiddlewareFunc
+}
+
+// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
+func RegisterHandlers(router fiber.Router, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, FiberServerOptions{})
+}
+
+// RegisterHandlersWithOptions creates http.Handler with additional options
+func RegisterHandlersWithOptions(router fiber.Router, si ServerInterface, options FiberServerOptions) {
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ }
+
+ for _, m := range options.Middlewares {
+ router.Use(m)
+ }
+
+ router.Get(options.BaseURL+"/pets", wrapper.FindPets)
+
+ router.Post(options.BaseURL+"/pets", wrapper.AddPet)
+
+ router.Delete(options.BaseURL+"/pets/:id", wrapper.DeletePet)
+
+ router.Get(options.BaseURL+"/pets/:id", wrapper.FindPetByID)
+
+}
+
+// Base64 encoded, gzipped, json marshaled Swagger object
+var swaggerSpec = []string{
+
+ "H4sIAAAAAAAC/+RXW48budH9KwV+32OnNbEXedBTvB4vICBrT+LdvKznoYZdkmrBSw9Z1FgY6L8HRbZu",
+ "I3k2QYIgQV506WY1T51zqlj9bGz0YwwUJJv5s8l2TR7rzw8pxaQ/xhRHSsJUL9s4kH4PlG3iUTgGM2+L",
+ "od7rzDImj2LmhoO8fWM6I9uR2l9aUTK7znjKGVfffND+9iE0S+KwMrtdZxI9Fk40mPkvZtpwv/x+15mP",
+ "9HRHcok7oL+y3Uf0BHEJsiYYSS437Izg6jLup+34etwLoHV3hTdhQ+c+Lc38l2fz/4mWZm7+b3YUYjap",
+ "MJty2XUvk+HhEtLPgR8LAQ/nuE7F+MN3V8R4gZQHc7+73+llDsvYJA+CtuImj+zM3ODIQuj/mJ9wtaLU",
+ "czTdRLH53K7Bu7sF/EToTWdK0qC1yJjns9lJ0K57kcU7yOhHRzVa1ihQMmVAzSZLTASYAQPQ17ZMIgzk",
+ "Y8iSUAiWhFISZeBQOfg0UtAnve1vII9keckW61adcWwpZDqaw7wb0a4J3vQ3F5ifnp56rLf7mFazKTbP",
+ "/rR4/+Hj5w+/e9Pf9GvxrjqGks+flp8pbdjS1cRndc1M5WBxp6zdTXmazmwo5cbK7/ub/kYfHUcKOLKZ",
+ "m7f1UmdGlHX1xEwZ0h+rZrFzXv9CUlLIgM5VKmGZoq8U5W0W8o1r/V8yJVgry9ZSziDxS/iIHjINYGMY",
+ "2FOQ4oGy9PAjkqWAGYT8GBNkXLEIZ8g4MoUOAllI6xhsyZDJnyxgAfQkPbyjQBgABVYJNzwgYFkV6gAt",
+ "MNriuIb28L4kfGApCeLAEVxM5DuIKWAioBUJkKMJXSDbgS0pl6wl4chKyT3cFs7gGaSkkXMHY3EbDph0",
+ "L0pRk+5AOFgeShDYYOKS4deSJfawCLBGC2sFgTkTjA6FEAa2UrzSsWhFpbngwCNny2EFGESzOebueFUc",
+ "HjIf15hIEu5J1PXgo6MsTMB+pDSwMvVX3qBvCaHjx4IeBkZlJmGGR81tQ44FQgwgMUlMSgkvKQyH3Xu4",
+ "S0iZgihMCuyPAEoKCJvoiowosKFAARVwI1c/PJakz1iE45OXlCbWl2jZcT7bpO6gH91RXws5DuhIhR06",
+ "5dFSQtHE9LuHzyWPFAZWlh2qeYboYurUgZmsqJtrltUqmnUHG1qzLQ5BW1saigfHD5RiDz/G9MBAhbOP",
+ "w6kMersa26HlwNh/CV/CZxqqEiXDktR8Lj7EVAMoHh2TiqTie9Da8FgfOJHP2XVA5axamuTgivpQ3dnD",
+ "3RozOdcKY6Q0hVeaq7wksMRi+aE0wnG/j647jd+Qm6TjDaWE3fnWWifAQ3coxMAP6x5+FhjJOQpCWU+O",
+ "MeZCWkn7IupBqcB9FWjR7bncP2mfVmWyq0AOtgglWJDEWerBtGFB6uGHki0BSe0GQ+FDFWinyJYcJa5w",
+ "mn/3AV7dUrCaxxafMYDHlaZMblKrhz+XFuqjU92aelSad45QukPzASxWi6StnOzZ0p7MMTWZQzWqWVRg",
+ "4NAdoUyFGzjzHnBWDJalDKxQc0YosvfZJGTb6Yy0ul8Pd6fCVOYmjGMi4eJPOlczTelO/K2tt/+iZ5wO",
+ "DfW8Wwxmbn7gMOj5Uo+NpARQynUKOT8sBFfa92HJTijBw9boMGDm5rFQ2h5Pel1numlorHOJkK9n0OUU",
+ "1S5gSrjV/1m29djT8aQOOOcIPH5lr228+AdKOtEkysVJhZXqWfYNTI49yxmo3xxHd/c6AuVRW0tF/+bm",
+ "Zj/3UGjz2ji6aXKY/ZoV4vO1tF8b5tok94KI3cUANJLAHkwbj5ZYnPxDeF6D0cb6KxuXQF9Hba3ag9ua",
+ "zuTiPabtlQFCsY0xXxk13idCqTNboCddux/G6lyjZ3DDrkt0nnMuPtFwYdZ3g3rVtOmUsnwfh+2/jIX9",
+ "ZH1Jwx2JegyHQb8OsM3plCyp0O6f9MxvWuW/xxoXgtf7dR6dPfOwaxZxJFdewNp1jc0cVq6+tcADapuN",
+ "zTWLW8hFc7rikdsa3Wzyakdb3GoPGZu2E5apf+gAfWwfPFwo/a1ecv1t6rKXfHeZtQJpKIb/JCFvD2JU",
+ "FbawuFV4r79QnCt20HFx+63j5/ttvff367Ukset/m1z/s2X8QtGmfl1CabOX6fyteP9S3p+82err6e5+",
+ "97cAAAD//ykDnxlaEgAA",
+}
+
+// GetSwagger returns the content of the embedded swagger specification file
+// or error if failed to decode
+func decodeSpec() ([]byte, error) {
+ zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %s", err)
+ }
+ zr, err := gzip.NewReader(bytes.NewReader(zipped))
+ if err != nil {
+ return nil, fmt.Errorf("error decompressing spec: %s", err)
+ }
+ var buf bytes.Buffer
+ _, err = buf.ReadFrom(zr)
+ if err != nil {
+ return nil, fmt.Errorf("error decompressing spec: %s", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cached of a decoded swagger spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ var res = make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSwagger returns the Swagger specification corresponding to the generated code
+// in this file. The external references of Swagger specification are resolved.
+// The logic of resolving external references is tightly connected to "import-mapping" feature.
+// Externally referenced files must be embedded in the corresponding golang packages.
+// Urls can be supported but this task was out of the scope.
+func GetSwagger() (swagger *openapi3.T, err error) {
+ var resolvePath = PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ var pathToFile = url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
diff --git a/examples/petstore-expanded/fiber/api/petstore-types.gen.go b/examples/petstore-expanded/fiber/api/petstore-types.gen.go
new file mode 100644
index 0000000000..16bbe200cf
--- /dev/null
+++ b/examples/petstore-expanded/fiber/api/petstore-types.gen.go
@@ -0,0 +1,46 @@
+// Package api provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT.
+package api
+
+// Error defines model for Error.
+type Error struct {
+ // Code Error code
+ Code int32 `json:"code"`
+
+ // Message Error message
+ Message string `json:"message"`
+}
+
+// NewPet defines model for NewPet.
+type NewPet struct {
+ // Name Name of the pet
+ Name string `json:"name"`
+
+ // Tag Type of the pet
+ Tag *string `json:"tag,omitempty"`
+}
+
+// Pet defines model for Pet.
+type Pet struct {
+ // Id Unique id of the pet
+ Id int64 `json:"id"`
+
+ // Name Name of the pet
+ Name string `json:"name"`
+
+ // Tag Type of the pet
+ Tag *string `json:"tag,omitempty"`
+}
+
+// FindPetsParams defines parameters for FindPets.
+type FindPetsParams struct {
+ // Tags tags to filter by
+ Tags *[]string `form:"tags,omitempty" json:"tags,omitempty"`
+
+ // Limit maximum number of results to return
+ Limit *int32 `form:"limit,omitempty" json:"limit,omitempty"`
+}
+
+// AddPetJSONRequestBody defines body for AddPet for application/json ContentType.
+type AddPetJSONRequestBody = NewPet
diff --git a/examples/petstore-expanded/fiber/api/petstore.go b/examples/petstore-expanded/fiber/api/petstore.go
new file mode 100644
index 0000000000..60ecd58ff0
--- /dev/null
+++ b/examples/petstore-expanded/fiber/api/petstore.go
@@ -0,0 +1,132 @@
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=types.cfg.yaml ../../petstore-expanded.yaml
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=server.cfg.yaml ../../petstore-expanded.yaml
+
+package api
+
+import (
+ "fmt"
+ "net/http"
+ "sync"
+
+ "github.com/gofiber/fiber/v2"
+)
+
+type PetStore struct {
+ Pets map[int64]Pet
+ NextId int64
+ Lock sync.Mutex
+}
+
+// Make sure we conform to ServerInterface
+
+var _ ServerInterface = (*PetStore)(nil)
+
+func NewPetStore() *PetStore {
+
+ return &PetStore{
+ Pets: make(map[int64]Pet),
+ NextId: 1000,
+ }
+}
+
+// This function wraps sending of an error in the Error format, and
+// handling the failure to marshal that.
+func sendPetStoreError(c *fiber.Ctx, code int, message string) error {
+
+ petErr := Error{
+ Code: int32(code),
+ Message: message,
+ }
+
+ return c.Status(code).JSON(petErr)
+}
+
+// FindPets implements all the handlers in the ServerInterface
+func (p *PetStore) FindPets(c *fiber.Ctx, params FindPetsParams) error {
+
+ p.Lock.Lock()
+ defer p.Lock.Unlock()
+
+ var result []Pet
+
+ for _, pet := range p.Pets {
+ if params.Tags != nil {
+ // If we have tags, filter pets by tag
+ for _, t := range *params.Tags {
+ if pet.Tag != nil && (*pet.Tag == t) {
+ result = append(result, pet)
+ }
+ }
+ } else {
+ // Add all pets if we're not filtering
+ result = append(result, pet)
+ }
+
+ if params.Limit != nil {
+ l := int(*params.Limit)
+ if len(result) >= l {
+ // We're at the limit
+ break
+ }
+ }
+ }
+
+ return c.Status(http.StatusOK).JSON(result)
+}
+
+func (p *PetStore) AddPet(c *fiber.Ctx) error {
+
+ // We expect a NewPet object in the request body.
+ var newPet NewPet
+
+ if err := c.BodyParser(&newPet); err != nil {
+ return sendPetStoreError(c, http.StatusBadRequest, "Invalid format for NewPet")
+ }
+
+ // We now have a pet, let's add it to our "database".
+
+ // We're always asynchronous, so lock unsafe operations below
+ p.Lock.Lock()
+ defer p.Lock.Unlock()
+
+ // We handle pets, not NewPets, which have an additional ID field
+ var pet Pet
+ pet.Name = newPet.Name
+ pet.Tag = newPet.Tag
+ pet.Id = p.NextId
+ p.NextId = p.NextId + 1
+
+ // Insert into map
+ p.Pets[pet.Id] = pet
+
+ // Now, we have to return the NewPet
+ return c.Status(http.StatusCreated).JSON(pet)
+}
+
+func (p *PetStore) FindPetByID(c *fiber.Ctx, id int64) error {
+
+ p.Lock.Lock()
+ defer p.Lock.Unlock()
+
+ pet, found := p.Pets[id]
+ if !found {
+ return sendPetStoreError(c, http.StatusNotFound, fmt.Sprintf("Could not find pet with ID %d", id))
+ }
+
+ return c.Status(http.StatusOK).JSON(pet)
+}
+
+func (p *PetStore) DeletePet(c *fiber.Ctx, id int64) error {
+
+ p.Lock.Lock()
+ defer p.Lock.Unlock()
+
+ _, found := p.Pets[id]
+ if !found {
+ return sendPetStoreError(c, http.StatusNotFound, fmt.Sprintf("Could not find pet with ID %d", id))
+ }
+ delete(p.Pets, id)
+
+ c.Status(http.StatusNoContent)
+ return nil
+}
diff --git a/examples/petstore-expanded/fiber/api/server.cfg.yaml b/examples/petstore-expanded/fiber/api/server.cfg.yaml
new file mode 100644
index 0000000000..91ef1331d2
--- /dev/null
+++ b/examples/petstore-expanded/fiber/api/server.cfg.yaml
@@ -0,0 +1,5 @@
+package: api
+generate:
+ fiber-server: true
+ embedded-spec: true
+output: petstore-server.gen.go
diff --git a/examples/petstore-expanded/fiber/api/types.cfg.yaml b/examples/petstore-expanded/fiber/api/types.cfg.yaml
new file mode 100644
index 0000000000..9ac30e11e9
--- /dev/null
+++ b/examples/petstore-expanded/fiber/api/types.cfg.yaml
@@ -0,0 +1,4 @@
+package: api
+generate:
+ models: true
+output: petstore-types.gen.go
diff --git a/examples/petstore-expanded/fiber/petstore.go b/examples/petstore-expanded/fiber/petstore.go
new file mode 100644
index 0000000000..344752bbbc
--- /dev/null
+++ b/examples/petstore-expanded/fiber/petstore.go
@@ -0,0 +1,57 @@
+// This is an example of implementing the Pet Store from the OpenAPI documentation
+// found at:
+// https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "log"
+ "os"
+
+ "github.com/gofiber/fiber/v2"
+
+ "github.com/deepmap/oapi-codegen/examples/petstore-expanded/fiber/api"
+ middleware "github.com/deepmap/oapi-codegen/pkg/fiber-middleware"
+)
+
+func main() {
+
+ var port = flag.Int("port", 8080, "Port for test HTTP server")
+
+ flag.Parse()
+
+ // Create an instance of our handler which satisfies the generated interface
+ petStore := api.NewPetStore()
+
+ s := NewFiberPetServer(petStore)
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(s.Listen(fmt.Sprintf("localhost:%d", *port)))
+}
+
+func NewFiberPetServer(petStore *api.PetStore) *fiber.App {
+
+ swagger, err := api.GetSwagger()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err)
+ os.Exit(1)
+ }
+
+ // Clear out the servers array in the swagger spec, that skips validating
+ // that server names match. We don't know how this thing will be run.
+ swagger.Servers = nil
+
+ // This is how you set up a basic fiber router
+ app := fiber.New()
+
+ // Use our validation middleware to check all requests against the
+ // OpenAPI schema.
+ app.Use(middleware.OapiRequestValidator(swagger))
+
+ // We now register our petStore above as the handler for the interface
+ api.RegisterHandlers(app, petStore)
+
+ return app
+}
diff --git a/examples/petstore-expanded/fiber/petstore_test.go b/examples/petstore-expanded/fiber/petstore_test.go
new file mode 100644
index 0000000000..e6a103ace9
--- /dev/null
+++ b/examples/petstore-expanded/fiber/petstore_test.go
@@ -0,0 +1,181 @@
+package main
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "net/http/httptest"
+ "net/url"
+ "testing"
+
+ "github.com/gofiber/fiber/v2"
+ "github.com/stretchr/testify/assert"
+
+ "github.com/deepmap/oapi-codegen/examples/petstore-expanded/fiber/api"
+)
+
+func doGet(t *testing.T, app *fiber.App, rawURL string) (*http.Response, error) {
+
+ u, err := url.Parse(rawURL)
+ if err != nil {
+ t.Fatalf("Invalid url: %s", rawURL)
+ }
+
+ req := httptest.NewRequest("GET", u.RequestURI(), nil)
+ req.Header.Add("Accept", "application/json")
+ req.Host = u.Host
+
+ return app.Test(req)
+}
+
+func doPost(t *testing.T, app *fiber.App, rawURL string, jsonBody interface{}) (*http.Response, error) {
+ u, err := url.Parse(rawURL)
+ if err != nil {
+ t.Fatalf("Invalid url: %s", rawURL)
+ }
+
+ buf, err := json.Marshal(jsonBody)
+ if err != nil {
+ return nil, err
+ }
+ req := httptest.NewRequest("POST", u.RequestURI(), bytes.NewReader(buf))
+ req.Header.Add("Accept", "application/json")
+ req.Header.Add("Content-Type", "application/json")
+ req.Host = u.Host
+ return app.Test(req)
+}
+
+func doDelete(t *testing.T, app *fiber.App, rawURL string) (*http.Response, error) {
+ u, err := url.Parse(rawURL)
+ if err != nil {
+ t.Fatalf("Invalid url: %s", rawURL)
+ }
+
+ req := httptest.NewRequest("DELETE", u.RequestURI(), nil)
+ req.Header.Add("Accept", "application/json")
+ req.Host = u.Host
+ return app.Test(req)
+}
+
+func TestPetStore(t *testing.T) {
+ var err error
+ store := api.NewPetStore()
+ fiberPetServer := NewFiberPetServer(store)
+
+ t.Run("Add pet", func(t *testing.T) {
+ tag := "TagOfSpot"
+ newPet := api.NewPet{
+ Name: "Spot",
+ Tag: &tag,
+ }
+
+ rr, _ := doPost(t, fiberPetServer, "/pets", newPet)
+ assert.Equal(t, http.StatusCreated, rr.StatusCode)
+
+ var resultPet api.Pet
+ err = json.NewDecoder(rr.Body).Decode(&resultPet)
+ assert.NoError(t, err, "error unmarshaling response")
+ assert.Equal(t, newPet.Name, resultPet.Name)
+ assert.Equal(t, *newPet.Tag, *resultPet.Tag)
+ })
+
+ t.Run("Find pet by ID", func(t *testing.T) {
+ pet := api.Pet{
+ Id: 100,
+ }
+
+ store.Pets[pet.Id] = pet
+ rr, _ := doGet(t, fiberPetServer, fmt.Sprintf("/pets/%d", pet.Id))
+ assert.Equal(t, http.StatusOK, rr.StatusCode)
+
+ var resultPet api.Pet
+ err = json.NewDecoder(rr.Body).Decode(&resultPet)
+ assert.NoError(t, err, "error getting pet")
+ assert.Equal(t, pet, resultPet)
+ })
+
+ t.Run("Pet not found", func(t *testing.T) {
+ rr, _ := doGet(t, fiberPetServer, "/pets/27179095781")
+ assert.Equal(t, http.StatusNotFound, rr.StatusCode)
+
+ var petError api.Error
+ err = json.NewDecoder(rr.Body).Decode(&petError)
+ assert.NoError(t, err, "error getting response", err)
+ assert.Equal(t, int32(http.StatusNotFound), petError.Code)
+ })
+
+ t.Run("List all pets", func(t *testing.T) {
+ store.Pets = map[int64]api.Pet{1: {}, 2: {}}
+
+ // Now, list all pets, we should have two
+ rr, _ := doGet(t, fiberPetServer, "/pets")
+ assert.Equal(t, http.StatusOK, rr.StatusCode)
+
+ var petList []api.Pet
+ err = json.NewDecoder(rr.Body).Decode(&petList)
+ assert.NoError(t, err, "error getting response", err)
+ assert.Equal(t, 2, len(petList))
+ })
+
+ t.Run("Filter pets by tag", func(t *testing.T) {
+ tag := "TagOfFido"
+
+ store.Pets = map[int64]api.Pet{
+ 1: {
+ Tag: &tag,
+ },
+ 2: {},
+ }
+
+ // Filter pets by tag, we should have 1
+ rr, _ := doGet(t, fiberPetServer, "/pets?tags=TagOfFido")
+ assert.Equal(t, http.StatusOK, rr.StatusCode)
+
+ var petList []api.Pet
+ err = json.NewDecoder(rr.Body).Decode(&petList)
+ assert.NoError(t, err, "error getting response", err)
+ assert.Equal(t, 1, len(petList))
+ })
+
+ t.Run("Filter pets by tag", func(t *testing.T) {
+ store.Pets = map[int64]api.Pet{1: {}, 2: {}}
+
+ // Filter pets by non existent tag, we should have 0
+ rr, _ := doGet(t, fiberPetServer, "/pets?tags=NotExists")
+ assert.Equal(t, http.StatusOK, rr.StatusCode)
+
+ var petList []api.Pet
+ err = json.NewDecoder(rr.Body).Decode(&petList)
+ assert.NoError(t, err, "error getting response", err)
+ assert.Equal(t, 0, len(petList))
+ })
+
+ t.Run("Delete pets", func(t *testing.T) {
+ store.Pets = map[int64]api.Pet{1: {}, 2: {}}
+
+ // Let's delete non-existent pet
+ rr, _ := doDelete(t, fiberPetServer, "/pets/7")
+ assert.Equal(t, http.StatusNotFound, rr.StatusCode)
+
+ var petError api.Error
+ err = json.NewDecoder(rr.Body).Decode(&petError)
+ assert.NoError(t, err, "error unmarshaling PetError")
+ assert.Equal(t, int32(http.StatusNotFound), petError.Code)
+
+ // Now, delete both real pets
+ rr, _ = doDelete(t, fiberPetServer, "/pets/1")
+ assert.Equal(t, http.StatusNoContent, rr.StatusCode)
+
+ rr, _ = doDelete(t, fiberPetServer, "/pets/2")
+ assert.Equal(t, http.StatusNoContent, rr.StatusCode)
+
+ // Should have no pets left.
+ var petList []api.Pet
+ rr, _ = doGet(t, fiberPetServer, "/pets")
+ assert.Equal(t, http.StatusOK, rr.StatusCode)
+ err = json.NewDecoder(rr.Body).Decode(&petList)
+ assert.NoError(t, err, "error getting response", err)
+ assert.Equal(t, 0, len(petList))
+ })
+}
diff --git a/examples/petstore-expanded/gin/api/petstore-server.gen.go b/examples/petstore-expanded/gin/api/petstore-server.gen.go
index 8dabdd9e76..3b0368db57 100644
--- a/examples/petstore-expanded/gin/api/petstore-server.gen.go
+++ b/examples/petstore-expanded/gin/api/petstore-server.gen.go
@@ -69,6 +69,9 @@ func (siw *ServerInterfaceWrapper) FindPets(c *gin.Context) {
for _, middleware := range siw.HandlerMiddlewares {
middleware(c)
+ if c.IsAborted() {
+ return
+ }
}
siw.Handler.FindPets(c, params)
@@ -79,6 +82,9 @@ func (siw *ServerInterfaceWrapper) AddPet(c *gin.Context) {
for _, middleware := range siw.HandlerMiddlewares {
middleware(c)
+ if c.IsAborted() {
+ return
+ }
}
siw.Handler.AddPet(c)
@@ -100,6 +106,9 @@ func (siw *ServerInterfaceWrapper) DeletePet(c *gin.Context) {
for _, middleware := range siw.HandlerMiddlewares {
middleware(c)
+ if c.IsAborted() {
+ return
+ }
}
siw.Handler.DeletePet(c, id)
@@ -121,6 +130,9 @@ func (siw *ServerInterfaceWrapper) FindPetByID(c *gin.Context) {
for _, middleware := range siw.HandlerMiddlewares {
middleware(c)
+ if c.IsAborted() {
+ return
+ }
}
siw.Handler.FindPetByID(c, id)
@@ -134,15 +146,13 @@ type GinServerOptions struct {
}
// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
-func RegisterHandlers(router *gin.Engine, si ServerInterface) *gin.Engine {
- return RegisterHandlersWithOptions(router, si, GinServerOptions{})
+func RegisterHandlers(router gin.IRouter, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, GinServerOptions{})
}
// RegisterHandlersWithOptions creates http.Handler with additional options
-func RegisterHandlersWithOptions(router *gin.Engine, si ServerInterface, options GinServerOptions) *gin.Engine {
-
+func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options GinServerOptions) {
errorHandler := options.ErrorHandler
-
if errorHandler == nil {
errorHandler = func(c *gin.Context, err error, statusCode int) {
c.JSON(statusCode, gin.H{"msg": err.Error()})
@@ -156,14 +166,9 @@ func RegisterHandlersWithOptions(router *gin.Engine, si ServerInterface, options
}
router.GET(options.BaseURL+"/pets", wrapper.FindPets)
-
router.POST(options.BaseURL+"/pets", wrapper.AddPet)
-
router.DELETE(options.BaseURL+"/pets/:id", wrapper.DeletePet)
-
router.GET(options.BaseURL+"/pets/:id", wrapper.FindPetByID)
-
- return router
}
// Base64 encoded, gzipped, json marshaled Swagger object
diff --git a/examples/petstore-expanded/gin/petstore.go b/examples/petstore-expanded/gin/petstore.go
index 2eae15bfca..a5b40a2f4c 100644
--- a/examples/petstore-expanded/gin/petstore.go
+++ b/examples/petstore-expanded/gin/petstore.go
@@ -11,9 +11,10 @@ import (
"net/http"
"os"
+ "github.com/gin-gonic/gin"
+
"github.com/deepmap/oapi-codegen/examples/petstore-expanded/gin/api"
middleware "github.com/deepmap/oapi-codegen/pkg/gin-middleware"
- "github.com/gin-gonic/gin"
)
func NewGinPetServer(petStore *api.PetStore, port int) *http.Server {
@@ -35,7 +36,7 @@ func NewGinPetServer(petStore *api.PetStore, port int) *http.Server {
r.Use(middleware.OapiRequestValidator(swagger))
// We now register our petStore above as the handler for the interface
- r = api.RegisterHandlers(r, petStore)
+ api.RegisterHandlers(r, petStore)
s := &http.Server{
Handler: r,
diff --git a/examples/petstore-expanded/gorilla/api/cfg.yaml b/examples/petstore-expanded/gorilla/api/cfg.yaml
index 7f1a2d759c..8ead7a60de 100644
--- a/examples/petstore-expanded/gorilla/api/cfg.yaml
+++ b/examples/petstore-expanded/gorilla/api/cfg.yaml
@@ -4,3 +4,5 @@ generate:
models: true
embedded-spec: true
output: petstore.gen.go
+compatibility:
+ apply-gorilla-middleware-first-to-last: true
diff --git a/examples/petstore-expanded/gorilla/api/petstore.gen.go b/examples/petstore-expanded/gorilla/api/petstore.gen.go
index deac9824ad..b55ecd0142 100644
--- a/examples/petstore-expanded/gorilla/api/petstore.gen.go
+++ b/examples/petstore-expanded/gorilla/api/petstore.gen.go
@@ -114,8 +114,8 @@ func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Reque
siw.Handler.FindPets(w, r, params)
}
- for _, middleware := range siw.HandlerMiddlewares {
- handler = middleware(handler)
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ handler = siw.HandlerMiddlewares[i](handler)
}
handler(w, r.WithContext(ctx))
@@ -129,8 +129,8 @@ func (siw *ServerInterfaceWrapper) AddPet(w http.ResponseWriter, r *http.Request
siw.Handler.AddPet(w, r)
}
- for _, middleware := range siw.HandlerMiddlewares {
- handler = middleware(handler)
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ handler = siw.HandlerMiddlewares[i](handler)
}
handler(w, r.WithContext(ctx))
@@ -155,8 +155,8 @@ func (siw *ServerInterfaceWrapper) DeletePet(w http.ResponseWriter, r *http.Requ
siw.Handler.DeletePet(w, r, id)
}
- for _, middleware := range siw.HandlerMiddlewares {
- handler = middleware(handler)
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ handler = siw.HandlerMiddlewares[i](handler)
}
handler(w, r.WithContext(ctx))
@@ -181,8 +181,8 @@ func (siw *ServerInterfaceWrapper) FindPetByID(w http.ResponseWriter, r *http.Re
siw.Handler.FindPetByID(w, r, id)
}
- for _, middleware := range siw.HandlerMiddlewares {
- handler = middleware(handler)
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ handler = siw.HandlerMiddlewares[i](handler)
}
handler(w, r.WithContext(ctx))
diff --git a/examples/petstore-expanded/petstore-client.gen.go b/examples/petstore-expanded/petstore-client.gen.go
index 0929a64096..766135e380 100644
--- a/examples/petstore-expanded/petstore-client.gen.go
+++ b/examples/petstore-expanded/petstore-client.gen.go
@@ -225,42 +225,44 @@ func NewFindPetsRequest(server string, params *FindPetsParams) (*http.Request, e
return nil, err
}
- queryValues := queryURL.Query()
-
- if params.Tags != nil {
-
- if queryFrag, err := runtime.StyleParamWithLocation("form", true, "tags", runtime.ParamLocationQuery, *params.Tags); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
- return nil, err
- } else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
+ if params != nil {
+ queryValues := queryURL.Query()
+
+ if params.Tags != nil {
+
+ if queryFrag, err := runtime.StyleParamWithLocation("form", true, "tags", runtime.ParamLocationQuery, *params.Tags); err != nil {
+ return nil, err
+ } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ return nil, err
+ } else {
+ for k, v := range parsed {
+ for _, v2 := range v {
+ queryValues.Add(k, v2)
+ }
}
}
- }
-
- }
- if params.Limit != nil {
+ }
- if queryFrag, err := runtime.StyleParamWithLocation("form", true, "limit", runtime.ParamLocationQuery, *params.Limit); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
- return nil, err
- } else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
+ if params.Limit != nil {
+
+ if queryFrag, err := runtime.StyleParamWithLocation("form", true, "limit", runtime.ParamLocationQuery, *params.Limit); err != nil {
+ return nil, err
+ } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ return nil, err
+ } else {
+ for k, v := range parsed {
+ for _, v2 := range v {
+ queryValues.Add(k, v2)
+ }
}
}
+
}
+ queryURL.RawQuery = queryValues.Encode()
}
- queryURL.RawQuery = queryValues.Encode()
-
req, err := http.NewRequest("GET", queryURL.String(), nil)
if err != nil {
return nil, err
diff --git a/examples/petstore-expanded/strict/api/petstore-server.gen.go b/examples/petstore-expanded/strict/api/petstore-server.gen.go
index cd9352ac11..822dee72ae 100644
--- a/examples/petstore-expanded/strict/api/petstore-server.gen.go
+++ b/examples/petstore-expanded/strict/api/petstore-server.gen.go
@@ -408,9 +408,8 @@ type StrictServerInterface interface {
FindPetByID(ctx context.Context, request FindPetByIDRequestObject) (FindPetByIDResponseObject, error)
}
-type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, args interface{}) (interface{}, error)
-
-type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+type StrictHandlerFunc = runtime.StrictHttpHandlerFunc
+type StrictMiddlewareFunc = runtime.StrictHttpMiddlewareFunc
type StrictHTTPServerOptions struct {
RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
diff --git a/go.mod b/go.mod
index ff48607022..aeff31dfb4 100644
--- a/go.mod
+++ b/go.mod
@@ -2,37 +2,44 @@ module github.com/deepmap/oapi-codegen
require (
github.com/apapsch/go-jsonmerge/v2 v2.0.0
- github.com/getkin/kin-openapi v0.107.0
- github.com/gin-gonic/gin v1.8.1
- github.com/go-chi/chi/v5 v5.0.7
+ github.com/getkin/kin-openapi v0.117.0
+ github.com/gin-gonic/gin v1.9.1
+ github.com/go-chi/chi/v5 v5.0.8
+ github.com/gofiber/fiber/v2 v2.46.0
github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219
github.com/google/uuid v1.3.0
github.com/gorilla/mux v1.8.0
- github.com/labstack/echo/v4 v4.9.1
+ github.com/labstack/echo/v4 v4.10.2
github.com/lestrrat-go/jwx v1.2.25
- github.com/matryer/moq v0.2.7
- github.com/stretchr/testify v1.8.1
- golang.org/x/text v0.4.0
- golang.org/x/tools v0.3.0
+ github.com/matryer/moq v0.3.1
+ github.com/stretchr/testify v1.8.3
+ golang.org/x/text v0.9.0
+ golang.org/x/tools v0.9.2
gopkg.in/yaml.v2 v2.4.0
)
require (
+ github.com/andybalholm/brotli v1.0.5 // indirect
+ github.com/bytedance/sonic v1.9.1 // indirect
+ github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
+ github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/swag v0.21.1 // indirect
- github.com/go-playground/locales v0.14.0 // indirect
- github.com/go-playground/universal-translator v0.18.0 // indirect
- github.com/go-playground/validator/v10 v10.11.1 // indirect
- github.com/goccy/go-json v0.9.11 // indirect
+ github.com/go-playground/locales v0.14.1 // indirect
+ github.com/go-playground/universal-translator v0.18.1 // indirect
+ github.com/go-playground/validator/v10 v10.14.0 // indirect
+ github.com/goccy/go-json v0.10.2 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/invopop/yaml v0.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
+ github.com/klauspost/compress v1.16.3 // indirect
+ github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/labstack/gommon v0.4.0 // indirect
- github.com/leodido/go-urn v1.2.1 // indirect
+ github.com/leodido/go-urn v1.2.4 // indirect
github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect
github.com/lestrrat-go/blackmagic v1.0.0 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect
@@ -40,24 +47,35 @@ require (
github.com/lestrrat-go/option v1.0.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
- github.com/mattn/go-isatty v0.0.16 // indirect
+ github.com/mattn/go-isatty v0.0.19 // indirect
+ github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
- github.com/pelletier/go-toml/v2 v2.0.5 // indirect
+ github.com/pelletier/go-toml/v2 v2.0.8 // indirect
+ github.com/perimeterx/marshmallow v1.1.4 // indirect
+ github.com/philhofer/fwd v1.1.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
+ github.com/rivo/uniseg v0.2.0 // indirect
+ github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 // indirect
+ github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
github.com/stretchr/objx v0.5.0 // indirect
- github.com/ugorji/go/codec v1.2.7 // indirect
+ github.com/tinylib/msgp v1.1.8 // indirect
+ github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
+ github.com/ugorji/go/codec v1.2.11 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
+ github.com/valyala/fasthttp v1.47.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
- golang.org/x/crypto v0.1.0 // indirect
- golang.org/x/mod v0.7.0 // indirect
- golang.org/x/net v0.2.0 // indirect
- golang.org/x/sys v0.2.0 // indirect
- golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect
+ github.com/valyala/tcplisten v1.0.0 // indirect
+ golang.org/x/arch v0.3.0 // indirect
+ golang.org/x/crypto v0.9.0 // indirect
+ golang.org/x/mod v0.10.0 // indirect
+ golang.org/x/net v0.10.0 // indirect
+ golang.org/x/sys v0.8.0 // indirect
+ golang.org/x/time v0.3.0 // indirect
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
- google.golang.org/protobuf v1.28.1 // indirect
+ google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/go.sum b/go.sum
index 86f056337d..f11b87036d 100644
--- a/go.sum
+++ b/go.sum
@@ -1,7 +1,15 @@
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
+github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
+github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
+github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
+github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
+github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
+github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
+github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
+github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -10,30 +18,35 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
-github.com/getkin/kin-openapi v0.107.0 h1:bxhL6QArW7BXQj8NjXfIJQy680NsMKd25nwhvpCXchg=
-github.com/getkin/kin-openapi v0.107.0/go.mod h1:9Dhr+FasATJZjS4iOLvB0hkaxgYdulrNYm2e9epLWOo=
+github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
+github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
+github.com/getkin/kin-openapi v0.117.0 h1:QT2DyGujAL09F4NrKDHJGsUoIprlIcFVHWDVDcUFE8A=
+github.com/getkin/kin-openapi v0.117.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
-github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8=
-github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
-github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8=
-github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
+github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
+github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
+github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0=
+github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU=
github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
-github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
-github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
-github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
-github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
-github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
-github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
-github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ=
-github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
+github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
+github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
+github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
+github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
+github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
+github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
+github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
+github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
+github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
-github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
-github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
+github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/gofiber/fiber/v2 v2.46.0 h1:wkkWotblsGVlLjXj2dpgKQAYHtXumsK/HyFugQM68Ns=
+github.com/gofiber/fiber/v2 v2.46.0/go.mod h1:DNl0/c37WLe0g92U6lx1VMQuxGUQY5V7EIaVoEsUffc=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
@@ -53,20 +66,22 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
+github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY=
+github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
+github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
+github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
+github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
-github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
-github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/labstack/echo/v4 v4.9.1 h1:GliPYSpzGKlyOhqIbG8nmHBo3i1saKWFOgh41AN3b+Y=
-github.com/labstack/echo/v4 v4.9.1/go.mod h1:Pop5HLc+xoc4qhTZ1ip6C0RtP7Z+4VzRLWZZFKqbbjo=
+github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M=
+github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k=
github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
-github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
-github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
+github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
+github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A=
github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y=
github.com/lestrrat-go/blackmagic v1.0.0 h1:XzdxDbuQTz0RZZEmdU7cnQxUtFUzgCSPq8RCz4BxIi4=
@@ -84,14 +99,17 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
-github.com/matryer/moq v0.2.7 h1:RtpiPUM8L7ZSCbSwK+QcZH/E9tgqAkFjKQxsRs25b4w=
-github.com/matryer/moq v0.2.7/go.mod h1:kITsx543GOENm48TUAQyJ9+SAvFSr7iGQXPoth/VUBk=
+github.com/matryer/moq v0.3.1 h1:kLDiBJoGcusWS2BixGyTkF224aSCD8nLY24tj/NcTCs=
+github.com/matryer/moq v0.3.1/go.mod h1:RJ75ZZZD71hejp39j4crZLsEDszGk6iH4v4YsWFKH4s=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
-github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
+github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
+github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -99,17 +117,26 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
-github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg=
-github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
-github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
+github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
+github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
+github.com/perimeterx/marshmallow v1.1.4 h1:pZLDH9RjlLGGorbXhcaQLhfuV0pFMNfPO55FuFkxqLw=
+github.com/perimeterx/marshmallow v1.1.4/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
+github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
+github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw=
+github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
-github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
-github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
+github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 h1:rmMl4fXJhKMNWl+K+r/fq4FbbKI+Ia2m9hYBLm2h4G4=
+github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94/go.mod h1:90zrgN3D/WJsDd1iXHT96alCoN2KJo6/4x1DZC3wZs8=
+github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4=
+github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk=
+github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
@@ -121,61 +148,95 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
+github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw=
+github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0=
+github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw=
+github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
+github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
-github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
+github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
+github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
+github.com/valyala/fasthttp v1.47.0 h1:y7moDoxYzMooFpT5aHgNgVOQDrS3qlkfiP9mDtGGK9c=
+github.com/valyala/fasthttp v1.47.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
-github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
+github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
+golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
-golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
-golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
-golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
+golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
+golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
+golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
-golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
+golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
-golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
-golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w=
-golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
+golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
-golang.org/x/tools v0.3.0 h1:SrNbZl6ECOS1qFzgTdQfWXZM9XBkiA6tkFrH9YSTPHM=
-golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
+golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
+golang.org/x/tools v0.9.2 h1:UXbndbirwCAx6TULftIfie/ygDNCwxEie+IiNP1IcNc=
+golang.org/x/tools v0.9.2/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -183,14 +244,12 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
-google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
+google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
-gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
@@ -200,3 +259,4 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
diff --git a/internal/test/any_of/param/param.gen.go b/internal/test/any_of/param/param.gen.go
index 7de9459481..650f1f3cc4 100644
--- a/internal/test/any_of/param/param.gen.go
+++ b/internal/test/any_of/param/param.gen.go
@@ -70,7 +70,7 @@ func (t *Test) MergeTest0(v Test0) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -96,7 +96,7 @@ func (t *Test) MergeTest1(v Test1) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -132,7 +132,7 @@ func (t *Test2) MergeTest20(v Test20) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -158,7 +158,7 @@ func (t *Test2) MergeTest21(v Test21) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -281,42 +281,44 @@ func NewGetTestRequest(server string, params *GetTestParams) (*http.Request, err
return nil, err
}
- queryValues := queryURL.Query()
+ if params != nil {
+ queryValues := queryURL.Query()
- if params.Test != nil {
+ if params.Test != nil {
- if queryFrag, err := runtime.StyleParamWithLocation("form", true, "test", runtime.ParamLocationQuery, *params.Test); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
- return nil, err
- } else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
+ if queryFrag, err := runtime.StyleParamWithLocation("form", true, "test", runtime.ParamLocationQuery, *params.Test); err != nil {
+ return nil, err
+ } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ return nil, err
+ } else {
+ for k, v := range parsed {
+ for _, v2 := range v {
+ queryValues.Add(k, v2)
+ }
}
}
- }
-
- }
- if params.Test2 != nil {
+ }
- if queryFrag, err := runtime.StyleParamWithLocation("form", true, "test2", runtime.ParamLocationQuery, *params.Test2); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
- return nil, err
- } else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
+ if params.Test2 != nil {
+
+ if queryFrag, err := runtime.StyleParamWithLocation("form", true, "test2", runtime.ParamLocationQuery, *params.Test2); err != nil {
+ return nil, err
+ } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ return nil, err
+ } else {
+ for k, v := range parsed {
+ for _, v2 := range v {
+ queryValues.Add(k, v2)
+ }
}
}
+
}
+ queryURL.RawQuery = queryValues.Encode()
}
- queryURL.RawQuery = queryValues.Encode()
-
req, err := http.NewRequest("GET", queryURL.String(), nil)
if err != nil {
return nil, err
diff --git a/internal/test/components/components.gen.go b/internal/test/components/components.gen.go
index d7e23d31c9..be29e17ad6 100644
--- a/internal/test/components/components.gen.go
+++ b/internal/test/components/components.gen.go
@@ -170,7 +170,7 @@ type ObjectWithJsonField struct {
Value2 json.RawMessage `json:"value2,omitempty"`
}
-// OneOfObject1 oneOf with references and no disciminator
+// OneOfObject1 oneOf with references and no discriminator
type OneOfObject1 struct {
union json.RawMessage
}
@@ -217,6 +217,13 @@ type OneOfObject120 = string
// OneOfObject121 defines model for .
type OneOfObject121 = float32
+// OneOfObject13 oneOf with fixed discriminator and other fields allowed
+type OneOfObject13 struct {
+ Type string `json:"type"`
+ AdditionalProperties map[string]interface{} `json:"-"`
+ union json.RawMessage
+}
+
// OneOfObject2 oneOf with inline elements
type OneOfObject2 struct {
union json.RawMessage
@@ -249,7 +256,7 @@ type OneOfObject4 struct {
union json.RawMessage
}
-// OneOfObject5 oneOf with disciminator but no mapping
+// OneOfObject5 oneOf with discriminator but no mapping
type OneOfObject5 struct {
union json.RawMessage
}
@@ -259,6 +266,16 @@ type OneOfObject6 struct {
union json.RawMessage
}
+// OneOfObject61 oneOf with discriminator and partial mapping
+type OneOfObject61 struct {
+ union json.RawMessage
+}
+
+// OneOfObject62 oneOf with snake_case discriminator and partial snake_case mapping
+type OneOfObject62 struct {
+ union json.RawMessage
+}
+
// OneOfObject7 array of oneOf
type OneOfObject7 = []OneOfObject7_Item
@@ -330,6 +347,12 @@ type SchemaObject struct {
WriteOnlyRequiredProp *int `json:"writeOnlyRequiredProp,omitempty"`
}
+// OneOfVariant51 defines model for one_of_variant51.
+type OneOfVariant51 struct {
+ Discriminator string `json:"discriminator"`
+ Id int `json:"id"`
+}
+
// EnumParam1 defines model for EnumParam1.
type EnumParam1 string
@@ -772,6 +795,23 @@ func (a AdditionalPropertiesObject4_Inner) MarshalJSON() ([]byte, error) {
return json.Marshal(object)
}
+// Getter for additional properties for OneOfObject13. Returns the specified
+// element and whether it was found
+func (a OneOfObject13) Get(fieldName string) (value interface{}, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
+}
+
+// Setter for additional properties for OneOfObject13
+func (a *OneOfObject13) Set(fieldName string, value interface{}) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]interface{})
+ }
+ a.AdditionalProperties[fieldName] = value
+}
+
// AsOneOfVariant4 returns the union data inside the AnyOfObject1 as a OneOfVariant4
func (t AnyOfObject1) AsOneOfVariant4() (OneOfVariant4, error) {
var body OneOfVariant4
@@ -793,7 +833,7 @@ func (t *AnyOfObject1) MergeOneOfVariant4(v OneOfVariant4) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -819,7 +859,7 @@ func (t *AnyOfObject1) MergeOneOfVariant5(v OneOfVariant5) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -855,7 +895,7 @@ func (t *OneOfObject1) MergeOneOfVariant1(v OneOfVariant1) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -881,7 +921,7 @@ func (t *OneOfObject1) MergeOneOfVariant2(v OneOfVariant2) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -907,7 +947,7 @@ func (t *OneOfObject1) MergeOneOfVariant3(v OneOfVariant3) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -943,7 +983,7 @@ func (t *OneOfObject10) MergeOneOfObject100(v OneOfObject100) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -969,7 +1009,7 @@ func (t *OneOfObject10) MergeOneOfObject101(v OneOfObject101) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1067,7 +1107,7 @@ func (t *OneOfObject11_AdditionalProperties) MergeOneOfObject110(v OneOfObject11
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1093,7 +1133,7 @@ func (t *OneOfObject11_AdditionalProperties) MergeOneOfObject111(v OneOfObject11
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1119,7 +1159,7 @@ func (t *OneOfObject11_AdditionalProperties) MergeOneOfObject112(v OneOfObject11
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1155,7 +1195,7 @@ func (t *OneOfObject12) MergeOneOfObject120(v OneOfObject120) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1181,7 +1221,7 @@ func (t *OneOfObject12) MergeOneOfObject121(v OneOfObject121) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1207,7 +1247,7 @@ func (t *OneOfObject12) MergeOneOfVariant3(v OneOfVariant3) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1233,7 +1273,7 @@ func (t *OneOfObject12) MergeOneOfVariant4(v OneOfVariant4) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1248,6 +1288,89 @@ func (t *OneOfObject12) UnmarshalJSON(b []byte) error {
return err
}
+// AsOneOfVariant1 returns the union data inside the OneOfObject13 as a OneOfVariant1
+func (t OneOfObject13) AsOneOfVariant1() (OneOfVariant1, error) {
+ var body OneOfVariant1
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromOneOfVariant1 overwrites any union data inside the OneOfObject13 as the provided OneOfVariant1
+func (t *OneOfObject13) FromOneOfVariant1(v OneOfVariant1) error {
+ t.Type = "v1"
+
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeOneOfVariant1 performs a merge with any union data inside the OneOfObject13, using the provided OneOfVariant1
+func (t *OneOfObject13) MergeOneOfVariant1(v OneOfVariant1) error {
+ t.Type = "v1"
+
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JsonMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsOneOfVariant6 returns the union data inside the OneOfObject13 as a OneOfVariant6
+func (t OneOfObject13) AsOneOfVariant6() (OneOfVariant6, error) {
+ var body OneOfVariant6
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromOneOfVariant6 overwrites any union data inside the OneOfObject13 as the provided OneOfVariant6
+func (t *OneOfObject13) FromOneOfVariant6(v OneOfVariant6) error {
+ t.Type = "v6"
+
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeOneOfVariant6 performs a merge with any union data inside the OneOfObject13, using the provided OneOfVariant6
+func (t *OneOfObject13) MergeOneOfVariant6(v OneOfVariant6) error {
+ t.Type = "v6"
+
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JsonMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t OneOfObject13) Discriminator() (string, error) {
+ var discriminator struct {
+ Discriminator string `json:"type"`
+ }
+ err := json.Unmarshal(t.union, &discriminator)
+ return discriminator.Discriminator, err
+}
+
+func (t OneOfObject13) ValueByDiscriminator() (interface{}, error) {
+ discriminator, err := t.Discriminator()
+ if err != nil {
+ return nil, err
+ }
+ switch discriminator {
+ case "v1":
+ return t.AsOneOfVariant1()
+ case "v6":
+ return t.AsOneOfVariant6()
+ default:
+ return nil, errors.New("unknown discriminator value: " + discriminator)
+ }
+}
+
// AsOneOfObject20 returns the union data inside the OneOfObject2 as a OneOfObject20
func (t OneOfObject2) AsOneOfObject20() (OneOfObject20, error) {
var body OneOfObject20
@@ -1269,7 +1392,7 @@ func (t *OneOfObject2) MergeOneOfObject20(v OneOfObject20) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1295,7 +1418,7 @@ func (t *OneOfObject2) MergeOneOfObject21(v OneOfObject21) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1321,7 +1444,7 @@ func (t *OneOfObject2) MergeOneOfObject22(v OneOfObject22) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1357,7 +1480,7 @@ func (t *OneOfObject3_Union) MergeOneOfVariant1(v OneOfVariant1) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1383,7 +1506,7 @@ func (t *OneOfObject3_Union) MergeOneOfVariant2(v OneOfVariant2) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1409,7 +1532,7 @@ func (t *OneOfObject3_Union) MergeOneOfVariant3(v OneOfVariant3) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1445,7 +1568,7 @@ func (t *OneOfObject4) MergeOneOfVariant1(v OneOfVariant1) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1471,7 +1594,7 @@ func (t *OneOfObject4) MergeOneOfVariant2(v OneOfVariant2) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1497,7 +1620,7 @@ func (t *OneOfObject4) MergeOneOfVariant3(v OneOfVariant3) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1555,6 +1678,7 @@ func (t OneOfObject5) AsOneOfVariant4() (OneOfVariant4, error) {
// FromOneOfVariant4 overwrites any union data inside the OneOfObject5 as the provided OneOfVariant4
func (t *OneOfObject5) FromOneOfVariant4(v OneOfVariant4) error {
+ v.Discriminator = "OneOfVariant4"
b, err := json.Marshal(v)
t.union = b
return err
@@ -1562,12 +1686,13 @@ func (t *OneOfObject5) FromOneOfVariant4(v OneOfVariant4) error {
// MergeOneOfVariant4 performs a merge with any union data inside the OneOfObject5, using the provided OneOfVariant4
func (t *OneOfObject5) MergeOneOfVariant4(v OneOfVariant4) error {
+ v.Discriminator = "OneOfVariant4"
b, err := json.Marshal(v)
if err != nil {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1581,6 +1706,7 @@ func (t OneOfObject5) AsOneOfVariant5() (OneOfVariant5, error) {
// FromOneOfVariant5 overwrites any union data inside the OneOfObject5 as the provided OneOfVariant5
func (t *OneOfObject5) FromOneOfVariant5(v OneOfVariant5) error {
+ v.Discriminator = "OneOfVariant5"
b, err := json.Marshal(v)
t.union = b
return err
@@ -1588,12 +1714,13 @@ func (t *OneOfObject5) FromOneOfVariant5(v OneOfVariant5) error {
// MergeOneOfVariant5 performs a merge with any union data inside the OneOfObject5, using the provided OneOfVariant5
func (t *OneOfObject5) MergeOneOfVariant5(v OneOfVariant5) error {
+ v.Discriminator = "OneOfVariant5"
b, err := json.Marshal(v)
if err != nil {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1606,6 +1733,21 @@ func (t OneOfObject5) Discriminator() (string, error) {
return discriminator.Discriminator, err
}
+func (t OneOfObject5) ValueByDiscriminator() (interface{}, error) {
+ discriminator, err := t.Discriminator()
+ if err != nil {
+ return nil, err
+ }
+ switch discriminator {
+ case "OneOfVariant4":
+ return t.AsOneOfVariant4()
+ case "OneOfVariant5":
+ return t.AsOneOfVariant5()
+ default:
+ return nil, errors.New("unknown discriminator value: " + discriminator)
+ }
+}
+
func (t OneOfObject5) MarshalJSON() ([]byte, error) {
b, err := t.union.MarshalJSON()
return b, err
@@ -1639,7 +1781,7 @@ func (t *OneOfObject6) MergeOneOfVariant4(v OneOfVariant4) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1667,7 +1809,7 @@ func (t *OneOfObject6) MergeOneOfVariant5(v OneOfVariant5) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1705,6 +1847,184 @@ func (t *OneOfObject6) UnmarshalJSON(b []byte) error {
return err
}
+// AsOneOfVariant4 returns the union data inside the OneOfObject61 as a OneOfVariant4
+func (t OneOfObject61) AsOneOfVariant4() (OneOfVariant4, error) {
+ var body OneOfVariant4
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromOneOfVariant4 overwrites any union data inside the OneOfObject61 as the provided OneOfVariant4
+func (t *OneOfObject61) FromOneOfVariant4(v OneOfVariant4) error {
+ v.Discriminator = "v4"
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeOneOfVariant4 performs a merge with any union data inside the OneOfObject61, using the provided OneOfVariant4
+func (t *OneOfObject61) MergeOneOfVariant4(v OneOfVariant4) error {
+ v.Discriminator = "v4"
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JsonMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsOneOfVariant5 returns the union data inside the OneOfObject61 as a OneOfVariant5
+func (t OneOfObject61) AsOneOfVariant5() (OneOfVariant5, error) {
+ var body OneOfVariant5
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromOneOfVariant5 overwrites any union data inside the OneOfObject61 as the provided OneOfVariant5
+func (t *OneOfObject61) FromOneOfVariant5(v OneOfVariant5) error {
+ v.Discriminator = "OneOfVariant5"
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeOneOfVariant5 performs a merge with any union data inside the OneOfObject61, using the provided OneOfVariant5
+func (t *OneOfObject61) MergeOneOfVariant5(v OneOfVariant5) error {
+ v.Discriminator = "OneOfVariant5"
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JsonMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t OneOfObject61) Discriminator() (string, error) {
+ var discriminator struct {
+ Discriminator string `json:"discriminator"`
+ }
+ err := json.Unmarshal(t.union, &discriminator)
+ return discriminator.Discriminator, err
+}
+
+func (t OneOfObject61) ValueByDiscriminator() (interface{}, error) {
+ discriminator, err := t.Discriminator()
+ if err != nil {
+ return nil, err
+ }
+ switch discriminator {
+ case "OneOfVariant5":
+ return t.AsOneOfVariant5()
+ case "v4":
+ return t.AsOneOfVariant4()
+ default:
+ return nil, errors.New("unknown discriminator value: " + discriminator)
+ }
+}
+
+func (t OneOfObject61) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *OneOfObject61) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
+
+// AsOneOfVariant4 returns the union data inside the OneOfObject62 as a OneOfVariant4
+func (t OneOfObject62) AsOneOfVariant4() (OneOfVariant4, error) {
+ var body OneOfVariant4
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromOneOfVariant4 overwrites any union data inside the OneOfObject62 as the provided OneOfVariant4
+func (t *OneOfObject62) FromOneOfVariant4(v OneOfVariant4) error {
+ v.Discriminator = "variant_four"
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeOneOfVariant4 performs a merge with any union data inside the OneOfObject62, using the provided OneOfVariant4
+func (t *OneOfObject62) MergeOneOfVariant4(v OneOfVariant4) error {
+ v.Discriminator = "variant_four"
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JsonMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsOneOfVariant51 returns the union data inside the OneOfObject62 as a OneOfVariant51
+func (t OneOfObject62) AsOneOfVariant51() (OneOfVariant51, error) {
+ var body OneOfVariant51
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromOneOfVariant51 overwrites any union data inside the OneOfObject62 as the provided OneOfVariant51
+func (t *OneOfObject62) FromOneOfVariant51(v OneOfVariant51) error {
+ v.Discriminator = "one_of_variant51"
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeOneOfVariant51 performs a merge with any union data inside the OneOfObject62, using the provided OneOfVariant51
+func (t *OneOfObject62) MergeOneOfVariant51(v OneOfVariant51) error {
+ v.Discriminator = "one_of_variant51"
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JsonMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t OneOfObject62) Discriminator() (string, error) {
+ var discriminator struct {
+ Discriminator string `json:"discriminator"`
+ }
+ err := json.Unmarshal(t.union, &discriminator)
+ return discriminator.Discriminator, err
+}
+
+func (t OneOfObject62) ValueByDiscriminator() (interface{}, error) {
+ discriminator, err := t.Discriminator()
+ if err != nil {
+ return nil, err
+ }
+ switch discriminator {
+ case "one_of_variant51":
+ return t.AsOneOfVariant51()
+ case "variant_four":
+ return t.AsOneOfVariant4()
+ default:
+ return nil, errors.New("unknown discriminator value: " + discriminator)
+ }
+}
+
+func (t OneOfObject62) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *OneOfObject62) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
+
// AsOneOfVariant1 returns the union data inside the OneOfObject7_Item as a OneOfVariant1
func (t OneOfObject7_Item) AsOneOfVariant1() (OneOfVariant1, error) {
var body OneOfVariant1
@@ -1726,7 +2046,7 @@ func (t *OneOfObject7_Item) MergeOneOfVariant1(v OneOfVariant1) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1752,7 +2072,7 @@ func (t *OneOfObject7_Item) MergeOneOfVariant2(v OneOfVariant2) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1788,7 +2108,7 @@ func (t *OneOfObject8) MergeOneOfVariant1(v OneOfVariant1) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1814,7 +2134,7 @@ func (t *OneOfObject8) MergeOneOfVariant2(v OneOfVariant2) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1888,7 +2208,7 @@ func (t *OneOfObject9) MergeOneOfVariant1(v OneOfVariant1) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1918,7 +2238,7 @@ func (t *OneOfObject9) MergeOneOfVariant6(v OneOfVariant6) error {
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -1988,3 +2308,66 @@ func (t *OneOfObject9) UnmarshalJSON(b []byte) error {
return err
}
+
+// Override default JSON handling for OneOfObject13 to handle AdditionalProperties and union
+func (a *OneOfObject13) UnmarshalJSON(b []byte) error {
+ err := a.union.UnmarshalJSON(b)
+ if err != nil {
+ return err
+ }
+ object := make(map[string]json.RawMessage)
+ err = json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
+
+ if raw, found := object["type"]; found {
+ err = json.Unmarshal(raw, &a.Type)
+ if err != nil {
+ return fmt.Errorf("error reading 'type': %w", err)
+ }
+ delete(object, "type")
+ }
+
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]interface{})
+ for fieldName, fieldBuf := range object {
+ var fieldVal interface{}
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
+}
+
+// Override default JSON handling for OneOfObject13 to handle AdditionalProperties and union
+func (a OneOfObject13) MarshalJSON() ([]byte, error) {
+ var err error
+ b, err := a.union.MarshalJSON()
+ if err != nil {
+ return nil, err
+ }
+ object := make(map[string]json.RawMessage)
+ if a.union != nil {
+ err = json.Unmarshal(b, &object)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ object["type"], err = json.Marshal(a.Type)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'type': %w", err)
+ }
+
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
+}
diff --git a/internal/test/components/components.yaml b/internal/test/components/components.yaml
index 79e3857361..24fdf77b7e 100644
--- a/internal/test/components/components.yaml
+++ b/internal/test/components/components.yaml
@@ -208,7 +208,7 @@ components:
additionalProperties:
$ref: '#/components/schemas/SchemaObject'
OneOfObject1:
- description: oneOf with references and no disciminator
+ description: oneOf with references and no discriminator
oneOf:
- $ref: '#/components/schemas/OneOfVariant1'
- $ref: '#/components/schemas/OneOfVariant2'
@@ -244,7 +244,7 @@ components:
- $ref: '#/components/schemas/OneOfVariant2'
- $ref: '#/components/schemas/OneOfVariant3'
OneOfObject5:
- description: oneOf with disciminator but no mapping
+ description: oneOf with discriminator but no mapping
oneOf:
- $ref: '#/components/schemas/OneOfVariant4'
- $ref: '#/components/schemas/OneOfVariant5'
@@ -260,6 +260,24 @@ components:
mapping:
v4: '#/components/schemas/OneOfVariant4'
v5: '#/components/schemas/OneOfVariant5'
+ OneOfObject61:
+ description: oneOf with discriminator and partial mapping
+ oneOf:
+ - $ref: '#/components/schemas/OneOfVariant4'
+ - $ref: '#/components/schemas/OneOfVariant5'
+ discriminator:
+ propertyName: discriminator
+ mapping:
+ v4: '#/components/schemas/OneOfVariant4'
+ OneOfObject62:
+ description: oneOf with snake_case discriminator and partial snake_case mapping
+ oneOf:
+ - $ref: '#/components/schemas/OneOfVariant4'
+ - $ref: '#/components/schemas/one_of_variant51'
+ discriminator:
+ propertyName: discriminator
+ mapping:
+ variant_four: '#/components/schemas/OneOfVariant4'
OneOfObject7:
description: array of oneOf
type: array
@@ -325,6 +343,23 @@ components:
- oneOf:
- $ref: '#/components/schemas/OneOfVariant3'
- $ref: '#/components/schemas/OneOfVariant4'
+ OneOfObject13:
+ description: oneOf with fixed discriminator and other fields allowed
+ type: object
+ properties:
+ type:
+ type: string
+ oneOf:
+ - $ref: '#/components/schemas/OneOfVariant1'
+ - $ref: '#/components/schemas/OneOfVariant6'
+ discriminator:
+ propertyName: type
+ mapping:
+ v1: '#/components/schemas/OneOfVariant1'
+ v6: '#/components/schemas/OneOfVariant6'
+ required:
+ - type
+ additionalProperties: true
AnyOfObject1:
description: simple anyOf case
anyOf:
@@ -363,6 +398,16 @@ components:
required:
- discriminator
- id
+ one_of_variant51:
+ type: object
+ properties:
+ discriminator:
+ type: string
+ id:
+ type: integer
+ required:
+ - discriminator
+ - id
OneOfVariant6:
type: object
properties:
diff --git a/internal/test/components/components_test.go b/internal/test/components/components_test.go
index e2eabfb09b..7810ea20d6 100644
--- a/internal/test/components/components_test.go
+++ b/internal/test/components/components_test.go
@@ -5,18 +5,12 @@ import (
"testing"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
func assertJsonEqual(t *testing.T, j1 []byte, j2 []byte) {
- var v1, v2 interface{}
-
- err := json.Unmarshal(j1, &v1)
- assert.NoError(t, err)
-
- err = json.Unmarshal(j2, &v2)
- assert.NoError(t, err)
-
- assert.EqualValues(t, v1, v2)
+ t.Helper()
+ assert.JSONEq(t, string(j1), string(j2))
}
func TestRawJSON(t *testing.T) {
@@ -151,6 +145,117 @@ func TestOneOfWithDiscriminator(t *testing.T) {
assertJsonEqual(t, []byte(variant5), marshaled)
}
+func TestOneOfWithDiscriminator_PartialMapping(t *testing.T) {
+ const variant4 = `{"discriminator": "v4", "name": "123"}`
+ const variant5 = `{"discriminator": "OneOfVariant5", "id": 321}`
+ var dst OneOfObject61
+
+ err := json.Unmarshal([]byte(variant4), &dst)
+ assert.NoError(t, err)
+ discriminator, err := dst.Discriminator()
+ require.NoError(t, err)
+ assert.Equal(t, "v4", discriminator)
+ v4, err := dst.ValueByDiscriminator()
+ require.NoError(t, err)
+ assert.Equal(t, OneOfVariant4{Discriminator: "v4", Name: "123"}, v4)
+
+ err = json.Unmarshal([]byte(variant5), &dst)
+ require.NoError(t, err)
+ discriminator, err = dst.Discriminator()
+ require.NoError(t, err)
+ assert.Equal(t, "OneOfVariant5", discriminator)
+ v5, err := dst.ValueByDiscriminator()
+ require.NoError(t, err)
+ assert.Equal(t, OneOfVariant5{Discriminator: "OneOfVariant5", Id: 321}, v5)
+
+ // discriminator value will be filled by the generated code
+ err = dst.FromOneOfVariant4(OneOfVariant4{Name: "123"})
+ require.NoError(t, err)
+ marshaled, err := json.Marshal(dst)
+ require.NoError(t, err)
+ assertJsonEqual(t, []byte(variant4), marshaled)
+
+ err = dst.FromOneOfVariant5(OneOfVariant5{Id: 321})
+ require.NoError(t, err)
+ marshaled, err = json.Marshal(dst)
+ require.NoError(t, err)
+ assertJsonEqual(t, []byte(variant5), marshaled)
+}
+
+func TestOneOfWithDiscriminator_SchemaNameUsed(t *testing.T) {
+ const variant4 = `{"discriminator": "variant_four", "name": "789"}`
+ const variant51 = `{"discriminator": "one_of_variant51", "id": 987}`
+ var dst OneOfObject62
+
+ err := json.Unmarshal([]byte(variant4), &dst)
+ assert.NoError(t, err)
+ discriminator, err := dst.Discriminator()
+ require.NoError(t, err)
+ assert.Equal(t, "variant_four", discriminator)
+ v4, err := dst.ValueByDiscriminator()
+ require.NoError(t, err)
+ assert.Equal(t, OneOfVariant4{Discriminator: "variant_four", Name: "789"}, v4)
+
+ err = json.Unmarshal([]byte(variant51), &dst)
+ require.NoError(t, err)
+ discriminator, err = dst.Discriminator()
+ require.NoError(t, err)
+ assert.Equal(t, "one_of_variant51", discriminator)
+ v5, err := dst.ValueByDiscriminator()
+ require.NoError(t, err)
+ assert.Equal(t, OneOfVariant51{Discriminator: "one_of_variant51", Id: 987}, v5)
+
+ // discriminator value will be filled by the generated code
+ err = dst.FromOneOfVariant4(OneOfVariant4{Name: "789"})
+ require.NoError(t, err)
+ marshaled, err := json.Marshal(dst)
+ require.NoError(t, err)
+ assertJsonEqual(t, []byte(variant4), marshaled)
+
+ err = dst.FromOneOfVariant51(OneOfVariant51{Id: 987})
+ require.NoError(t, err)
+ marshaled, err = json.Marshal(dst)
+ require.NoError(t, err)
+ assertJsonEqual(t, []byte(variant51), marshaled)
+}
+
+func TestOneOfWithDiscriminator_FullImplicitMapping(t *testing.T) {
+ const variant4 = `{"discriminator": "OneOfVariant4", "name": "456"}`
+ const variant5 = `{"discriminator": "OneOfVariant5", "id": 654}`
+ var dst OneOfObject5
+
+ err := json.Unmarshal([]byte(variant4), &dst)
+ assert.NoError(t, err)
+ discriminator, err := dst.Discriminator()
+ require.NoError(t, err)
+ assert.Equal(t, "OneOfVariant4", discriminator)
+ v4, err := dst.ValueByDiscriminator()
+ require.NoError(t, err)
+ assert.Equal(t, OneOfVariant4{Discriminator: "OneOfVariant4", Name: "456"}, v4)
+
+ err = json.Unmarshal([]byte(variant5), &dst)
+ require.NoError(t, err)
+ discriminator, err = dst.Discriminator()
+ require.NoError(t, err)
+ assert.Equal(t, "OneOfVariant5", discriminator)
+ v5, err := dst.ValueByDiscriminator()
+ require.NoError(t, err)
+ assert.Equal(t, OneOfVariant5{Discriminator: "OneOfVariant5", Id: 654}, v5)
+
+ // discriminator value will be filled by the generated code
+ err = dst.FromOneOfVariant4(OneOfVariant4{Name: "456"})
+ require.NoError(t, err)
+ marshaled, err := json.Marshal(dst)
+ require.NoError(t, err)
+ assertJsonEqual(t, []byte(variant4), marshaled)
+
+ err = dst.FromOneOfVariant5(OneOfVariant5{Id: 654})
+ require.NoError(t, err)
+ marshaled, err = json.Marshal(dst)
+ require.NoError(t, err)
+ assertJsonEqual(t, []byte(variant5), marshaled)
+}
+
func TestOneOfWithFixedProperties(t *testing.T) {
const variant1 = "{\"type\": \"v1\", \"name\": \"123\"}"
const variant6 = "{\"type\": \"v6\", \"values\": [1, 2, 3]}"
@@ -203,6 +308,34 @@ func TestAnyOf(t *testing.T) {
assert.Equal(t, OneOfVariant5{Discriminator: "all", Id: 456}, v5)
}
+func TestOneOfWithAdditional(t *testing.T) {
+ x := OneOfObject13{
+ AdditionalProperties: map[string]interface{}{"x": "y"},
+ }
+ err := x.MergeOneOfVariant1(OneOfVariant1{Name: "test-name"})
+ require.NoError(t, err)
+ b, err := json.Marshal(x)
+ require.NoError(t, err)
+ assert.JSONEq(t, `{"x":"y", "name":"test-name", "type":"v1"}`, string(b))
+ var y OneOfObject13
+ err = json.Unmarshal(b, &y)
+ require.NoError(t, err)
+ assert.Equal(t, x.Type, y.Type)
+ xVariant, err := x.AsOneOfVariant1()
+ require.NoError(t, err)
+ yVariant, err := y.AsOneOfVariant1()
+ require.NoError(t, err)
+ assert.Equal(t, xVariant, yVariant)
+ xAdditional, ok := x.Get("x")
+ assert.True(t, ok)
+ yAdditional, ok := y.Get("x")
+ assert.True(t, ok)
+ assert.Equal(t, xAdditional, yAdditional)
+ b, err = json.Marshal(y)
+ require.NoError(t, err)
+ assert.JSONEq(t, `{"x":"y", "name":"test-name", "type":"v1"}`, string(b))
+}
+
func TestMarshalWhenNoUnionValueSet(t *testing.T) {
const expected = `{}`
diff --git a/internal/test/issues/issue-grab_import_names/issue.gen.go b/internal/test/issues/issue-grab_import_names/issue.gen.go
index 6378e57dfb..b9904fcde1 100644
--- a/internal/test/issues/issue-grab_import_names/issue.gen.go
+++ b/internal/test/issues/issue-grab_import_names/issue.gen.go
@@ -363,12 +363,12 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
- "H4sIAAAAAAAC/3yRQWv7MAzFv4rQ2aih/fM/5DjGxu67jTHcVG08YstY6mhX8t2HnZ7KulyERPTz03sX",
- "HCRmSZxMsb/MDkPaC/YXtGATY49EhA6/uGiQhD121FGHs0PJnHwO2OOGOlqjw+xtrBRc7aUxDmy17FiH",
- "ErItgAUomYuvk5cd9vjM9iTSEMVHNi6K/dvt5tYr//9HsD0bK8EwBoJBkvHJCHgYhYBLkaIE+2gEh++Q",
- "CUazTBCE4FMlEVx1b6qKULEj+x0XdJh8rBcvSnQYOfrmxDnXsVoJ6YDz7G51XYkf9UclqDYQlGOyEJlg",
- "2VOC1j4el7OX7jVEhmOZCE5xIjj7ON2V9eDLn7LeHRbWLEm5hbDuulqaQanl4HOewtCeX1Uv6uw+b3a/",
- "BDe37ycAAP//wjdd4jYCAAA=",
+ "H4sIAAAAAAAC/3yRzWrrQAyFX0VoPSgmudyFl6W0dN9dKWXiKPEUzw+SUpIGv3uZcVahqTdCwvrm6JwL",
+ "hrTP2F/Qgk2MPRIROvxi0ZAT9thRRx3ODnPh5EvAHjfU0RodFm+j1t3VPjfGga2WHesgodgCWIC5sPg6",
+ "edlhj89sTzk3hPjIxqLYv91ubr3y/38E27OxEgxjIBhyMj4ZAQ9jJmCRLEqwj0Zw+A6FYDQrBCETfGpO",
+ "BFfdm6oiVOzIfseCDpOP9eJFiQ4jR9+cOJc6VpOQDjjP7lbXlfhRf1SCagOBHJOFyATLnhK09vG4nL10",
+ "ryEyHGUiOMWJ4OzjdFfWg5c/Zb07FNaSk3ILYd11tTSDUsvBlzKFoT2/ql7U2X3e7H4Jbm7fTwAAAP//",
+ "VfuleiYCAAA=",
}
// GetSwagger returns the content of the embedded swagger specification file
diff --git a/internal/test/issues/issue-head-digit-of-httpheader/issue.gen.go b/internal/test/issues/issue-head-digit-of-httpheader/issue.gen.go
index 703c262af6..6e5994e2bf 100644
--- a/internal/test/issues/issue-head-digit-of-httpheader/issue.gen.go
+++ b/internal/test/issues/issue-head-digit-of-httpheader/issue.gen.go
@@ -3,37 +3,9 @@
// Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT.
package headdigitofhttpheader
-import (
- "context"
- "fmt"
- "net/http"
-)
-
type N200ResponseHeaders struct {
N000Foo string
}
type N200Response struct {
Headers N200ResponseHeaders
}
-
-type GetFooRequestObject struct {
-}
-
-type GetFooResponseObject interface {
- VisitGetFooResponse(w http.ResponseWriter) error
-}
-
-type GetFoo200Response = N200Response
-
-func (response GetFoo200Response) VisitGetFooResponse(w http.ResponseWriter) error {
- w.Header().Set("000-foo", fmt.Sprint(response.Headers.N000Foo))
- w.WriteHeader(200)
- return nil
-}
-
-// StrictServerInterface represents all server handlers.
-type StrictServerInterface interface {
-
- // (GET /foo)
- GetFoo(ctx context.Context, request GetFooRequestObject) (GetFooResponseObject, error)
-}
diff --git a/internal/test/issues/issue-head-digit-of-operation-id/issue.gen.go b/internal/test/issues/issue-head-digit-of-operation-id/issue.gen.go
index 17607466a4..4a5d3e86f6 100644
--- a/internal/test/issues/issue-head-digit-of-operation-id/issue.gen.go
+++ b/internal/test/issues/issue-head-digit-of-operation-id/issue.gen.go
@@ -2,22 +2,3 @@
//
// Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT.
package head_digit_of_operation_id
-
-import (
- "context"
- "net/http"
-)
-
-type N3GPPFooRequestObject struct {
-}
-
-type N3GPPFooResponseObject interface {
- VisitN3GPPFooResponse(w http.ResponseWriter) error
-}
-
-// StrictServerInterface represents all server handlers.
-type StrictServerInterface interface {
-
- // (GET /3gpp/foo)
- N3GPPFoo(ctx context.Context, request N3GPPFooRequestObject) (N3GPPFooResponseObject, error)
-}
diff --git a/internal/test/issues/issue-removed-external-ref/gen/spec_base/issue.gen.go b/internal/test/issues/issue-removed-external-ref/gen/spec_base/issue.gen.go
index 09e8df32f5..69766e1c31 100644
--- a/internal/test/issues/issue-removed-external-ref/gen/spec_base/issue.gen.go
+++ b/internal/test/issues/issue-removed-external-ref/gen/spec_base/issue.gen.go
@@ -10,6 +10,7 @@ import (
"net/http"
externalRef0 "github.com/deepmap/oapi-codegen/internal/test/issues/issue-removed-external-ref/gen/spec_ext"
+ "github.com/deepmap/oapi-codegen/pkg/runtime"
"github.com/go-chi/chi/v5"
)
@@ -244,9 +245,8 @@ type StrictServerInterface interface {
PostNoTrouble(ctx context.Context, request PostNoTroubleRequestObject) (PostNoTroubleResponseObject, error)
}
-type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, args interface{}) (interface{}, error)
-
-type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+type StrictHandlerFunc = runtime.StrictHttpHandlerFunc
+type StrictMiddlewareFunc = runtime.StrictHttpMiddlewareFunc
type StrictHTTPServerOptions struct {
RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
diff --git a/internal/test/issues/issue-removed-external-ref/gen/spec_ext/issue.gen.go b/internal/test/issues/issue-removed-external-ref/gen/spec_ext/issue.gen.go
index 21222f879f..ed5a474465 100644
--- a/internal/test/issues/issue-removed-external-ref/gen/spec_ext/issue.gen.go
+++ b/internal/test/issues/issue-removed-external-ref/gen/spec_ext/issue.gen.go
@@ -4,10 +4,10 @@
package spec_ext
import (
- "context"
"fmt"
"net/http"
+ "github.com/deepmap/oapi-codegen/pkg/runtime"
"github.com/go-chi/chi/v5"
)
@@ -161,9 +161,8 @@ type PascalJSONResponse PascalSchema
type StrictServerInterface interface {
}
-type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, args interface{}) (interface{}, error)
-
-type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+type StrictHandlerFunc = runtime.StrictHttpHandlerFunc
+type StrictMiddlewareFunc = runtime.StrictHttpMiddlewareFunc
type StrictHTTPServerOptions struct {
RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
diff --git a/internal/test/parameters/parameters.gen.go b/internal/test/parameters/parameters.gen.go
index 45d11b462c..1f2b4b840f 100644
--- a/internal/test/parameters/parameters.gen.go
+++ b/internal/test/parameters/parameters.gen.go
@@ -732,26 +732,28 @@ func NewEnumParamsRequest(server string, params *EnumParamsParams) (*http.Reques
return nil, err
}
- queryValues := queryURL.Query()
-
- if params.EnumPathParam != nil {
-
- if queryFrag, err := runtime.StyleParamWithLocation("form", true, "enumPathParam", runtime.ParamLocationQuery, *params.EnumPathParam); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
- return nil, err
- } else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
+ if params != nil {
+ queryValues := queryURL.Query()
+
+ if params.EnumPathParam != nil {
+
+ if queryFrag, err := runtime.StyleParamWithLocation("form", true, "enumPathParam", runtime.ParamLocationQuery, *params.EnumPathParam); err != nil {
+ return nil, err
+ } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ return nil, err
+ } else {
+ for k, v := range parsed {
+ for _, v2 := range v {
+ queryValues.Add(k, v2)
+ }
}
}
+
}
+ queryURL.RawQuery = queryValues.Encode()
}
- queryURL.RawQuery = queryValues.Encode()
-
req, err := http.NewRequest("GET", queryURL.String(), nil)
if err != nil {
return nil, err
@@ -1199,21 +1201,23 @@ func NewGetDeepObjectRequest(server string, params *GetDeepObjectParams) (*http.
return nil, err
}
- queryValues := queryURL.Query()
+ if params != nil {
+ queryValues := queryURL.Query()
- if queryFrag, err := runtime.StyleParamWithLocation("deepObject", true, "deepObj", runtime.ParamLocationQuery, params.DeepObj); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
- return nil, err
- } else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
+ if queryFrag, err := runtime.StyleParamWithLocation("deepObject", true, "deepObj", runtime.ParamLocationQuery, params.DeepObj); err != nil {
+ return nil, err
+ } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ return nil, err
+ } else {
+ for k, v := range parsed {
+ for _, v2 := range v {
+ queryValues.Add(k, v2)
+ }
}
}
- }
- queryURL.RawQuery = queryValues.Encode()
+ queryURL.RawQuery = queryValues.Encode()
+ }
req, err := http.NewRequest("GET", queryURL.String(), nil)
if err != nil {
@@ -1242,148 +1246,150 @@ func NewGetQueryFormRequest(server string, params *GetQueryFormParams) (*http.Re
return nil, err
}
- queryValues := queryURL.Query()
+ if params != nil {
+ queryValues := queryURL.Query()
- if params.Ea != nil {
+ if params.Ea != nil {
- if queryFrag, err := runtime.StyleParamWithLocation("form", true, "ea", runtime.ParamLocationQuery, *params.Ea); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
- return nil, err
- } else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
+ if queryFrag, err := runtime.StyleParamWithLocation("form", true, "ea", runtime.ParamLocationQuery, *params.Ea); err != nil {
+ return nil, err
+ } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ return nil, err
+ } else {
+ for k, v := range parsed {
+ for _, v2 := range v {
+ queryValues.Add(k, v2)
+ }
}
}
- }
- }
+ }
- if params.A != nil {
+ if params.A != nil {
- if queryFrag, err := runtime.StyleParamWithLocation("form", false, "a", runtime.ParamLocationQuery, *params.A); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
- return nil, err
- } else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
+ if queryFrag, err := runtime.StyleParamWithLocation("form", false, "a", runtime.ParamLocationQuery, *params.A); err != nil {
+ return nil, err
+ } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ return nil, err
+ } else {
+ for k, v := range parsed {
+ for _, v2 := range v {
+ queryValues.Add(k, v2)
+ }
}
}
- }
- }
+ }
- if params.Eo != nil {
+ if params.Eo != nil {
- if queryFrag, err := runtime.StyleParamWithLocation("form", true, "eo", runtime.ParamLocationQuery, *params.Eo); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
- return nil, err
- } else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
+ if queryFrag, err := runtime.StyleParamWithLocation("form", true, "eo", runtime.ParamLocationQuery, *params.Eo); err != nil {
+ return nil, err
+ } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ return nil, err
+ } else {
+ for k, v := range parsed {
+ for _, v2 := range v {
+ queryValues.Add(k, v2)
+ }
}
}
- }
- }
+ }
- if params.O != nil {
+ if params.O != nil {
- if queryFrag, err := runtime.StyleParamWithLocation("form", false, "o", runtime.ParamLocationQuery, *params.O); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
- return nil, err
- } else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
+ if queryFrag, err := runtime.StyleParamWithLocation("form", false, "o", runtime.ParamLocationQuery, *params.O); err != nil {
+ return nil, err
+ } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ return nil, err
+ } else {
+ for k, v := range parsed {
+ for _, v2 := range v {
+ queryValues.Add(k, v2)
+ }
}
}
- }
- }
+ }
- if params.Ep != nil {
+ if params.Ep != nil {
- if queryFrag, err := runtime.StyleParamWithLocation("form", true, "ep", runtime.ParamLocationQuery, *params.Ep); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
- return nil, err
- } else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
+ if queryFrag, err := runtime.StyleParamWithLocation("form", true, "ep", runtime.ParamLocationQuery, *params.Ep); err != nil {
+ return nil, err
+ } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ return nil, err
+ } else {
+ for k, v := range parsed {
+ for _, v2 := range v {
+ queryValues.Add(k, v2)
+ }
}
}
- }
- }
+ }
- if params.P != nil {
+ if params.P != nil {
- if queryFrag, err := runtime.StyleParamWithLocation("form", false, "p", runtime.ParamLocationQuery, *params.P); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
- return nil, err
- } else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
+ if queryFrag, err := runtime.StyleParamWithLocation("form", false, "p", runtime.ParamLocationQuery, *params.P); err != nil {
+ return nil, err
+ } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ return nil, err
+ } else {
+ for k, v := range parsed {
+ for _, v2 := range v {
+ queryValues.Add(k, v2)
+ }
}
}
- }
- }
+ }
- if params.Ps != nil {
+ if params.Ps != nil {
- if queryFrag, err := runtime.StyleParamWithLocation("form", true, "ps", runtime.ParamLocationQuery, *params.Ps); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
- return nil, err
- } else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
+ if queryFrag, err := runtime.StyleParamWithLocation("form", true, "ps", runtime.ParamLocationQuery, *params.Ps); err != nil {
+ return nil, err
+ } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ return nil, err
+ } else {
+ for k, v := range parsed {
+ for _, v2 := range v {
+ queryValues.Add(k, v2)
+ }
}
}
+
}
- }
+ if params.Co != nil {
- if params.Co != nil {
+ if queryParamBuf, err := json.Marshal(*params.Co); err != nil {
+ return nil, err
+ } else {
+ queryValues.Add("co", string(queryParamBuf))
+ }
- if queryParamBuf, err := json.Marshal(*params.Co); err != nil {
- return nil, err
- } else {
- queryValues.Add("co", string(queryParamBuf))
}
- }
+ if params.N1s != nil {
- if params.N1s != nil {
-
- if queryFrag, err := runtime.StyleParamWithLocation("form", true, "1s", runtime.ParamLocationQuery, *params.N1s); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
- return nil, err
- } else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
+ if queryFrag, err := runtime.StyleParamWithLocation("form", true, "1s", runtime.ParamLocationQuery, *params.N1s); err != nil {
+ return nil, err
+ } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ return nil, err
+ } else {
+ for k, v := range parsed {
+ for _, v2 := range v {
+ queryValues.Add(k, v2)
+ }
}
}
+
}
+ queryURL.RawQuery = queryValues.Encode()
}
- queryURL.RawQuery = queryValues.Encode()
-
req, err := http.NewRequest("GET", queryURL.String(), nil)
if err != nil {
return nil, err
diff --git a/internal/test/schemas/config.yaml b/internal/test/schemas/config.yaml
index 58b5060d37..9086953659 100644
--- a/internal/test/schemas/config.yaml
+++ b/internal/test/schemas/config.yaml
@@ -5,3 +5,5 @@ generate:
models: true
embedded-spec: true
output: schemas.gen.go
+output-options:
+ skip-prune: true
diff --git a/internal/test/schemas/schemas.gen.go b/internal/test/schemas/schemas.gen.go
index b6a9f2086b..91f73389c6 100644
--- a/internal/test/schemas/schemas.gen.go
+++ b/internal/test/schemas/schemas.gen.go
@@ -48,6 +48,24 @@ type AnyType2 = interface{}
// CustomStringType defines model for CustomStringType.
type CustomStringType = string
+// DeprecatedProperty defines model for DeprecatedProperty.
+type DeprecatedProperty struct {
+ // NewProp Use this now!
+ NewProp string `json:"newProp"`
+ // Deprecated:
+ OldProp1 *string `json:"oldProp1,omitempty"`
+
+ // OldProp2 It used to do this and that
+ // Deprecated:
+ OldProp2 *string `json:"oldProp2,omitempty"`
+ // Deprecated: Use NewProp instead!
+ OldProp3 *string `json:"oldProp3,omitempty"`
+
+ // OldProp4 It used to do this and that
+ // Deprecated: Use NewProp instead!
+ OldProp4 *string `json:"oldProp4,omitempty"`
+}
+
// EnumInObjInArray defines model for EnumInObjInArray.
type EnumInObjInArray = []struct {
Val *EnumInObjInArrayVal `json:"val,omitempty"`
@@ -67,6 +85,17 @@ type NullableProperties struct {
RequiredAndNullable *string `json:"requiredAndNullable"`
}
+// OuterTypeWithAnonymousInner defines model for OuterTypeWithAnonymousInner.
+type OuterTypeWithAnonymousInner struct {
+ Inner InnerRenamedAnonymousObject `json:"inner"`
+ Name string `json:"name"`
+}
+
+// InnerRenamedAnonymousObject defines model for .
+type InnerRenamedAnonymousObject struct {
+ Id int `json:"id"`
+}
+
// StringInPath defines model for StringInPath.
type StringInPath = string
@@ -160,6 +189,9 @@ type ClientInterface interface {
// EnsureEverythingIsReferenced request
EnsureEverythingIsReferenced(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+ // Issue1051 request
+ Issue1051(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+
// Issue127 request
Issue127(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
@@ -184,6 +216,9 @@ type ClientInterface interface {
Issue9WithBody(ctx context.Context, params *Issue9Params, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
Issue9(ctx context.Context, params *Issue9Params, body Issue9JSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // Issue975 request
+ Issue975(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
}
func (c *Client) EnsureEverythingIsReferenced(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
@@ -198,6 +233,18 @@ func (c *Client) EnsureEverythingIsReferenced(ctx context.Context, reqEditors ..
return c.Client.Do(req)
}
+func (c *Client) Issue1051(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewIssue1051Request(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
func (c *Client) Issue127(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewIssue127Request(c.Server)
if err != nil {
@@ -306,6 +353,18 @@ func (c *Client) Issue9(ctx context.Context, params *Issue9Params, body Issue9JS
return c.Client.Do(req)
}
+func (c *Client) Issue975(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewIssue975Request(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
// NewEnsureEverythingIsReferencedRequest generates requests for EnsureEverythingIsReferenced
func NewEnsureEverythingIsReferencedRequest(server string) (*http.Request, error) {
var err error
@@ -333,6 +392,33 @@ func NewEnsureEverythingIsReferencedRequest(server string) (*http.Request, error
return req, nil
}
+// NewIssue1051Request generates requests for Issue1051
+func NewIssue1051Request(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/issues/1051")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest("GET", queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
// NewIssue127Request generates requests for Issue127
func NewIssue127Request(server string) (*http.Request, error) {
var err error
@@ -559,21 +645,23 @@ func NewIssue9RequestWithBody(server string, params *Issue9Params, contentType s
return nil, err
}
- queryValues := queryURL.Query()
+ if params != nil {
+ queryValues := queryURL.Query()
- if queryFrag, err := runtime.StyleParamWithLocation("form", true, "foo", runtime.ParamLocationQuery, params.Foo); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
- return nil, err
- } else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
+ if queryFrag, err := runtime.StyleParamWithLocation("form", true, "foo", runtime.ParamLocationQuery, params.Foo); err != nil {
+ return nil, err
+ } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ return nil, err
+ } else {
+ for k, v := range parsed {
+ for _, v2 := range v {
+ queryValues.Add(k, v2)
+ }
}
}
- }
- queryURL.RawQuery = queryValues.Encode()
+ queryURL.RawQuery = queryValues.Encode()
+ }
req, err := http.NewRequest("GET", queryURL.String(), body)
if err != nil {
@@ -585,6 +673,33 @@ func NewIssue9RequestWithBody(server string, params *Issue9Params, contentType s
return req, nil
}
+// NewIssue975Request generates requests for Issue975
+func NewIssue975Request(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/issues/975")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest("GET", queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
for _, r := range c.RequestEditors {
if err := r(ctx, req); err != nil {
@@ -631,6 +746,9 @@ type ClientWithResponsesInterface interface {
// EnsureEverythingIsReferenced request
EnsureEverythingIsReferencedWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*EnsureEverythingIsReferencedResponse, error)
+ // Issue1051 request
+ Issue1051WithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*Issue1051Response, error)
+
// Issue127 request
Issue127WithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*Issue127Response, error)
@@ -655,6 +773,9 @@ type ClientWithResponsesInterface interface {
Issue9WithBodyWithResponse(ctx context.Context, params *Issue9Params, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*Issue9Response, error)
Issue9WithResponse(ctx context.Context, params *Issue9Params, body Issue9JSONRequestBody, reqEditors ...RequestEditorFn) (*Issue9Response, error)
+
+ // Issue975 request
+ Issue975WithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*Issue975Response, error)
}
type EnsureEverythingIsReferencedResponse struct {
@@ -687,6 +808,29 @@ func (r EnsureEverythingIsReferencedResponse) StatusCode() int {
return 0
}
+type Issue1051Response struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *map[string]interface{}
+ ApplicationvndSomethingV1JSON200 *map[string]interface{}
+}
+
+// Status returns HTTPResponse.Status
+func (r Issue1051Response) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r Issue1051Response) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
type Issue127Response struct {
Body []byte
HTTPResponse *http.Response
@@ -839,6 +983,28 @@ func (r Issue9Response) StatusCode() int {
return 0
}
+type Issue975Response struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *DeprecatedProperty
+}
+
+// Status returns HTTPResponse.Status
+func (r Issue975Response) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r Issue975Response) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
// EnsureEverythingIsReferencedWithResponse request returning *EnsureEverythingIsReferencedResponse
func (c *ClientWithResponses) EnsureEverythingIsReferencedWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*EnsureEverythingIsReferencedResponse, error) {
rsp, err := c.EnsureEverythingIsReferenced(ctx, reqEditors...)
@@ -848,6 +1014,15 @@ func (c *ClientWithResponses) EnsureEverythingIsReferencedWithResponse(ctx conte
return ParseEnsureEverythingIsReferencedResponse(rsp)
}
+// Issue1051WithResponse request returning *Issue1051Response
+func (c *ClientWithResponses) Issue1051WithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*Issue1051Response, error) {
+ rsp, err := c.Issue1051(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseIssue1051Response(rsp)
+}
+
// Issue127WithResponse request returning *Issue127Response
func (c *ClientWithResponses) Issue127WithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*Issue127Response, error) {
rsp, err := c.Issue127(ctx, reqEditors...)
@@ -927,6 +1102,15 @@ func (c *ClientWithResponses) Issue9WithResponse(ctx context.Context, params *Is
return ParseIssue9Response(rsp)
}
+// Issue975WithResponse request returning *Issue975Response
+func (c *ClientWithResponses) Issue975WithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*Issue975Response, error) {
+ rsp, err := c.Issue975(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseIssue975Response(rsp)
+}
+
// ParseEnsureEverythingIsReferencedResponse parses an HTTP response from a EnsureEverythingIsReferencedWithResponse call
func ParseEnsureEverythingIsReferencedResponse(rsp *http.Response) (*EnsureEverythingIsReferencedResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
@@ -961,6 +1145,32 @@ func ParseEnsureEverythingIsReferencedResponse(rsp *http.Response) (*EnsureEvery
return response, nil
}
+// ParseIssue1051Response parses an HTTP response from a Issue1051WithResponse call
+func ParseIssue1051Response(rsp *http.Response) (*Issue1051Response, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &Issue1051Response{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest map[string]interface{}
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.ApplicationvndSomethingV1JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
// ParseIssue127Response parses an HTTP response from a Issue127WithResponse call
func ParseIssue127Response(rsp *http.Response) (*Issue127Response, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
@@ -1120,12 +1330,41 @@ func ParseIssue9Response(rsp *http.Response) (*Issue9Response, error) {
return response, nil
}
+// ParseIssue975Response parses an HTTP response from a Issue975WithResponse call
+func ParseIssue975Response(rsp *http.Response) (*Issue975Response, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &Issue975Response{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest DeprecatedProperty
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
// ServerInterface represents all server handlers.
type ServerInterface interface {
// (GET /ensure-everything-is-referenced)
EnsureEverythingIsReferenced(ctx echo.Context) error
+ // (GET /issues/1051)
+ Issue1051(ctx echo.Context) error
+
// (GET /issues/127)
Issue127(ctx echo.Context) error
@@ -1146,6 +1385,9 @@ type ServerInterface interface {
// (GET /issues/9)
Issue9(ctx echo.Context, params Issue9Params) error
+
+ // (GET /issues/975)
+ Issue975(ctx echo.Context) error
}
// ServerInterfaceWrapper converts echo contexts to parameters.
@@ -1157,18 +1399,29 @@ type ServerInterfaceWrapper struct {
func (w *ServerInterfaceWrapper) EnsureEverythingIsReferenced(ctx echo.Context) error {
var err error
- ctx.Set(Access_tokenScopes, []string{""})
+ ctx.Set(Access_tokenScopes, []string{})
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.EnsureEverythingIsReferenced(ctx)
return err
}
+// Issue1051 converts echo context to params.
+func (w *ServerInterfaceWrapper) Issue1051(ctx echo.Context) error {
+ var err error
+
+ ctx.Set(Access_tokenScopes, []string{})
+
+ // Invoke the callback with all the unmarshalled arguments
+ err = w.Handler.Issue1051(ctx)
+ return err
+}
+
// Issue127 converts echo context to params.
func (w *ServerInterfaceWrapper) Issue127(ctx echo.Context) error {
var err error
- ctx.Set(Access_tokenScopes, []string{""})
+ ctx.Set(Access_tokenScopes, []string{})
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.Issue127(ctx)
@@ -1179,7 +1432,7 @@ func (w *ServerInterfaceWrapper) Issue127(ctx echo.Context) error {
func (w *ServerInterfaceWrapper) Issue185(ctx echo.Context) error {
var err error
- ctx.Set(Access_tokenScopes, []string{""})
+ ctx.Set(Access_tokenScopes, []string{})
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.Issue185(ctx)
@@ -1197,7 +1450,7 @@ func (w *ServerInterfaceWrapper) Issue209(ctx echo.Context) error {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter str: %s", err))
}
- ctx.Set(Access_tokenScopes, []string{""})
+ ctx.Set(Access_tokenScopes, []string{})
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.Issue209(ctx, str)
@@ -1215,7 +1468,7 @@ func (w *ServerInterfaceWrapper) Issue30(ctx echo.Context) error {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter fallthrough: %s", err))
}
- ctx.Set(Access_tokenScopes, []string{""})
+ ctx.Set(Access_tokenScopes, []string{})
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.Issue30(ctx, pFallthrough)
@@ -1226,7 +1479,7 @@ func (w *ServerInterfaceWrapper) Issue30(ctx echo.Context) error {
func (w *ServerInterfaceWrapper) GetIssues375(ctx echo.Context) error {
var err error
- ctx.Set(Access_tokenScopes, []string{""})
+ ctx.Set(Access_tokenScopes, []string{})
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.GetIssues375(ctx)
@@ -1244,7 +1497,7 @@ func (w *ServerInterfaceWrapper) Issue41(ctx echo.Context) error {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter 1param: %s", err))
}
- ctx.Set(Access_tokenScopes, []string{""})
+ ctx.Set(Access_tokenScopes, []string{})
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.Issue41(ctx, n1param)
@@ -1255,7 +1508,7 @@ func (w *ServerInterfaceWrapper) Issue41(ctx echo.Context) error {
func (w *ServerInterfaceWrapper) Issue9(ctx echo.Context) error {
var err error
- ctx.Set(Access_tokenScopes, []string{""})
+ ctx.Set(Access_tokenScopes, []string{})
// Parameter object where we will unmarshal all parameters from the context
var params Issue9Params
@@ -1271,6 +1524,17 @@ func (w *ServerInterfaceWrapper) Issue9(ctx echo.Context) error {
return err
}
+// Issue975 converts echo context to params.
+func (w *ServerInterfaceWrapper) Issue975(ctx echo.Context) error {
+ var err error
+
+ ctx.Set(Access_tokenScopes, []string{})
+
+ // Invoke the callback with all the unmarshalled arguments
+ err = w.Handler.Issue975(ctx)
+ return err
+}
+
// This is a simple interface which specifies echo.Route addition functions which
// are present on both echo.Echo and echo.Group, since we want to allow using
// either of them for path registration
@@ -1300,6 +1564,7 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
}
router.GET(baseURL+"/ensure-everything-is-referenced", wrapper.EnsureEverythingIsReferenced)
+ router.GET(baseURL+"/issues/1051", wrapper.Issue1051)
router.GET(baseURL+"/issues/127", wrapper.Issue127)
router.GET(baseURL+"/issues/185", wrapper.Issue185)
router.GET(baseURL+"/issues/209/$:str", wrapper.Issue209)
@@ -1307,33 +1572,39 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
router.GET(baseURL+"/issues/375", wrapper.GetIssues375)
router.GET(baseURL+"/issues/41/:1param", wrapper.Issue41)
router.GET(baseURL+"/issues/9", wrapper.Issue9)
+ router.GET(baseURL+"/issues/975", wrapper.Issue975)
}
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
- "H4sIAAAAAAAC/7RX0W/buA/+Vwj9BvxenDjNNmzNW2/YDT3gtmItsIemD4rNxFptypPotkaQ//1AyamT",
- "xelt160vjS1R5PeR/ESvVWar2hISezVbq1o7XSGjC0+X7AytzulCcyHPOfrMmZqNJTVTZ+DDOtSaC3i0",
- "VIkysixvVaJIV6hmyrMsOPzWGIe5mrFrMFE+K7DScjS3dbfN0EptNpvtYgjk9SVrx/6L4eJjUy3QHUZz",
- "VRgP0QTEJ/hgAveGC9BA0SzZOrKLr5ix2iTqjNqrtsYTNVv3T9MBuN0KOKwdemEMNLUgB47nNKcYQWGb",
- "MocFgiYwxOiWOsP1Zk7i613j2VaR1qsQyFotras0q5nKwmIfYsdFoh5GVtdmlNkcV0gjfGCnR6xXPppb",
- "NVML7ZRw9p6a6pw+Lb6e05lzupUdhrGKyXW2RscGw9OdLuUfUlOp2bVaGudZJcpjZilXN8lBSga4617o",
- "4GqTqA9I6Ez2KW7o09pbfGzKUi9KvNiLZT8yGyiP4X0XRPK4eEb59izZR4+/Y2Ud2PWltz6++HOH7p16",
- "3f8ePu/mgL9NYLtxhttLKdyIXmcZej9ie4skzwvUDt2f2yr568vVKJYMxJ0Qdo7npLqWERfRqK+lgrmO",
- "XWVoaQe6Bz1Dpj16WFoHd9oZ23gw3jfhVUM52Dt0wKbCMVyUqD2CznPQwFtbMZ2T9MSiWcHSPGAew2LD",
- "QmL0conuLoR2h85H7yfjyXgSk4uka6Nm6uV4Mj5RSVCRQEuK5BuHI7xD13JhaDUyfuRwiQ4pi3ldIR8R",
- "BqS8toYY8MF49uAtcKEZevWDTJO0beZQM+ZgCLgwfk6+xgw05UCWZUPtGsI84JKi1eLmPFcz9T4E+P4x",
- "vnP/uY9OasLXlnxM8nQykX+ZJUYKQeu6Lk0WTku/ehtS38vjfoPoXrLUC4dLNVP/S3soaaec6aO0bZKt",
- "zfQHbaZikw3I1VO2B/I2IBrxL1FprK30ZPrmaOr+1rcIQio05Ju6tk4yE0h74CC8HnJL/2eoHWJVM/S7",
- "wup4IE3n4le8PjMlTxGxr4MCd/esh6p8zlECPq20u83tPT37oFY/Jxo5Jselbkr+jeT9IsTfV97b18dF",
- "o60RVmIfEMB9gQTbqyfdyjv0bQnaIWzvi+Nl9/Z1dzug5z9s3v4y0gbu1Yh2p8YlvF0CppPT9MXas9sc",
- "5eFdgdmtB7Ps57sINces1D0FZTsMeDo5VYcxJHtz5vUwsn5LujeHbm52ILycpOulLksunG1WxeYQwWf0",
- "cuHkcIvtvXX57ohWOwy3lIi9XHlCYBgeO+HoKBnA9XLyI7AG5uCdYH9qHt4D/eZ44coA2CWnq1ztt4Us",
- "qnhvMpR0coEgo19YNyTTalToOd0XJiu6997kCHYpy2HIG6rsD8iBEy9x/UZRPZhtDzr61Um6Pgk5OF7R",
- "F9sU7XwlyEdM+E54/EoYSPmrOI78W4Kj/ydz+xTIwy+dzebmyS4+Pd68pUHi2Lk+XIhgKLPOYcZlK7/L",
- "Jsc8THydJkUaFjZvZeSZU4/3qKadHqHlW4Ou3Sl8a3+u4P+zTnaX0i4TnzrlDsjUkCruzOIBwv4Ufn0j",
- "8QQh6SA2ruzG6lmadmOrDMLjHLGudD3WRpTqnwAAAP//yJQBrWAPAAA=",
+ "H4sIAAAAAAAC/7RYXW/buBL9Kyxvgftw/Z0GbfyW2+0WLrBJ0GTRhzoPtDi22EhDlaTsCIb++2JI2bIj",
+ "yW02bV5iiZzhmTPDM6S2PNJpphHQWT7d8kwYkYID459unVG4muGNcDE9S7CRUZlTGvmUXzLrx1kmXMz2",
+ "lrzHFQ3TW97jKFLgU24dDRj4nisDkk+dyaHHbRRDKsi1K7JqmsIVL8tyN+iBnN86YZz9olx8lacLME00",
+ "d7GyLJgwWpNZb8I2ysVMMAxmvd1CevENIsfLHr/E4q7IYMyn2/pp0hJuNcIMZAYsMcYEFowcDuY4x4Ag",
+ "1nki2QKYQKbQgVmKCLblHGmt97l1Og203nkgW77UJhWOT3nkB2uIFRc9/tjXIlP9SEtYAfbh0RnRd2Jl",
+ "g7nmU74QhhNnfxC2SDiQN0ZnYFzhsxp+K/AWCBsabEb4twXmKAjUm1cNHGWP68S7HQfT3Uq7ZHZNn7RP",
+ "P1575lhuQTKnmdQBhUDJXCzcCSRnP4OECKzn9A0Iuw/3KnDBFFoHQr468P3mV8N+Ho7ycLd83SdtD4/f",
+ "t9TyB8zTGV4vvs3w0hjhk68cpLZZBWuR0D/APCX/S2UsQbYQaZQHzvc7smW56oXwS5U9/hEQjIquw4R6",
+ "V9cWV3mSiEUCN0dYjpFpT26A10x8NXiJcufL1/T+d0ct1lxuuwef5/RJhva/2/21pes6d2BIB0jYLlFj",
+ "kerczhCDwB3TojpeH4ZEgrMC08CmZHN9KseV7tPLfiXSfuXPQE9yD+d6DzfM2v6ABz+rV8FtRl36GsuN",
+ "csUtqXWIQkQRWNt3+gGQnhcgDJg/d9L46ctdP+gkCzOZnzmYI6/6BC0RjOp9FzuXhVaicKlbWgZYxyJh",
+ "wbKlNmwtjNK5Zcra3L/KUTK9BsOcSmHAbhIQFpiQkgnmdrZkOkdqBIt8xZbqEWSA5ZSj0gmr3IJZe2hr",
+ "MDasPh6MBqNQ0oAiU3zKzwajwZj3fOv0tAwBbW6gD2swhYsVrvrK9g0swQBGoZpX4Dq6IaDMtELH4FFZ",
+ "Z5nVXphY3fJZJJB6VWSANIkp9Bo2R5tB5JUMtaMJmckRpI+Lik/QMjPJp/yDB/hhj29mP9foqDBsptGG",
+ "JE9GI/oXaXSAHrTIskRF3tvwm1fD7cGZ4LjQRd2n+WsDSz7l/xnWoQyr48Jw38/L3s5m8pM2E7KJWnr0",
+ "KdtGT2+RyvDX48NQW8Px6Hzcmbu/8sSpLAGWglTCny8sI9KEQvbp9vqqJQ0z8uu9vpDz5m49nL9GObA6",
+ "BZ/qwXr8vx87eBr55G134OIBGJUTy9HmWaYN1aSH/ugqHqTG/zqWGYA0c6ye5UcHncxM3r6UmFMlcNz3",
+ "npL2mCYvcUXBD1NhHqTe4IsdFeIlaMiNhKXIE/cbyftFET+tvHfn3XJZZMBWZO8jYJsYkO2OGsNdd2O1",
+ "IDFhgO3OB91l9+68Og2Adf/XsvhlpLWco0K0BzVO8A4JmIwuhq+31pmyk4f3MUQPlqllfZ0LoUqIElFT",
+ "kBTtAU9GF7yJoXd0rfzaHlk9ZXh07SzvD0I4Gw23S5EkLjY6X8VlM4LPYKnVSvYAxUYbeXgjywz4/kxt",
+ "jpo9EejvipVwVJS0xHU2+pmwWq69B2Cfdf09Cvptd+HSgb9KTlW5wu4KmVRxoyKgdLoYGB31/bhCupwG",
+ "hZ7jJlZRXL23SgLTSxr2h/q2yv4IznNiCddvFNXGXaaxo9+Mh9uxz0F3Rd/sUnTwUUDhKnwW2H8UaEn5",
+ "m3AQ+1GCw/onc3sqyOaHjbK8P7mLL7o3b6IAXdi51jdEpjDSxkDkkoJ+J7kE6c+6lSYFGhZaFnTYm2Md",
+ "b6emXXTQ8j0HUxwUvtbPK/h/rZNVUzpk4rpSbh8ZP62KFyd2V/01hS0VJLWYrMAxUWkhHadTQNdJ2O/d",
+ "Ji1ffFoY8d/q8qhKuGzE5V+vhSlobySwhoRkQOoop9A8Ll7tvt3tzaf++N729Z7y6AW4Ko3cJNVFbDoc",
+ "VhcdujoNJECWimwgFCn8PwEAAP//WUiKvIcUAAA=",
}
// GetSwagger returns the content of the embedded swagger specification file
diff --git a/internal/test/schemas/schemas.yaml b/internal/test/schemas/schemas.yaml
index 3d73527c60..2e094de126 100644
--- a/internal/test/schemas/schemas.yaml
+++ b/internal/test/schemas/schemas.yaml
@@ -121,6 +121,32 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/EnumInObjInArray"
+ /issues/975:
+ get:
+ operationId: Issue975
+ description: |
+ Deprecated fields should get a proper comment
+ responses:
+ 200:
+ description: A struct with deprecated fields with varying level of documentation
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/DeprecatedProperty"
+ /issues/1051:
+ get:
+ operationId: Issue1051
+ description: |
+ Multiple media types contain JSON
+ responses:
+ '200':
+ content:
+ application/vnd.something.v1+json:
+ schema:
+ type: object
+ application/json:
+ schema:
+ type: object
components:
schemas:
GenericObject:
@@ -165,6 +191,45 @@ components:
enum:
- first
- second
+ DeprecatedProperty:
+ type: object
+ required:
+ - newProp
+ - oldProp
+ properties:
+ newProp:
+ type: string
+ description: Use this now!
+ oldProp1:
+ type: string
+ deprecated: true
+ # description: No description on this one to test generation in that case
+ oldProp2:
+ type: string
+ deprecated: true
+ description: It used to do this and that
+ oldProp3:
+ type: string
+ deprecated: true
+ x-deprecated-reason: Use NewProp instead!
+ oldProp4:
+ type: string
+ deprecated: true
+ x-deprecated-reason: Use NewProp instead!
+ description: It used to do this and that
+ OuterTypeWithAnonymousInner:
+ type: object
+ properties:
+ name:
+ type: string
+ inner:
+ type: object
+ x-go-type-name: InnerRenamedAnonymousObject
+ properties:
+ id:
+ type: integer
+ required: [ id ]
+ required: [ name, inner ]
parameters:
StringInPath:
name: str
@@ -183,4 +248,3 @@ components:
JWT-format access token.
security:
- access-token: [ ]
-
diff --git a/internal/test/strict-server/chi/server.gen.go b/internal/test/strict-server/chi/server.gen.go
index 124c057d2f..b3904b50e6 100644
--- a/internal/test/strict-server/chi/server.gen.go
+++ b/internal/test/strict-server/chi/server.gen.go
@@ -34,6 +34,9 @@ type ServerInterface interface {
// (POST /multiple)
MultipleRequestAndResponseTypes(w http.ResponseWriter, r *http.Request)
+ // (GET /reserved-go-keyword-parameters/{type})
+ ReservedGoKeywordParameters(w http.ResponseWriter, r *http.Request, pType string)
+
// (POST /reusable-responses)
ReusableResponses(w http.ResponseWriter, r *http.Request)
@@ -107,6 +110,32 @@ func (siw *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(w http.Respon
handler.ServeHTTP(w, r.WithContext(ctx))
}
+// ReservedGoKeywordParameters operation middleware
+func (siw *ServerInterfaceWrapper) ReservedGoKeywordParameters(w http.ResponseWriter, r *http.Request) {
+ ctx := r.Context()
+
+ var err error
+
+ // ------------- Path parameter "type" -------------
+ var pType string
+
+ err = runtime.BindStyledParameterWithLocation("simple", false, "type", runtime.ParamLocationPath, chi.URLParam(r, "type"), &pType)
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "type", Err: err})
+ return
+ }
+
+ var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.ReservedGoKeywordParameters(w, r, pType)
+ })
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r.WithContext(ctx))
+}
+
// ReusableResponses operation middleware
func (siw *ServerInterfaceWrapper) ReusableResponses(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
@@ -368,6 +397,9 @@ func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handl
r.Group(func(r chi.Router) {
r.Post(options.BaseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes)
})
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/reserved-go-keyword-parameters/{type}", wrapper.ReservedGoKeywordParameters)
+ })
r.Group(func(r chi.Router) {
r.Post(options.BaseURL+"/reusable-responses", wrapper.ReusableResponses)
})
@@ -553,6 +585,24 @@ func (response MultipleRequestAndResponseTypes400Response) VisitMultipleRequestA
return nil
}
+type ReservedGoKeywordParametersRequestObject struct {
+ Type string `json:"type"`
+}
+
+type ReservedGoKeywordParametersResponseObject interface {
+ VisitReservedGoKeywordParametersResponse(w http.ResponseWriter) error
+}
+
+type ReservedGoKeywordParameters200TextResponse string
+
+func (response ReservedGoKeywordParameters200TextResponse) VisitReservedGoKeywordParametersResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "text/plain")
+ w.WriteHeader(200)
+
+ _, err := w.Write([]byte(response))
+ return err
+}
+
type ReusableResponsesRequestObject struct {
Body *ReusableResponsesJSONRequestBody
}
@@ -820,6 +870,9 @@ type StrictServerInterface interface {
// (POST /multiple)
MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, error)
+ // (GET /reserved-go-keyword-parameters/{type})
+ ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error)
+
// (POST /reusable-responses)
ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error)
@@ -839,9 +892,8 @@ type StrictServerInterface interface {
HeadersExample(ctx context.Context, request HeadersExampleRequestObject) (HeadersExampleResponseObject, error)
}
-type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, args interface{}) (interface{}, error)
-
-type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+type StrictHandlerFunc = runtime.StrictHttpHandlerFunc
+type StrictMiddlewareFunc = runtime.StrictHttpMiddlewareFunc
type StrictHTTPServerOptions struct {
RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
@@ -996,6 +1048,32 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(w http.ResponseWriter,
}
}
+// ReservedGoKeywordParameters operation middleware
+func (sh *strictHandler) ReservedGoKeywordParameters(w http.ResponseWriter, r *http.Request, pType string) {
+ var request ReservedGoKeywordParametersRequestObject
+
+ request.Type = pType
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.ReservedGoKeywordParameters(ctx, request.(ReservedGoKeywordParametersRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "ReservedGoKeywordParameters")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(ReservedGoKeywordParametersResponseObject); ok {
+ if err := validResponse.VisitReservedGoKeywordParametersResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("Unexpected response type: %T", response))
+ }
+}
+
// ReusableResponses operation middleware
func (sh *strictHandler) ReusableResponses(w http.ResponseWriter, r *http.Request) {
var request ReusableResponsesRequestObject
@@ -1184,21 +1262,23 @@ func (sh *strictHandler) HeadersExample(w http.ResponseWriter, r *http.Request,
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
- "H4sIAAAAAAAC/+xYS4/iOBD+K1btnkaB0D194rbTGmnfI9Ezp9UcirgAzya2166QRoj/vnJsaBjSCFo8",
- "pNXeEqde/qq+KsdLKExljSbNHoZLcOSt0Z7alzFKR//U5Dm8SfKFU5aV0TCEDyhH6dsqA0e1x3FJa/Ug",
- "XxjNpFtVtLZUBQbV/JsP+kvwxYwqDE8/OprAEH7IX0LJ41ef0zNWtiRYrVbZdxF8+g0ymBFKcm208fFu",
- "1zYvLMEQPDulpxCMRLH7TjGlmabkgrcgmoIIAus4hkuwzlhyrCJGcyxr6vaUVsz4GxUcd6D0xOxj+Wg0",
- "o9JeSDWZkCPNIoEngg0vfG2tcUxSjBcieChYeHJzcpABKw6BwdP2ukgBe8hgTs5HR3f9QX8Q8mUsabQK",
- "hvC+XcrAIs/aDW0SZE1X3n99+vSnUF5gzaZCVgWW5UJU6PwMy5KkUJpNiLEu2PehdeXazP8ik/rHhGUo",
- "m7aCPhi5uETFtIW5Vc/3g8GVCnOVwUN01mVjE1S+xbDWzATrsgP0L/pvbRotyDnj0s7yqi5ZWXS8naxd",
- "tP9YixwD+cZePjGu6klkvBDq5/J0U+BTM+gkydPMNF7MTCPYCElYikbxTKwVv2O30gKFV3paklgHlXVm",
- "sqTUc3/ScpT28jnYuDiXsh0rz72maXpt8mpXki6MJPk2s6rCKeVWT3fVg21kGMJ4waFs97vrmYooA6Zn",
- "zm2JSh8eHVdqJ/8jfTZiR7quzya9neR1E3dNKi8K1GIc+DjxgcRdvvZIOkqeRlsStxlxhzHaO61do2uG",
- "5L8+qT7T81FD6oxkvXY1ngpYHRdfxyxpHQPbG7l/BIpzJcnklX040fLNQPWWCjVRJHtpF70Y22st4dHo",
- "whHvDu1wAtaGxcZYOJjzjEREIBPeiIZEVXsWFr0XitsuUqp4uJe01zy+vET2GD2FyX5EVt9dKKfvbpXR",
- "h8Hd6SrvL1w3O8P3FT6Ofv8YZU79wznblD/xjHI+vzeiczhW97buALop/HMUeJnpBak5SYFaCkdcO01S",
- "zBWuf1v3uJkMvKTVosOKuPX61xLCCEkXC5CBxoo273epCJQLyLKrKTt0PXHQ1j1kh+4svv6Hf6gvedNz",
- "6TpdZRAvZWKx1K4MGWW2wzyPlzl93+B0Sq6vTI5Wwerr6t8AAAD//ygSomqZEwAA",
+ "H4sIAAAAAAAC/+xYX2/bNhD/KgS3p0KynDRPeluDotu6rYOTPg15oMWzzFYiuePJimHouw8UJf+pFS/O",
+ "7BgY+mbRd787/u4Pj1zxzJTWaNDkeLriCM4a7aD9mAqJ8HcFjvyXBJehsqSM5il/J+Sk+6+JOELlxLSA",
+ "Xt3LZ0YT6FZVWFuoTHjV5Ivz+ivusjmUwv/6EWHGU/5DsnElCf+6BB5FaQvgTdNE33jw6SOP+ByEBGy9",
+ "DT+vdrFpaYGn3BEqnXMPEsSuB8WUJsgBvTUv2jnhBXo/0hW3aCwgqcDRQhQVDFvqVsz0C2QUdqD0zOxz",
+ "eWs0CaUdk2o2AwRNrCOPeQzHXGWtQQLJpkvmLWTEHOACkEecFHnH+N32OuscdjziC0AXDF2NxqOxj5ex",
+ "oIVVPOVv26WIW0HzdkPrAFkzFPdf7z79wZRjoiJTClKZKIolKwW6uSgKkExpMt7HKiM34q0pbCP/i+zU",
+ "33dc+rRpM+idkctzZEybmFv5fD0ev1JiNhG/CcaGMNZOJVsV1sLMRFUMkP5Zf9Wm1gwQDXY7S8qqIGUF",
+ "0nawdtn+vRd5DuVrvGRmsIylIHEm1k9l6aLEd81gsEju5qZ2bG5qRoZJEAWrFc1Zr/hNdSvNBHNK5wWw",
+ "3qloMJIFdD33Jy0n3V7uPcbZaynaQXmM67qO2+BVWIDOjAT5MlhVihwSq/NddY8tiKd8uiSftvvd9URJ",
+ "FHGCR0psIZQ+fHS8Ujv5zvTJCjuUK0J7JMo4N/FXWNYGZWwFihII0CUrb73xwDkMlPKfa0mWCc2mwLQo",
+ "QTIxI0D2wbAO0u2V7KSz+8F8DCIbqPa8XX+kf624p6Q9g3nEvQGeBlZCXSv0QSesIDpA28O/5ud/CkDP",
+ "Zpj04h1Tw22wb1Fr6hBmzrfEocgN8BcsTbYkLjMwHM64vdn3Nc4gH8mnz/17eHzWkX/C1vfatX0sYVVY",
+ "fJqzTus5tL2wkz6DxYWSYJLS3hyJfDFSnYVMzRTIuNtFHHx7qiXcGp0h0O4I5O8T2hBbg/lrDs2BBQYi",
+ "5gyrgZWVI2aFc0xR20UKFa5KEvaax+eNZ7fB0v2mnR6K6pszxfTNpSJ6M746XuXtmfNmZ5R5oh4nv70P",
+ "MsfeF082Mx058Z3O7oXK2V9S4q0XleES/jkIbM70DNTCT0RaMgSqUINkCyX6R4C92uwANmEdmoWCG5tp",
+ "qH/dOWYgig5iXfPo0AvQw//4eeKc72bnztMm4uGJKyRLhYWPKJFNkyQ8jY1cLfIccKRMIqzizUPzTwAA",
+ "AP//O0NNuucUAAA=",
}
// GetSwagger returns the content of the embedded swagger specification file
diff --git a/internal/test/strict-server/chi/server.go b/internal/test/strict-server/chi/server.go
index 5b7026809e..b0724db19f 100644
--- a/internal/test/strict-server/chi/server.go
+++ b/internal/test/strict-server/chi/server.go
@@ -100,3 +100,7 @@ func (s StrictServer) HeadersExample(ctx context.Context, request HeadersExample
func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error) {
return ReusableResponses200JSONResponse{ReusableresponseJSONResponse: ReusableresponseJSONResponse{Body: *request.Body}}, nil
}
+
+func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) {
+ return ReservedGoKeywordParameters200TextResponse(""), nil
+}
diff --git a/internal/test/strict-server/client/client.gen.go b/internal/test/strict-server/client/client.gen.go
index 68105f2f24..5ec0210b50 100644
--- a/internal/test/strict-server/client/client.gen.go
+++ b/internal/test/strict-server/client/client.gen.go
@@ -156,6 +156,9 @@ type ClientInterface interface {
MultipleRequestAndResponseTypesWithTextBody(ctx context.Context, body MultipleRequestAndResponseTypesTextRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+ // ReservedGoKeywordParameters request
+ ReservedGoKeywordParameters(ctx context.Context, pType string, reqEditors ...RequestEditorFn) (*http.Response, error)
+
// ReusableResponses request with any body
ReusableResponsesWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
@@ -267,6 +270,18 @@ func (c *Client) MultipleRequestAndResponseTypesWithTextBody(ctx context.Context
return c.Client.Do(req)
}
+func (c *Client) ReservedGoKeywordParameters(ctx context.Context, pType string, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewReservedGoKeywordParametersRequest(c.Server, pType)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
func (c *Client) ReusableResponsesWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewReusableResponsesRequestWithBody(c.Server, contentType, body)
if err != nil {
@@ -514,6 +529,40 @@ func NewMultipleRequestAndResponseTypesRequestWithBody(server string, contentTyp
return req, nil
}
+// NewReservedGoKeywordParametersRequest generates requests for ReservedGoKeywordParameters
+func NewReservedGoKeywordParametersRequest(server string, pType string) (*http.Request, error) {
+ var err error
+
+ var pathParam0 string
+
+ pathParam0, err = runtime.StyleParamWithLocation("simple", false, "type", runtime.ParamLocationPath, pType)
+ if err != nil {
+ return nil, err
+ }
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/reserved-go-keyword-parameters/%s", pathParam0)
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest("GET", queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
// NewReusableResponsesRequest calls the generic ReusableResponses builder with application/json body
func NewReusableResponsesRequest(server string, body ReusableResponsesJSONRequestBody) (*http.Request, error) {
var bodyReader io.Reader
@@ -808,6 +857,9 @@ type ClientWithResponsesInterface interface {
MultipleRequestAndResponseTypesWithTextBodyWithResponse(ctx context.Context, body MultipleRequestAndResponseTypesTextRequestBody, reqEditors ...RequestEditorFn) (*MultipleRequestAndResponseTypesResponse, error)
+ // ReservedGoKeywordParameters request
+ ReservedGoKeywordParametersWithResponse(ctx context.Context, pType string, reqEditors ...RequestEditorFn) (*ReservedGoKeywordParametersResponse, error)
+
// ReusableResponses request with any body
ReusableResponsesWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*ReusableResponsesResponse, error)
@@ -900,6 +952,27 @@ func (r MultipleRequestAndResponseTypesResponse) StatusCode() int {
return 0
}
+type ReservedGoKeywordParametersResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// Status returns HTTPResponse.Status
+func (r ReservedGoKeywordParametersResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r ReservedGoKeywordParametersResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
type ReusableResponsesResponse struct {
Body []byte
HTTPResponse *http.Response
@@ -1087,6 +1160,15 @@ func (c *ClientWithResponses) MultipleRequestAndResponseTypesWithTextBodyWithRes
return ParseMultipleRequestAndResponseTypesResponse(rsp)
}
+// ReservedGoKeywordParametersWithResponse request returning *ReservedGoKeywordParametersResponse
+func (c *ClientWithResponses) ReservedGoKeywordParametersWithResponse(ctx context.Context, pType string, reqEditors ...RequestEditorFn) (*ReservedGoKeywordParametersResponse, error) {
+ rsp, err := c.ReservedGoKeywordParameters(ctx, pType, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseReservedGoKeywordParametersResponse(rsp)
+}
+
// ReusableResponsesWithBodyWithResponse request with arbitrary body returning *ReusableResponsesResponse
func (c *ClientWithResponses) ReusableResponsesWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*ReusableResponsesResponse, error) {
rsp, err := c.ReusableResponsesWithBody(ctx, contentType, body, reqEditors...)
@@ -1244,6 +1326,22 @@ func ParseMultipleRequestAndResponseTypesResponse(rsp *http.Response) (*Multiple
return response, nil
}
+// ParseReservedGoKeywordParametersResponse parses an HTTP response from a ReservedGoKeywordParametersWithResponse call
+func ParseReservedGoKeywordParametersResponse(rsp *http.Response) (*ReservedGoKeywordParametersResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &ReservedGoKeywordParametersResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
+
// ParseReusableResponsesResponse parses an HTTP response from a ReusableResponsesWithResponse call
func ParseReusableResponsesResponse(rsp *http.Response) (*ReusableResponsesResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
diff --git a/internal/test/strict-server/echo/server.gen.go b/internal/test/strict-server/echo/server.gen.go
index 46531bd8a4..0912230952 100644
--- a/internal/test/strict-server/echo/server.gen.go
+++ b/internal/test/strict-server/echo/server.gen.go
@@ -34,6 +34,9 @@ type ServerInterface interface {
// (POST /multiple)
MultipleRequestAndResponseTypes(ctx echo.Context) error
+ // (GET /reserved-go-keyword-parameters/{type})
+ ReservedGoKeywordParameters(ctx echo.Context, pType string) error
+
// (POST /reusable-responses)
ReusableResponses(ctx echo.Context) error
@@ -85,6 +88,22 @@ func (w *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(ctx echo.Contex
return err
}
+// ReservedGoKeywordParameters converts echo context to params.
+func (w *ServerInterfaceWrapper) ReservedGoKeywordParameters(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "type" -------------
+ var pType string
+
+ err = runtime.BindStyledParameterWithLocation("simple", false, "type", runtime.ParamLocationPath, ctx.Param("type"), &pType)
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter type: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshalled arguments
+ err = w.Handler.ReservedGoKeywordParameters(ctx, pType)
+ return err
+}
+
// ReusableResponses converts echo context to params.
func (w *ServerInterfaceWrapper) ReusableResponses(ctx echo.Context) error {
var err error
@@ -207,6 +226,7 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
router.POST(baseURL+"/json", wrapper.JSONExample)
router.POST(baseURL+"/multipart", wrapper.MultipartExample)
router.POST(baseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes)
+ router.GET(baseURL+"/reserved-go-keyword-parameters/:type", wrapper.ReservedGoKeywordParameters)
router.POST(baseURL+"/reusable-responses", wrapper.ReusableResponses)
router.POST(baseURL+"/text", wrapper.TextExample)
router.POST(baseURL+"/unknown", wrapper.UnknownExample)
@@ -379,6 +399,24 @@ func (response MultipleRequestAndResponseTypes400Response) VisitMultipleRequestA
return nil
}
+type ReservedGoKeywordParametersRequestObject struct {
+ Type string `json:"type"`
+}
+
+type ReservedGoKeywordParametersResponseObject interface {
+ VisitReservedGoKeywordParametersResponse(w http.ResponseWriter) error
+}
+
+type ReservedGoKeywordParameters200TextResponse string
+
+func (response ReservedGoKeywordParameters200TextResponse) VisitReservedGoKeywordParametersResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "text/plain")
+ w.WriteHeader(200)
+
+ _, err := w.Write([]byte(response))
+ return err
+}
+
type ReusableResponsesRequestObject struct {
Body *ReusableResponsesJSONRequestBody
}
@@ -646,6 +684,9 @@ type StrictServerInterface interface {
// (POST /multiple)
MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, error)
+ // (GET /reserved-go-keyword-parameters/{type})
+ ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error)
+
// (POST /reusable-responses)
ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error)
@@ -665,9 +706,8 @@ type StrictServerInterface interface {
HeadersExample(ctx context.Context, request HeadersExampleRequestObject) (HeadersExampleResponseObject, error)
}
-type StrictHandlerFunc func(ctx echo.Context, args interface{}) (interface{}, error)
-
-type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+type StrictHandlerFunc = runtime.StrictEchoHandlerFunc
+type StrictMiddlewareFunc = runtime.StrictEchoMiddlewareFunc
func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
return &strictHandler{ssi: ssi, middlewares: middlewares}
@@ -796,6 +836,31 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx echo.Context) error
return nil
}
+// ReservedGoKeywordParameters operation middleware
+func (sh *strictHandler) ReservedGoKeywordParameters(ctx echo.Context, pType string) error {
+ var request ReservedGoKeywordParametersRequestObject
+
+ request.Type = pType
+
+ handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.ReservedGoKeywordParameters(ctx.Request().Context(), request.(ReservedGoKeywordParametersRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "ReservedGoKeywordParameters")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return err
+ } else if validResponse, ok := response.(ReservedGoKeywordParametersResponseObject); ok {
+ return validResponse.VisitReservedGoKeywordParametersResponse(ctx.Response())
+ } else if response != nil {
+ return fmt.Errorf("Unexpected response type: %T", response)
+ }
+ return nil
+}
+
// ReusableResponses operation middleware
func (sh *strictHandler) ReusableResponses(ctx echo.Context) error {
var request ReusableResponsesRequestObject
@@ -974,21 +1039,23 @@ func (sh *strictHandler) HeadersExample(ctx echo.Context, params HeadersExampleP
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
- "H4sIAAAAAAAC/+xYS4/iOBD+K1btnkaB0D194rbTGmnfI9Ezp9UcirgAzya2166QRoj/vnJsaBjSCFo8",
- "pNXeEqde/qq+KsdLKExljSbNHoZLcOSt0Z7alzFKR//U5Dm8SfKFU5aV0TCEDyhH6dsqA0e1x3FJa/Ug",
- "XxjNpFtVtLZUBQbV/JsP+kvwxYwqDE8/OprAEH7IX0LJ41ef0zNWtiRYrVbZdxF8+g0ymBFKcm208fFu",
- "1zYvLMEQPDulpxCMRLH7TjGlmabkgrcgmoIIAus4hkuwzlhyrCJGcyxr6vaUVsz4GxUcd6D0xOxj+Wg0",
- "o9JeSDWZkCPNIoEngg0vfG2tcUxSjBcieChYeHJzcpABKw6BwdP2ukgBe8hgTs5HR3f9QX8Q8mUsabQK",
- "hvC+XcrAIs/aDW0SZE1X3n99+vSnUF5gzaZCVgWW5UJU6PwMy5KkUJpNiLEu2PehdeXazP8ik/rHhGUo",
- "m7aCPhi5uETFtIW5Vc/3g8GVCnOVwUN01mVjE1S+xbDWzATrsgP0L/pvbRotyDnj0s7yqi5ZWXS8naxd",
- "tP9YixwD+cZePjGu6klkvBDq5/J0U+BTM+gkydPMNF7MTCPYCElYikbxTKwVv2O30gKFV3paklgHlXVm",
- "sqTUc3/ScpT28jnYuDiXsh0rz72maXpt8mpXki6MJPk2s6rCKeVWT3fVg21kGMJ4waFs97vrmYooA6Zn",
- "zm2JSh8eHVdqJ/8jfTZiR7quzya9neR1E3dNKi8K1GIc+DjxgcRdvvZIOkqeRlsStxlxhzHaO61do2uG",
- "5L8+qT7T81FD6oxkvXY1ngpYHRdfxyxpHQPbG7l/BIpzJcnklX040fLNQPWWCjVRJHtpF70Y22st4dHo",
- "whHvDu1wAtaGxcZYOJjzjEREIBPeiIZEVXsWFr0XitsuUqp4uJe01zy+vET2GD2FyX5EVt9dKKfvbpXR",
- "h8Hd6SrvL1w3O8P3FT6Ofv8YZU79wznblD/xjHI+vzeiczhW97buALop/HMUeJnpBak5SYFaCkdcO01S",
- "zBWuf1v3uJkMvKTVosOKuPX61xLCCEkXC5CBxoo273epCJQLyLKrKTt0PXHQ1j1kh+4svv6Hf6gvedNz",
- "6TpdZRAvZWKx1K4MGWW2wzyPlzl93+B0Sq6vTI5Wwerr6t8AAAD//ygSomqZEwAA",
+ "H4sIAAAAAAAC/+xYX2/bNhD/KgS3p0KynDRPeluDotu6rYOTPg15oMWzzFYiuePJimHouw8UJf+pFS/O",
+ "7BgY+mbRd787/u4Pj1zxzJTWaNDkeLriCM4a7aD9mAqJ8HcFjvyXBJehsqSM5il/J+Sk+6+JOELlxLSA",
+ "Xt3LZ0YT6FZVWFuoTHjV5Ivz+ivusjmUwv/6EWHGU/5DsnElCf+6BB5FaQvgTdNE33jw6SOP+ByEBGy9",
+ "DT+vdrFpaYGn3BEqnXMPEsSuB8WUJsgBvTUv2jnhBXo/0hW3aCwgqcDRQhQVDFvqVsz0C2QUdqD0zOxz",
+ "eWs0CaUdk2o2AwRNrCOPeQzHXGWtQQLJpkvmLWTEHOACkEecFHnH+N32OuscdjziC0AXDF2NxqOxj5ex",
+ "oIVVPOVv26WIW0HzdkPrAFkzFPdf7z79wZRjoiJTClKZKIolKwW6uSgKkExpMt7HKiM34q0pbCP/i+zU",
+ "33dc+rRpM+idkctzZEybmFv5fD0ev1JiNhG/CcaGMNZOJVsV1sLMRFUMkP5Zf9Wm1gwQDXY7S8qqIGUF",
+ "0nawdtn+vRd5DuVrvGRmsIylIHEm1k9l6aLEd81gsEju5qZ2bG5qRoZJEAWrFc1Zr/hNdSvNBHNK5wWw",
+ "3qloMJIFdD33Jy0n3V7uPcbZaynaQXmM67qO2+BVWIDOjAT5MlhVihwSq/NddY8tiKd8uiSftvvd9URJ",
+ "FHGCR0psIZQ+fHS8Ujv5zvTJCjuUK0J7JMo4N/FXWNYGZWwFihII0CUrb73xwDkMlPKfa0mWCc2mwLQo",
+ "QTIxI0D2wbAO0u2V7KSz+8F8DCIbqPa8XX+kf624p6Q9g3nEvQGeBlZCXSv0QSesIDpA28O/5ud/CkDP",
+ "Zpj04h1Tw22wb1Fr6hBmzrfEocgN8BcsTbYkLjMwHM64vdn3Nc4gH8mnz/17eHzWkX/C1vfatX0sYVVY",
+ "fJqzTus5tL2wkz6DxYWSYJLS3hyJfDFSnYVMzRTIuNtFHHx7qiXcGp0h0O4I5O8T2hBbg/lrDs2BBQYi",
+ "5gyrgZWVI2aFc0xR20UKFa5KEvaax+eNZ7fB0v2mnR6K6pszxfTNpSJ6M746XuXtmfNmZ5R5oh4nv70P",
+ "MsfeF082Mx058Z3O7oXK2V9S4q0XleES/jkIbM70DNTCT0RaMgSqUINkCyX6R4C92uwANmEdmoWCG5tp",
+ "qH/dOWYgig5iXfPo0AvQw//4eeKc72bnztMm4uGJKyRLhYWPKJFNkyQ8jY1cLfIccKRMIqzizUPzTwAA",
+ "AP//O0NNuucUAAA=",
}
// GetSwagger returns the content of the embedded swagger specification file
diff --git a/internal/test/strict-server/echo/server.go b/internal/test/strict-server/echo/server.go
index 5b7026809e..b0724db19f 100644
--- a/internal/test/strict-server/echo/server.go
+++ b/internal/test/strict-server/echo/server.go
@@ -100,3 +100,7 @@ func (s StrictServer) HeadersExample(ctx context.Context, request HeadersExample
func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error) {
return ReusableResponses200JSONResponse{ReusableresponseJSONResponse: ReusableresponseJSONResponse{Body: *request.Body}}, nil
}
+
+func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) {
+ return ReservedGoKeywordParameters200TextResponse(""), nil
+}
diff --git a/internal/test/strict-server/fiber/server.cfg.yaml b/internal/test/strict-server/fiber/server.cfg.yaml
new file mode 100644
index 0000000000..3a6471261f
--- /dev/null
+++ b/internal/test/strict-server/fiber/server.cfg.yaml
@@ -0,0 +1,6 @@
+package: api
+generate:
+ fiber-server: true
+ strict-server: true
+ embedded-spec: true
+output: server.gen.go
diff --git a/internal/test/strict-server/fiber/server.gen.go b/internal/test/strict-server/fiber/server.gen.go
new file mode 100644
index 0000000000..84671503d0
--- /dev/null
+++ b/internal/test/strict-server/fiber/server.gen.go
@@ -0,0 +1,1105 @@
+// Package api provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT.
+package api
+
+import (
+ "bytes"
+ "compress/gzip"
+ "context"
+ "encoding/base64"
+ "fmt"
+ "io"
+ "mime/multipart"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/deepmap/oapi-codegen/pkg/runtime"
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/gofiber/fiber/v2"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (POST /json)
+ JSONExample(c *fiber.Ctx) error
+
+ // (POST /multipart)
+ MultipartExample(c *fiber.Ctx) error
+
+ // (POST /multiple)
+ MultipleRequestAndResponseTypes(c *fiber.Ctx) error
+
+ // (GET /reserved-go-keyword-parameters/{type})
+ ReservedGoKeywordParameters(c *fiber.Ctx, pType string) error
+
+ // (POST /reusable-responses)
+ ReusableResponses(c *fiber.Ctx) error
+
+ // (POST /text)
+ TextExample(c *fiber.Ctx) error
+
+ // (POST /unknown)
+ UnknownExample(c *fiber.Ctx) error
+
+ // (POST /unspecified-content-type)
+ UnspecifiedContentType(c *fiber.Ctx) error
+
+ // (POST /urlencoded)
+ URLEncodedExample(c *fiber.Ctx) error
+
+ // (POST /with-headers)
+ HeadersExample(c *fiber.Ctx, params HeadersExampleParams) error
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+}
+
+type MiddlewareFunc fiber.Handler
+
+// JSONExample operation middleware
+func (siw *ServerInterfaceWrapper) JSONExample(c *fiber.Ctx) error {
+
+ return siw.Handler.JSONExample(c)
+}
+
+// MultipartExample operation middleware
+func (siw *ServerInterfaceWrapper) MultipartExample(c *fiber.Ctx) error {
+
+ return siw.Handler.MultipartExample(c)
+}
+
+// MultipleRequestAndResponseTypes operation middleware
+func (siw *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(c *fiber.Ctx) error {
+
+ return siw.Handler.MultipleRequestAndResponseTypes(c)
+}
+
+// ReservedGoKeywordParameters operation middleware
+func (siw *ServerInterfaceWrapper) ReservedGoKeywordParameters(c *fiber.Ctx) error {
+
+ var err error
+
+ // ------------- Path parameter "type" -------------
+ var pType string
+
+ err = runtime.BindStyledParameter("simple", false, "type", c.Params("type"), &pType)
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter type: %w", err).Error())
+ }
+
+ return siw.Handler.ReservedGoKeywordParameters(c, pType)
+}
+
+// ReusableResponses operation middleware
+func (siw *ServerInterfaceWrapper) ReusableResponses(c *fiber.Ctx) error {
+
+ return siw.Handler.ReusableResponses(c)
+}
+
+// TextExample operation middleware
+func (siw *ServerInterfaceWrapper) TextExample(c *fiber.Ctx) error {
+
+ return siw.Handler.TextExample(c)
+}
+
+// UnknownExample operation middleware
+func (siw *ServerInterfaceWrapper) UnknownExample(c *fiber.Ctx) error {
+
+ return siw.Handler.UnknownExample(c)
+}
+
+// UnspecifiedContentType operation middleware
+func (siw *ServerInterfaceWrapper) UnspecifiedContentType(c *fiber.Ctx) error {
+
+ return siw.Handler.UnspecifiedContentType(c)
+}
+
+// URLEncodedExample operation middleware
+func (siw *ServerInterfaceWrapper) URLEncodedExample(c *fiber.Ctx) error {
+
+ return siw.Handler.URLEncodedExample(c)
+}
+
+// HeadersExample operation middleware
+func (siw *ServerInterfaceWrapper) HeadersExample(c *fiber.Ctx) error {
+
+ var err error
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params HeadersExampleParams
+
+ headers := c.GetReqHeaders()
+
+ // ------------- Required header parameter "header1" -------------
+ if value, found := headers[http.CanonicalHeaderKey("header1")]; found {
+ var Header1 string
+
+ err = runtime.BindStyledParameterWithLocation("simple", false, "header1", runtime.ParamLocationHeader, value, &Header1)
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter header1: %w", err).Error())
+ }
+
+ params.Header1 = Header1
+
+ } else {
+ err = fmt.Errorf("Header parameter header1 is required, but not found: %w", err)
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+
+ // ------------- Optional header parameter "header2" -------------
+ if value, found := headers[http.CanonicalHeaderKey("header2")]; found {
+ var Header2 int
+
+ err = runtime.BindStyledParameterWithLocation("simple", false, "header2", runtime.ParamLocationHeader, value, &Header2)
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter header2: %w", err).Error())
+ }
+
+ params.Header2 = &Header2
+
+ }
+
+ return siw.Handler.HeadersExample(c, params)
+}
+
+// FiberServerOptions provides options for the Fiber server.
+type FiberServerOptions struct {
+ BaseURL string
+ Middlewares []MiddlewareFunc
+}
+
+// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
+func RegisterHandlers(router fiber.Router, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, FiberServerOptions{})
+}
+
+// RegisterHandlersWithOptions creates http.Handler with additional options
+func RegisterHandlersWithOptions(router fiber.Router, si ServerInterface, options FiberServerOptions) {
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ }
+
+ for _, m := range options.Middlewares {
+ router.Use(m)
+ }
+
+ router.Post(options.BaseURL+"/json", wrapper.JSONExample)
+
+ router.Post(options.BaseURL+"/multipart", wrapper.MultipartExample)
+
+ router.Post(options.BaseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes)
+
+ router.Get(options.BaseURL+"/reserved-go-keyword-parameters/:type", wrapper.ReservedGoKeywordParameters)
+
+ router.Post(options.BaseURL+"/reusable-responses", wrapper.ReusableResponses)
+
+ router.Post(options.BaseURL+"/text", wrapper.TextExample)
+
+ router.Post(options.BaseURL+"/unknown", wrapper.UnknownExample)
+
+ router.Post(options.BaseURL+"/unspecified-content-type", wrapper.UnspecifiedContentType)
+
+ router.Post(options.BaseURL+"/urlencoded", wrapper.URLEncodedExample)
+
+ router.Post(options.BaseURL+"/with-headers", wrapper.HeadersExample)
+
+}
+
+type BadrequestResponse struct {
+}
+
+type ReusableresponseResponseHeaders struct {
+ Header1 string
+ Header2 int
+}
+type ReusableresponseJSONResponse struct {
+ Body Example
+
+ Headers ReusableresponseResponseHeaders
+}
+
+type JSONExampleRequestObject struct {
+ Body *JSONExampleJSONRequestBody
+}
+
+type JSONExampleResponseObject interface {
+ VisitJSONExampleResponse(ctx *fiber.Ctx) error
+}
+
+type JSONExample200JSONResponse Example
+
+func (response JSONExample200JSONResponse) VisitJSONExampleResponse(ctx *fiber.Ctx) error {
+ ctx.Response().Header.Set("Content-Type", "application/json")
+ ctx.Status(200)
+
+ return ctx.JSON(&response)
+}
+
+type JSONExample400Response = BadrequestResponse
+
+func (response JSONExample400Response) VisitJSONExampleResponse(ctx *fiber.Ctx) error {
+ ctx.Status(400)
+ return nil
+}
+
+type JSONExampledefaultResponse struct {
+ StatusCode int
+}
+
+func (response JSONExampledefaultResponse) VisitJSONExampleResponse(ctx *fiber.Ctx) error {
+ ctx.Status(response.StatusCode)
+ return nil
+}
+
+type MultipartExampleRequestObject struct {
+ Body *multipart.Reader
+}
+
+type MultipartExampleResponseObject interface {
+ VisitMultipartExampleResponse(ctx *fiber.Ctx) error
+}
+
+type MultipartExample200MultipartResponse func(writer *multipart.Writer) error
+
+func (response MultipartExample200MultipartResponse) VisitMultipartExampleResponse(ctx *fiber.Ctx) error {
+ writer := multipart.NewWriter(ctx.Response().BodyWriter())
+ ctx.Response().Header.Set("Content-Type", writer.FormDataContentType())
+ ctx.Status(200)
+
+ defer writer.Close()
+ return response(writer)
+}
+
+type MultipartExample400Response = BadrequestResponse
+
+func (response MultipartExample400Response) VisitMultipartExampleResponse(ctx *fiber.Ctx) error {
+ ctx.Status(400)
+ return nil
+}
+
+type MultipartExampledefaultResponse struct {
+ StatusCode int
+}
+
+func (response MultipartExampledefaultResponse) VisitMultipartExampleResponse(ctx *fiber.Ctx) error {
+ ctx.Status(response.StatusCode)
+ return nil
+}
+
+type MultipleRequestAndResponseTypesRequestObject struct {
+ JSONBody *MultipleRequestAndResponseTypesJSONRequestBody
+ FormdataBody *MultipleRequestAndResponseTypesFormdataRequestBody
+ Body io.Reader
+ MultipartBody *multipart.Reader
+ TextBody *MultipleRequestAndResponseTypesTextRequestBody
+}
+
+type MultipleRequestAndResponseTypesResponseObject interface {
+ VisitMultipleRequestAndResponseTypesResponse(ctx *fiber.Ctx) error
+}
+
+type MultipleRequestAndResponseTypes200JSONResponse Example
+
+func (response MultipleRequestAndResponseTypes200JSONResponse) VisitMultipleRequestAndResponseTypesResponse(ctx *fiber.Ctx) error {
+ ctx.Response().Header.Set("Content-Type", "application/json")
+ ctx.Status(200)
+
+ return ctx.JSON(&response)
+}
+
+type MultipleRequestAndResponseTypes200FormdataResponse Example
+
+func (response MultipleRequestAndResponseTypes200FormdataResponse) VisitMultipleRequestAndResponseTypesResponse(ctx *fiber.Ctx) error {
+ ctx.Response().Header.Set("Content-Type", "application/x-www-form-urlencoded")
+ ctx.Status(200)
+
+ if form, err := runtime.MarshalForm(response, nil); err != nil {
+ return err
+ } else {
+ _, err := ctx.WriteString(form.Encode())
+ return err
+ }
+}
+
+type MultipleRequestAndResponseTypes200ImagepngResponse struct {
+ Body io.Reader
+ ContentLength int64
+}
+
+func (response MultipleRequestAndResponseTypes200ImagepngResponse) VisitMultipleRequestAndResponseTypesResponse(ctx *fiber.Ctx) error {
+ ctx.Response().Header.Set("Content-Type", "image/png")
+ if response.ContentLength != 0 {
+ ctx.Response().Header.Set("Content-Length", fmt.Sprint(response.ContentLength))
+ }
+ ctx.Status(200)
+
+ if closer, ok := response.Body.(io.ReadCloser); ok {
+ defer closer.Close()
+ }
+ _, err := io.Copy(ctx.Response().BodyWriter(), response.Body)
+ return err
+}
+
+type MultipleRequestAndResponseTypes200MultipartResponse func(writer *multipart.Writer) error
+
+func (response MultipleRequestAndResponseTypes200MultipartResponse) VisitMultipleRequestAndResponseTypesResponse(ctx *fiber.Ctx) error {
+ writer := multipart.NewWriter(ctx.Response().BodyWriter())
+ ctx.Response().Header.Set("Content-Type", writer.FormDataContentType())
+ ctx.Status(200)
+
+ defer writer.Close()
+ return response(writer)
+}
+
+type MultipleRequestAndResponseTypes200TextResponse string
+
+func (response MultipleRequestAndResponseTypes200TextResponse) VisitMultipleRequestAndResponseTypesResponse(ctx *fiber.Ctx) error {
+ ctx.Response().Header.Set("Content-Type", "text/plain")
+ ctx.Status(200)
+
+ _, err := ctx.WriteString(string(response))
+ return err
+}
+
+type MultipleRequestAndResponseTypes400Response = BadrequestResponse
+
+func (response MultipleRequestAndResponseTypes400Response) VisitMultipleRequestAndResponseTypesResponse(ctx *fiber.Ctx) error {
+ ctx.Status(400)
+ return nil
+}
+
+type ReservedGoKeywordParametersRequestObject struct {
+ Type string `json:"type"`
+}
+
+type ReservedGoKeywordParametersResponseObject interface {
+ VisitReservedGoKeywordParametersResponse(ctx *fiber.Ctx) error
+}
+
+type ReservedGoKeywordParameters200TextResponse string
+
+func (response ReservedGoKeywordParameters200TextResponse) VisitReservedGoKeywordParametersResponse(ctx *fiber.Ctx) error {
+ ctx.Response().Header.Set("Content-Type", "text/plain")
+ ctx.Status(200)
+
+ _, err := ctx.WriteString(string(response))
+ return err
+}
+
+type ReusableResponsesRequestObject struct {
+ Body *ReusableResponsesJSONRequestBody
+}
+
+type ReusableResponsesResponseObject interface {
+ VisitReusableResponsesResponse(ctx *fiber.Ctx) error
+}
+
+type ReusableResponses200JSONResponse struct{ ReusableresponseJSONResponse }
+
+func (response ReusableResponses200JSONResponse) VisitReusableResponsesResponse(ctx *fiber.Ctx) error {
+ ctx.Response().Header.Set("header1", fmt.Sprint(response.Headers.Header1))
+ ctx.Response().Header.Set("header2", fmt.Sprint(response.Headers.Header2))
+ ctx.Response().Header.Set("Content-Type", "application/json")
+ ctx.Status(200)
+
+ return ctx.JSON(&response.Body)
+}
+
+type ReusableResponses400Response = BadrequestResponse
+
+func (response ReusableResponses400Response) VisitReusableResponsesResponse(ctx *fiber.Ctx) error {
+ ctx.Status(400)
+ return nil
+}
+
+type ReusableResponsesdefaultResponse struct {
+ StatusCode int
+}
+
+func (response ReusableResponsesdefaultResponse) VisitReusableResponsesResponse(ctx *fiber.Ctx) error {
+ ctx.Status(response.StatusCode)
+ return nil
+}
+
+type TextExampleRequestObject struct {
+ Body *TextExampleTextRequestBody
+}
+
+type TextExampleResponseObject interface {
+ VisitTextExampleResponse(ctx *fiber.Ctx) error
+}
+
+type TextExample200TextResponse string
+
+func (response TextExample200TextResponse) VisitTextExampleResponse(ctx *fiber.Ctx) error {
+ ctx.Response().Header.Set("Content-Type", "text/plain")
+ ctx.Status(200)
+
+ _, err := ctx.WriteString(string(response))
+ return err
+}
+
+type TextExample400Response = BadrequestResponse
+
+func (response TextExample400Response) VisitTextExampleResponse(ctx *fiber.Ctx) error {
+ ctx.Status(400)
+ return nil
+}
+
+type TextExampledefaultResponse struct {
+ StatusCode int
+}
+
+func (response TextExampledefaultResponse) VisitTextExampleResponse(ctx *fiber.Ctx) error {
+ ctx.Status(response.StatusCode)
+ return nil
+}
+
+type UnknownExampleRequestObject struct {
+ Body io.Reader
+}
+
+type UnknownExampleResponseObject interface {
+ VisitUnknownExampleResponse(ctx *fiber.Ctx) error
+}
+
+type UnknownExample200Videomp4Response struct {
+ Body io.Reader
+ ContentLength int64
+}
+
+func (response UnknownExample200Videomp4Response) VisitUnknownExampleResponse(ctx *fiber.Ctx) error {
+ ctx.Response().Header.Set("Content-Type", "video/mp4")
+ if response.ContentLength != 0 {
+ ctx.Response().Header.Set("Content-Length", fmt.Sprint(response.ContentLength))
+ }
+ ctx.Status(200)
+
+ if closer, ok := response.Body.(io.ReadCloser); ok {
+ defer closer.Close()
+ }
+ _, err := io.Copy(ctx.Response().BodyWriter(), response.Body)
+ return err
+}
+
+type UnknownExample400Response = BadrequestResponse
+
+func (response UnknownExample400Response) VisitUnknownExampleResponse(ctx *fiber.Ctx) error {
+ ctx.Status(400)
+ return nil
+}
+
+type UnknownExampledefaultResponse struct {
+ StatusCode int
+}
+
+func (response UnknownExampledefaultResponse) VisitUnknownExampleResponse(ctx *fiber.Ctx) error {
+ ctx.Status(response.StatusCode)
+ return nil
+}
+
+type UnspecifiedContentTypeRequestObject struct {
+ ContentType string
+ Body io.Reader
+}
+
+type UnspecifiedContentTypeResponseObject interface {
+ VisitUnspecifiedContentTypeResponse(ctx *fiber.Ctx) error
+}
+
+type UnspecifiedContentType200VideoResponse struct {
+ Body io.Reader
+ ContentType string
+ ContentLength int64
+}
+
+func (response UnspecifiedContentType200VideoResponse) VisitUnspecifiedContentTypeResponse(ctx *fiber.Ctx) error {
+ ctx.Response().Header.Set("Content-Type", response.ContentType)
+ if response.ContentLength != 0 {
+ ctx.Response().Header.Set("Content-Length", fmt.Sprint(response.ContentLength))
+ }
+ ctx.Status(200)
+
+ if closer, ok := response.Body.(io.ReadCloser); ok {
+ defer closer.Close()
+ }
+ _, err := io.Copy(ctx.Response().BodyWriter(), response.Body)
+ return err
+}
+
+type UnspecifiedContentType400Response = BadrequestResponse
+
+func (response UnspecifiedContentType400Response) VisitUnspecifiedContentTypeResponse(ctx *fiber.Ctx) error {
+ ctx.Status(400)
+ return nil
+}
+
+type UnspecifiedContentType401Response struct {
+}
+
+func (response UnspecifiedContentType401Response) VisitUnspecifiedContentTypeResponse(ctx *fiber.Ctx) error {
+ ctx.Status(401)
+ return nil
+}
+
+type UnspecifiedContentType403Response struct {
+}
+
+func (response UnspecifiedContentType403Response) VisitUnspecifiedContentTypeResponse(ctx *fiber.Ctx) error {
+ ctx.Status(403)
+ return nil
+}
+
+type UnspecifiedContentTypedefaultResponse struct {
+ StatusCode int
+}
+
+func (response UnspecifiedContentTypedefaultResponse) VisitUnspecifiedContentTypeResponse(ctx *fiber.Ctx) error {
+ ctx.Status(response.StatusCode)
+ return nil
+}
+
+type URLEncodedExampleRequestObject struct {
+ Body *URLEncodedExampleFormdataRequestBody
+}
+
+type URLEncodedExampleResponseObject interface {
+ VisitURLEncodedExampleResponse(ctx *fiber.Ctx) error
+}
+
+type URLEncodedExample200FormdataResponse Example
+
+func (response URLEncodedExample200FormdataResponse) VisitURLEncodedExampleResponse(ctx *fiber.Ctx) error {
+ ctx.Response().Header.Set("Content-Type", "application/x-www-form-urlencoded")
+ ctx.Status(200)
+
+ if form, err := runtime.MarshalForm(response, nil); err != nil {
+ return err
+ } else {
+ _, err := ctx.WriteString(form.Encode())
+ return err
+ }
+}
+
+type URLEncodedExample400Response = BadrequestResponse
+
+func (response URLEncodedExample400Response) VisitURLEncodedExampleResponse(ctx *fiber.Ctx) error {
+ ctx.Status(400)
+ return nil
+}
+
+type URLEncodedExampledefaultResponse struct {
+ StatusCode int
+}
+
+func (response URLEncodedExampledefaultResponse) VisitURLEncodedExampleResponse(ctx *fiber.Ctx) error {
+ ctx.Status(response.StatusCode)
+ return nil
+}
+
+type HeadersExampleRequestObject struct {
+ Params HeadersExampleParams
+ Body *HeadersExampleJSONRequestBody
+}
+
+type HeadersExampleResponseObject interface {
+ VisitHeadersExampleResponse(ctx *fiber.Ctx) error
+}
+
+type HeadersExample200ResponseHeaders struct {
+ Header1 string
+ Header2 int
+}
+
+type HeadersExample200JSONResponse struct {
+ Body Example
+ Headers HeadersExample200ResponseHeaders
+}
+
+func (response HeadersExample200JSONResponse) VisitHeadersExampleResponse(ctx *fiber.Ctx) error {
+ ctx.Response().Header.Set("header1", fmt.Sprint(response.Headers.Header1))
+ ctx.Response().Header.Set("header2", fmt.Sprint(response.Headers.Header2))
+ ctx.Response().Header.Set("Content-Type", "application/json")
+ ctx.Status(200)
+
+ return ctx.JSON(&response.Body)
+}
+
+type HeadersExample400Response = BadrequestResponse
+
+func (response HeadersExample400Response) VisitHeadersExampleResponse(ctx *fiber.Ctx) error {
+ ctx.Status(400)
+ return nil
+}
+
+type HeadersExampledefaultResponse struct {
+ StatusCode int
+}
+
+func (response HeadersExampledefaultResponse) VisitHeadersExampleResponse(ctx *fiber.Ctx) error {
+ ctx.Status(response.StatusCode)
+ return nil
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+
+ // (POST /json)
+ JSONExample(ctx context.Context, request JSONExampleRequestObject) (JSONExampleResponseObject, error)
+
+ // (POST /multipart)
+ MultipartExample(ctx context.Context, request MultipartExampleRequestObject) (MultipartExampleResponseObject, error)
+
+ // (POST /multiple)
+ MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, error)
+
+ // (GET /reserved-go-keyword-parameters/{type})
+ ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error)
+
+ // (POST /reusable-responses)
+ ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error)
+
+ // (POST /text)
+ TextExample(ctx context.Context, request TextExampleRequestObject) (TextExampleResponseObject, error)
+
+ // (POST /unknown)
+ UnknownExample(ctx context.Context, request UnknownExampleRequestObject) (UnknownExampleResponseObject, error)
+
+ // (POST /unspecified-content-type)
+ UnspecifiedContentType(ctx context.Context, request UnspecifiedContentTypeRequestObject) (UnspecifiedContentTypeResponseObject, error)
+
+ // (POST /urlencoded)
+ URLEncodedExample(ctx context.Context, request URLEncodedExampleRequestObject) (URLEncodedExampleResponseObject, error)
+
+ // (POST /with-headers)
+ HeadersExample(ctx context.Context, request HeadersExampleRequestObject) (HeadersExampleResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx *fiber.Ctx, args interface{}) (interface{}, error)
+
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+}
+
+// JSONExample operation middleware
+func (sh *strictHandler) JSONExample(ctx *fiber.Ctx) error {
+ var request JSONExampleRequestObject
+
+ var body JSONExampleJSONRequestBody
+ if err := ctx.BodyParser(&body); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ request.Body = &body
+
+ handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+ return sh.ssi.JSONExample(ctx.UserContext(), request.(JSONExampleRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "JSONExample")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ } else if validResponse, ok := response.(JSONExampleResponseObject); ok {
+ if err := validResponse.VisitJSONExampleResponse(ctx); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else if response != nil {
+ return fmt.Errorf("Unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// MultipartExample operation middleware
+func (sh *strictHandler) MultipartExample(ctx *fiber.Ctx) error {
+ var request MultipartExampleRequestObject
+
+ request.Body = multipart.NewReader(bytes.NewReader(ctx.Request().Body()), string(ctx.Request().Header.MultipartFormBoundary()))
+
+ handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+ return sh.ssi.MultipartExample(ctx.UserContext(), request.(MultipartExampleRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "MultipartExample")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ } else if validResponse, ok := response.(MultipartExampleResponseObject); ok {
+ if err := validResponse.VisitMultipartExampleResponse(ctx); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else if response != nil {
+ return fmt.Errorf("Unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// MultipleRequestAndResponseTypes operation middleware
+func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx *fiber.Ctx) error {
+ var request MultipleRequestAndResponseTypesRequestObject
+
+ if strings.HasPrefix(string(ctx.Request().Header.ContentType()), "application/json") {
+ var body MultipleRequestAndResponseTypesJSONRequestBody
+ if err := ctx.BodyParser(&body); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ request.JSONBody = &body
+ }
+ if strings.HasPrefix(string(ctx.Request().Header.ContentType()), "application/x-www-form-urlencoded") {
+ var body MultipleRequestAndResponseTypesFormdataRequestBody
+ if err := ctx.BodyParser(&body); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ request.FormdataBody = &body
+ }
+ if strings.HasPrefix(string(ctx.Request().Header.ContentType()), "image/png") {
+ request.Body = bytes.NewReader(ctx.Request().Body())
+ }
+ if strings.HasPrefix(string(ctx.Request().Header.ContentType()), "multipart/form-data") {
+ request.MultipartBody = multipart.NewReader(bytes.NewReader(ctx.Request().Body()), string(ctx.Request().Header.MultipartFormBoundary()))
+ }
+ if strings.HasPrefix(string(ctx.Request().Header.ContentType()), "text/plain") {
+ data := ctx.Request().Body()
+ body := MultipleRequestAndResponseTypesTextRequestBody(data)
+ request.TextBody = &body
+ }
+
+ handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+ return sh.ssi.MultipleRequestAndResponseTypes(ctx.UserContext(), request.(MultipleRequestAndResponseTypesRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "MultipleRequestAndResponseTypes")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ } else if validResponse, ok := response.(MultipleRequestAndResponseTypesResponseObject); ok {
+ if err := validResponse.VisitMultipleRequestAndResponseTypesResponse(ctx); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else if response != nil {
+ return fmt.Errorf("Unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// ReservedGoKeywordParameters operation middleware
+func (sh *strictHandler) ReservedGoKeywordParameters(ctx *fiber.Ctx, pType string) error {
+ var request ReservedGoKeywordParametersRequestObject
+
+ request.Type = pType
+
+ handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+ return sh.ssi.ReservedGoKeywordParameters(ctx.UserContext(), request.(ReservedGoKeywordParametersRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "ReservedGoKeywordParameters")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ } else if validResponse, ok := response.(ReservedGoKeywordParametersResponseObject); ok {
+ if err := validResponse.VisitReservedGoKeywordParametersResponse(ctx); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else if response != nil {
+ return fmt.Errorf("Unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// ReusableResponses operation middleware
+func (sh *strictHandler) ReusableResponses(ctx *fiber.Ctx) error {
+ var request ReusableResponsesRequestObject
+
+ var body ReusableResponsesJSONRequestBody
+ if err := ctx.BodyParser(&body); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ request.Body = &body
+
+ handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+ return sh.ssi.ReusableResponses(ctx.UserContext(), request.(ReusableResponsesRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "ReusableResponses")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ } else if validResponse, ok := response.(ReusableResponsesResponseObject); ok {
+ if err := validResponse.VisitReusableResponsesResponse(ctx); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else if response != nil {
+ return fmt.Errorf("Unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// TextExample operation middleware
+func (sh *strictHandler) TextExample(ctx *fiber.Ctx) error {
+ var request TextExampleRequestObject
+
+ data := ctx.Request().Body()
+ body := TextExampleTextRequestBody(data)
+ request.Body = &body
+
+ handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+ return sh.ssi.TextExample(ctx.UserContext(), request.(TextExampleRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "TextExample")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ } else if validResponse, ok := response.(TextExampleResponseObject); ok {
+ if err := validResponse.VisitTextExampleResponse(ctx); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else if response != nil {
+ return fmt.Errorf("Unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// UnknownExample operation middleware
+func (sh *strictHandler) UnknownExample(ctx *fiber.Ctx) error {
+ var request UnknownExampleRequestObject
+
+ request.Body = bytes.NewReader(ctx.Request().Body())
+
+ handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+ return sh.ssi.UnknownExample(ctx.UserContext(), request.(UnknownExampleRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "UnknownExample")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ } else if validResponse, ok := response.(UnknownExampleResponseObject); ok {
+ if err := validResponse.VisitUnknownExampleResponse(ctx); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else if response != nil {
+ return fmt.Errorf("Unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// UnspecifiedContentType operation middleware
+func (sh *strictHandler) UnspecifiedContentType(ctx *fiber.Ctx) error {
+ var request UnspecifiedContentTypeRequestObject
+
+ request.ContentType = string(ctx.Request().Header.ContentType())
+
+ request.Body = bytes.NewReader(ctx.Request().Body())
+
+ handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+ return sh.ssi.UnspecifiedContentType(ctx.UserContext(), request.(UnspecifiedContentTypeRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "UnspecifiedContentType")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ } else if validResponse, ok := response.(UnspecifiedContentTypeResponseObject); ok {
+ if err := validResponse.VisitUnspecifiedContentTypeResponse(ctx); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else if response != nil {
+ return fmt.Errorf("Unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// URLEncodedExample operation middleware
+func (sh *strictHandler) URLEncodedExample(ctx *fiber.Ctx) error {
+ var request URLEncodedExampleRequestObject
+
+ var body URLEncodedExampleFormdataRequestBody
+ if err := ctx.BodyParser(&body); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ request.Body = &body
+
+ handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+ return sh.ssi.URLEncodedExample(ctx.UserContext(), request.(URLEncodedExampleRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "URLEncodedExample")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ } else if validResponse, ok := response.(URLEncodedExampleResponseObject); ok {
+ if err := validResponse.VisitURLEncodedExampleResponse(ctx); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else if response != nil {
+ return fmt.Errorf("Unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// HeadersExample operation middleware
+func (sh *strictHandler) HeadersExample(ctx *fiber.Ctx, params HeadersExampleParams) error {
+ var request HeadersExampleRequestObject
+
+ request.Params = params
+
+ var body HeadersExampleJSONRequestBody
+ if err := ctx.BodyParser(&body); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ request.Body = &body
+
+ handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+ return sh.ssi.HeadersExample(ctx.UserContext(), request.(HeadersExampleRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "HeadersExample")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ } else if validResponse, ok := response.(HeadersExampleResponseObject); ok {
+ if err := validResponse.VisitHeadersExampleResponse(ctx); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else if response != nil {
+ return fmt.Errorf("Unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// Base64 encoded, gzipped, json marshaled Swagger object
+var swaggerSpec = []string{
+
+ "H4sIAAAAAAAC/+xYX2/bNhD/KgS3p0KynDRPeluDotu6rYOTPg15oMWzzFYiuePJimHouw8UJf+pFS/O",
+ "7BgY+mbRd787/u4Pj1zxzJTWaNDkeLriCM4a7aD9mAqJ8HcFjvyXBJehsqSM5il/J+Sk+6+JOELlxLSA",
+ "Xt3LZ0YT6FZVWFuoTHjV5Ivz+ivusjmUwv/6EWHGU/5DsnElCf+6BB5FaQvgTdNE33jw6SOP+ByEBGy9",
+ "DT+vdrFpaYGn3BEqnXMPEsSuB8WUJsgBvTUv2jnhBXo/0hW3aCwgqcDRQhQVDFvqVsz0C2QUdqD0zOxz",
+ "eWs0CaUdk2o2AwRNrCOPeQzHXGWtQQLJpkvmLWTEHOACkEecFHnH+N32OuscdjziC0AXDF2NxqOxj5ex",
+ "oIVVPOVv26WIW0HzdkPrAFkzFPdf7z79wZRjoiJTClKZKIolKwW6uSgKkExpMt7HKiM34q0pbCP/i+zU",
+ "33dc+rRpM+idkctzZEybmFv5fD0ev1JiNhG/CcaGMNZOJVsV1sLMRFUMkP5Zf9Wm1gwQDXY7S8qqIGUF",
+ "0nawdtn+vRd5DuVrvGRmsIylIHEm1k9l6aLEd81gsEju5qZ2bG5qRoZJEAWrFc1Zr/hNdSvNBHNK5wWw",
+ "3qloMJIFdD33Jy0n3V7uPcbZaynaQXmM67qO2+BVWIDOjAT5MlhVihwSq/NddY8tiKd8uiSftvvd9URJ",
+ "FHGCR0psIZQ+fHS8Ujv5zvTJCjuUK0J7JMo4N/FXWNYGZWwFihII0CUrb73xwDkMlPKfa0mWCc2mwLQo",
+ "QTIxI0D2wbAO0u2V7KSz+8F8DCIbqPa8XX+kf624p6Q9g3nEvQGeBlZCXSv0QSesIDpA28O/5ud/CkDP",
+ "Zpj04h1Tw22wb1Fr6hBmzrfEocgN8BcsTbYkLjMwHM64vdn3Nc4gH8mnz/17eHzWkX/C1vfatX0sYVVY",
+ "fJqzTus5tL2wkz6DxYWSYJLS3hyJfDFSnYVMzRTIuNtFHHx7qiXcGp0h0O4I5O8T2hBbg/lrDs2BBQYi",
+ "5gyrgZWVI2aFc0xR20UKFa5KEvaax+eNZ7fB0v2mnR6K6pszxfTNpSJ6M746XuXtmfNmZ5R5oh4nv70P",
+ "MsfeF082Mx058Z3O7oXK2V9S4q0XleES/jkIbM70DNTCT0RaMgSqUINkCyX6R4C92uwANmEdmoWCG5tp",
+ "qH/dOWYgig5iXfPo0AvQw//4eeKc72bnztMm4uGJKyRLhYWPKJFNkyQ8jY1cLfIccKRMIqzizUPzTwAA",
+ "AP//O0NNuucUAAA=",
+}
+
+// GetSwagger returns the content of the embedded swagger specification file
+// or error if failed to decode
+func decodeSpec() ([]byte, error) {
+ zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %s", err)
+ }
+ zr, err := gzip.NewReader(bytes.NewReader(zipped))
+ if err != nil {
+ return nil, fmt.Errorf("error decompressing spec: %s", err)
+ }
+ var buf bytes.Buffer
+ _, err = buf.ReadFrom(zr)
+ if err != nil {
+ return nil, fmt.Errorf("error decompressing spec: %s", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cached of a decoded swagger spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ var res = make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSwagger returns the Swagger specification corresponding to the generated code
+// in this file. The external references of Swagger specification are resolved.
+// The logic of resolving external references is tightly connected to "import-mapping" feature.
+// Externally referenced files must be embedded in the corresponding golang packages.
+// Urls can be supported but this task was out of the scope.
+func GetSwagger() (swagger *openapi3.T, err error) {
+ var resolvePath = PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ var pathToFile = url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
diff --git a/internal/test/strict-server/fiber/server.go b/internal/test/strict-server/fiber/server.go
new file mode 100644
index 0000000000..b0724db19f
--- /dev/null
+++ b/internal/test/strict-server/fiber/server.go
@@ -0,0 +1,106 @@
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=server.cfg.yaml ../strict-schema.yaml
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=types.cfg.yaml ../strict-schema.yaml
+
+package api
+
+import (
+ "context"
+ "io"
+ "mime/multipart"
+)
+
+type StrictServer struct {
+}
+
+func (s StrictServer) JSONExample(ctx context.Context, request JSONExampleRequestObject) (JSONExampleResponseObject, error) {
+ return JSONExample200JSONResponse(*request.Body), nil
+}
+
+func (s StrictServer) MultipartExample(ctx context.Context, request MultipartExampleRequestObject) (MultipartExampleResponseObject, error) {
+ return MultipartExample200MultipartResponse(func(writer *multipart.Writer) error {
+ for {
+ part, err := request.Body.NextPart()
+ if err == io.EOF {
+ return nil
+ } else if err != nil {
+ return err
+ }
+ w, err := writer.CreatePart(part.Header)
+ if err != nil {
+ return err
+ }
+ _, err = io.Copy(w, part)
+ if err != nil {
+ return err
+ }
+ if err = part.Close(); err != nil {
+ return err
+ }
+ }
+ }), nil
+}
+
+func (s StrictServer) MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, error) {
+ switch {
+ case request.Body != nil:
+ return MultipleRequestAndResponseTypes200ImagepngResponse{Body: request.Body}, nil
+ case request.JSONBody != nil:
+ return MultipleRequestAndResponseTypes200JSONResponse(*request.JSONBody), nil
+ case request.FormdataBody != nil:
+ return MultipleRequestAndResponseTypes200FormdataResponse(*request.FormdataBody), nil
+ case request.TextBody != nil:
+ return MultipleRequestAndResponseTypes200TextResponse(*request.TextBody), nil
+ case request.MultipartBody != nil:
+ return MultipleRequestAndResponseTypes200MultipartResponse(func(writer *multipart.Writer) error {
+ for {
+ part, err := request.MultipartBody.NextPart()
+ if err == io.EOF {
+ return nil
+ } else if err != nil {
+ return err
+ }
+ w, err := writer.CreatePart(part.Header)
+ if err != nil {
+ return err
+ }
+ _, err = io.Copy(w, part)
+ if err != nil {
+ return err
+ }
+ if err = part.Close(); err != nil {
+ return err
+ }
+ }
+ }), nil
+ default:
+ return MultipleRequestAndResponseTypes400Response{}, nil
+ }
+}
+
+func (s StrictServer) TextExample(ctx context.Context, request TextExampleRequestObject) (TextExampleResponseObject, error) {
+ return TextExample200TextResponse(*request.Body), nil
+}
+
+func (s StrictServer) UnknownExample(ctx context.Context, request UnknownExampleRequestObject) (UnknownExampleResponseObject, error) {
+ return UnknownExample200Videomp4Response{Body: request.Body}, nil
+}
+
+func (s StrictServer) UnspecifiedContentType(ctx context.Context, request UnspecifiedContentTypeRequestObject) (UnspecifiedContentTypeResponseObject, error) {
+ return UnspecifiedContentType200VideoResponse{Body: request.Body, ContentType: request.ContentType}, nil
+}
+
+func (s StrictServer) URLEncodedExample(ctx context.Context, request URLEncodedExampleRequestObject) (URLEncodedExampleResponseObject, error) {
+ return URLEncodedExample200FormdataResponse(*request.Body), nil
+}
+
+func (s StrictServer) HeadersExample(ctx context.Context, request HeadersExampleRequestObject) (HeadersExampleResponseObject, error) {
+ return HeadersExample200JSONResponse{Body: *request.Body, Headers: HeadersExample200ResponseHeaders{Header1: request.Params.Header1, Header2: *request.Params.Header2}}, nil
+}
+
+func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error) {
+ return ReusableResponses200JSONResponse{ReusableresponseJSONResponse: ReusableresponseJSONResponse{Body: *request.Body}}, nil
+}
+
+func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) {
+ return ReservedGoKeywordParameters200TextResponse(""), nil
+}
diff --git a/internal/test/strict-server/fiber/types.cfg.yaml b/internal/test/strict-server/fiber/types.cfg.yaml
new file mode 100644
index 0000000000..4ea1d8aa5b
--- /dev/null
+++ b/internal/test/strict-server/fiber/types.cfg.yaml
@@ -0,0 +1,4 @@
+package: api
+generate:
+ models: true
+output: types.gen.go
diff --git a/internal/test/strict-server/fiber/types.gen.go b/internal/test/strict-server/fiber/types.gen.go
new file mode 100644
index 0000000000..33827cb7a4
--- /dev/null
+++ b/internal/test/strict-server/fiber/types.gen.go
@@ -0,0 +1,54 @@
+// Package api provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT.
+package api
+
+// Example defines model for example.
+type Example struct {
+ Value *string `json:"value,omitempty"`
+}
+
+// Reusableresponse defines model for reusableresponse.
+type Reusableresponse = Example
+
+// MultipleRequestAndResponseTypesTextBody defines parameters for MultipleRequestAndResponseTypes.
+type MultipleRequestAndResponseTypesTextBody = string
+
+// TextExampleTextBody defines parameters for TextExample.
+type TextExampleTextBody = string
+
+// HeadersExampleParams defines parameters for HeadersExample.
+type HeadersExampleParams struct {
+ Header1 string `json:"header1"`
+ Header2 *int `json:"header2,omitempty"`
+}
+
+// JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType.
+type JSONExampleJSONRequestBody = Example
+
+// MultipartExampleMultipartRequestBody defines body for MultipartExample for multipart/form-data ContentType.
+type MultipartExampleMultipartRequestBody = Example
+
+// MultipleRequestAndResponseTypesJSONRequestBody defines body for MultipleRequestAndResponseTypes for application/json ContentType.
+type MultipleRequestAndResponseTypesJSONRequestBody = Example
+
+// MultipleRequestAndResponseTypesFormdataRequestBody defines body for MultipleRequestAndResponseTypes for application/x-www-form-urlencoded ContentType.
+type MultipleRequestAndResponseTypesFormdataRequestBody = Example
+
+// MultipleRequestAndResponseTypesMultipartRequestBody defines body for MultipleRequestAndResponseTypes for multipart/form-data ContentType.
+type MultipleRequestAndResponseTypesMultipartRequestBody = Example
+
+// MultipleRequestAndResponseTypesTextRequestBody defines body for MultipleRequestAndResponseTypes for text/plain ContentType.
+type MultipleRequestAndResponseTypesTextRequestBody = MultipleRequestAndResponseTypesTextBody
+
+// ReusableResponsesJSONRequestBody defines body for ReusableResponses for application/json ContentType.
+type ReusableResponsesJSONRequestBody = Example
+
+// TextExampleTextRequestBody defines body for TextExample for text/plain ContentType.
+type TextExampleTextRequestBody = TextExampleTextBody
+
+// URLEncodedExampleFormdataRequestBody defines body for URLEncodedExample for application/x-www-form-urlencoded ContentType.
+type URLEncodedExampleFormdataRequestBody = Example
+
+// HeadersExampleJSONRequestBody defines body for HeadersExample for application/json ContentType.
+type HeadersExampleJSONRequestBody = Example
diff --git a/internal/test/strict-server/gin/server.gen.go b/internal/test/strict-server/gin/server.gen.go
index 52c729007a..dd9839c23b 100644
--- a/internal/test/strict-server/gin/server.gen.go
+++ b/internal/test/strict-server/gin/server.gen.go
@@ -34,6 +34,9 @@ type ServerInterface interface {
// (POST /multiple)
MultipleRequestAndResponseTypes(c *gin.Context)
+ // (GET /reserved-go-keyword-parameters/{type})
+ ReservedGoKeywordParameters(c *gin.Context, pType string)
+
// (POST /reusable-responses)
ReusableResponses(c *gin.Context)
@@ -67,6 +70,9 @@ func (siw *ServerInterfaceWrapper) JSONExample(c *gin.Context) {
for _, middleware := range siw.HandlerMiddlewares {
middleware(c)
+ if c.IsAborted() {
+ return
+ }
}
siw.Handler.JSONExample(c)
@@ -77,6 +83,9 @@ func (siw *ServerInterfaceWrapper) MultipartExample(c *gin.Context) {
for _, middleware := range siw.HandlerMiddlewares {
middleware(c)
+ if c.IsAborted() {
+ return
+ }
}
siw.Handler.MultipartExample(c)
@@ -87,16 +96,46 @@ func (siw *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(c *gin.Contex
for _, middleware := range siw.HandlerMiddlewares {
middleware(c)
+ if c.IsAborted() {
+ return
+ }
}
siw.Handler.MultipleRequestAndResponseTypes(c)
}
+// ReservedGoKeywordParameters operation middleware
+func (siw *ServerInterfaceWrapper) ReservedGoKeywordParameters(c *gin.Context) {
+
+ var err error
+
+ // ------------- Path parameter "type" -------------
+ var pType string
+
+ err = runtime.BindStyledParameter("simple", false, "type", c.Param("type"), &pType)
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter type: %s", err), http.StatusBadRequest)
+ return
+ }
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.ReservedGoKeywordParameters(c, pType)
+}
+
// ReusableResponses operation middleware
func (siw *ServerInterfaceWrapper) ReusableResponses(c *gin.Context) {
for _, middleware := range siw.HandlerMiddlewares {
middleware(c)
+ if c.IsAborted() {
+ return
+ }
}
siw.Handler.ReusableResponses(c)
@@ -107,6 +146,9 @@ func (siw *ServerInterfaceWrapper) TextExample(c *gin.Context) {
for _, middleware := range siw.HandlerMiddlewares {
middleware(c)
+ if c.IsAborted() {
+ return
+ }
}
siw.Handler.TextExample(c)
@@ -117,6 +159,9 @@ func (siw *ServerInterfaceWrapper) UnknownExample(c *gin.Context) {
for _, middleware := range siw.HandlerMiddlewares {
middleware(c)
+ if c.IsAborted() {
+ return
+ }
}
siw.Handler.UnknownExample(c)
@@ -127,6 +172,9 @@ func (siw *ServerInterfaceWrapper) UnspecifiedContentType(c *gin.Context) {
for _, middleware := range siw.HandlerMiddlewares {
middleware(c)
+ if c.IsAborted() {
+ return
+ }
}
siw.Handler.UnspecifiedContentType(c)
@@ -137,6 +185,9 @@ func (siw *ServerInterfaceWrapper) URLEncodedExample(c *gin.Context) {
for _, middleware := range siw.HandlerMiddlewares {
middleware(c)
+ if c.IsAborted() {
+ return
+ }
}
siw.Handler.URLEncodedExample(c)
@@ -170,7 +221,7 @@ func (siw *ServerInterfaceWrapper) HeadersExample(c *gin.Context) {
params.Header1 = Header1
} else {
- siw.ErrorHandler(c, fmt.Errorf("Header parameter header1 is required, but not found: %s", err), http.StatusBadRequest)
+ siw.ErrorHandler(c, fmt.Errorf("Header parameter header1 is required, but not found"), http.StatusBadRequest)
return
}
@@ -195,6 +246,9 @@ func (siw *ServerInterfaceWrapper) HeadersExample(c *gin.Context) {
for _, middleware := range siw.HandlerMiddlewares {
middleware(c)
+ if c.IsAborted() {
+ return
+ }
}
siw.Handler.HeadersExample(c, params)
@@ -208,15 +262,13 @@ type GinServerOptions struct {
}
// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
-func RegisterHandlers(router *gin.Engine, si ServerInterface) *gin.Engine {
- return RegisterHandlersWithOptions(router, si, GinServerOptions{})
+func RegisterHandlers(router gin.IRouter, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, GinServerOptions{})
}
// RegisterHandlersWithOptions creates http.Handler with additional options
-func RegisterHandlersWithOptions(router *gin.Engine, si ServerInterface, options GinServerOptions) *gin.Engine {
-
+func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options GinServerOptions) {
errorHandler := options.ErrorHandler
-
if errorHandler == nil {
errorHandler = func(c *gin.Context, err error, statusCode int) {
c.JSON(statusCode, gin.H{"msg": err.Error()})
@@ -230,24 +282,15 @@ func RegisterHandlersWithOptions(router *gin.Engine, si ServerInterface, options
}
router.POST(options.BaseURL+"/json", wrapper.JSONExample)
-
router.POST(options.BaseURL+"/multipart", wrapper.MultipartExample)
-
router.POST(options.BaseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes)
-
+ router.GET(options.BaseURL+"/reserved-go-keyword-parameters/:type", wrapper.ReservedGoKeywordParameters)
router.POST(options.BaseURL+"/reusable-responses", wrapper.ReusableResponses)
-
router.POST(options.BaseURL+"/text", wrapper.TextExample)
-
router.POST(options.BaseURL+"/unknown", wrapper.UnknownExample)
-
router.POST(options.BaseURL+"/unspecified-content-type", wrapper.UnspecifiedContentType)
-
router.POST(options.BaseURL+"/urlencoded", wrapper.URLEncodedExample)
-
router.POST(options.BaseURL+"/with-headers", wrapper.HeadersExample)
-
- return router
}
type BadrequestResponse struct {
@@ -413,6 +456,24 @@ func (response MultipleRequestAndResponseTypes400Response) VisitMultipleRequestA
return nil
}
+type ReservedGoKeywordParametersRequestObject struct {
+ Type string `json:"type"`
+}
+
+type ReservedGoKeywordParametersResponseObject interface {
+ VisitReservedGoKeywordParametersResponse(w http.ResponseWriter) error
+}
+
+type ReservedGoKeywordParameters200TextResponse string
+
+func (response ReservedGoKeywordParameters200TextResponse) VisitReservedGoKeywordParametersResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "text/plain")
+ w.WriteHeader(200)
+
+ _, err := w.Write([]byte(response))
+ return err
+}
+
type ReusableResponsesRequestObject struct {
Body *ReusableResponsesJSONRequestBody
}
@@ -680,6 +741,9 @@ type StrictServerInterface interface {
// (POST /multiple)
MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, error)
+ // (GET /reserved-go-keyword-parameters/{type})
+ ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error)
+
// (POST /reusable-responses)
ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error)
@@ -699,9 +763,8 @@ type StrictServerInterface interface {
HeadersExample(ctx context.Context, request HeadersExampleRequestObject) (HeadersExampleResponseObject, error)
}
-type StrictHandlerFunc func(ctx *gin.Context, args interface{}) (interface{}, error)
-
-type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+type StrictHandlerFunc = runtime.StrictGinHandlerFunc
+type StrictMiddlewareFunc = runtime.StrictGinMiddlewareFunc
func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
return &strictHandler{ssi: ssi, middlewares: middlewares}
@@ -735,6 +798,7 @@ func (sh *strictHandler) JSONExample(ctx *gin.Context) {
if err != nil {
ctx.Error(err)
+ ctx.Status(http.StatusInternalServerError)
} else if validResponse, ok := response.(JSONExampleResponseObject); ok {
if err := validResponse.VisitJSONExampleResponse(ctx.Writer); err != nil {
ctx.Error(err)
@@ -766,6 +830,7 @@ func (sh *strictHandler) MultipartExample(ctx *gin.Context) {
if err != nil {
ctx.Error(err)
+ ctx.Status(http.StatusInternalServerError)
} else if validResponse, ok := response.(MultipartExampleResponseObject); ok {
if err := validResponse.VisitMultipartExampleResponse(ctx.Writer); err != nil {
ctx.Error(err)
@@ -832,6 +897,7 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx *gin.Context) {
if err != nil {
ctx.Error(err)
+ ctx.Status(http.StatusInternalServerError)
} else if validResponse, ok := response.(MultipleRequestAndResponseTypesResponseObject); ok {
if err := validResponse.VisitMultipleRequestAndResponseTypesResponse(ctx.Writer); err != nil {
ctx.Error(err)
@@ -841,6 +907,33 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx *gin.Context) {
}
}
+// ReservedGoKeywordParameters operation middleware
+func (sh *strictHandler) ReservedGoKeywordParameters(ctx *gin.Context, pType string) {
+ var request ReservedGoKeywordParametersRequestObject
+
+ request.Type = pType
+
+ handler := func(ctx *gin.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.ReservedGoKeywordParameters(ctx, request.(ReservedGoKeywordParametersRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "ReservedGoKeywordParameters")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ ctx.Error(err)
+ ctx.Status(http.StatusInternalServerError)
+ } else if validResponse, ok := response.(ReservedGoKeywordParametersResponseObject); ok {
+ if err := validResponse.VisitReservedGoKeywordParametersResponse(ctx.Writer); err != nil {
+ ctx.Error(err)
+ }
+ } else if response != nil {
+ ctx.Error(fmt.Errorf("Unexpected response type: %T", response))
+ }
+}
+
// ReusableResponses operation middleware
func (sh *strictHandler) ReusableResponses(ctx *gin.Context) {
var request ReusableResponsesRequestObject
@@ -864,6 +957,7 @@ func (sh *strictHandler) ReusableResponses(ctx *gin.Context) {
if err != nil {
ctx.Error(err)
+ ctx.Status(http.StatusInternalServerError)
} else if validResponse, ok := response.(ReusableResponsesResponseObject); ok {
if err := validResponse.VisitReusableResponsesResponse(ctx.Writer); err != nil {
ctx.Error(err)
@@ -896,6 +990,7 @@ func (sh *strictHandler) TextExample(ctx *gin.Context) {
if err != nil {
ctx.Error(err)
+ ctx.Status(http.StatusInternalServerError)
} else if validResponse, ok := response.(TextExampleResponseObject); ok {
if err := validResponse.VisitTextExampleResponse(ctx.Writer); err != nil {
ctx.Error(err)
@@ -922,6 +1017,7 @@ func (sh *strictHandler) UnknownExample(ctx *gin.Context) {
if err != nil {
ctx.Error(err)
+ ctx.Status(http.StatusInternalServerError)
} else if validResponse, ok := response.(UnknownExampleResponseObject); ok {
if err := validResponse.VisitUnknownExampleResponse(ctx.Writer); err != nil {
ctx.Error(err)
@@ -950,6 +1046,7 @@ func (sh *strictHandler) UnspecifiedContentType(ctx *gin.Context) {
if err != nil {
ctx.Error(err)
+ ctx.Status(http.StatusInternalServerError)
} else if validResponse, ok := response.(UnspecifiedContentTypeResponseObject); ok {
if err := validResponse.VisitUnspecifiedContentTypeResponse(ctx.Writer); err != nil {
ctx.Error(err)
@@ -985,6 +1082,7 @@ func (sh *strictHandler) URLEncodedExample(ctx *gin.Context) {
if err != nil {
ctx.Error(err)
+ ctx.Status(http.StatusInternalServerError)
} else if validResponse, ok := response.(URLEncodedExampleResponseObject); ok {
if err := validResponse.VisitURLEncodedExampleResponse(ctx.Writer); err != nil {
ctx.Error(err)
@@ -1019,6 +1117,7 @@ func (sh *strictHandler) HeadersExample(ctx *gin.Context, params HeadersExampleP
if err != nil {
ctx.Error(err)
+ ctx.Status(http.StatusInternalServerError)
} else if validResponse, ok := response.(HeadersExampleResponseObject); ok {
if err := validResponse.VisitHeadersExampleResponse(ctx.Writer); err != nil {
ctx.Error(err)
@@ -1031,21 +1130,23 @@ func (sh *strictHandler) HeadersExample(ctx *gin.Context, params HeadersExampleP
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
- "H4sIAAAAAAAC/+xYS4/iOBD+K1btnkaB0D194rbTGmnfI9Ezp9UcirgAzya2166QRoj/vnJsaBjSCFo8",
- "pNXeEqde/qq+KsdLKExljSbNHoZLcOSt0Z7alzFKR//U5Dm8SfKFU5aV0TCEDyhH6dsqA0e1x3FJa/Ug",
- "XxjNpFtVtLZUBQbV/JsP+kvwxYwqDE8/OprAEH7IX0LJ41ef0zNWtiRYrVbZdxF8+g0ymBFKcm208fFu",
- "1zYvLMEQPDulpxCMRLH7TjGlmabkgrcgmoIIAus4hkuwzlhyrCJGcyxr6vaUVsz4GxUcd6D0xOxj+Wg0",
- "o9JeSDWZkCPNIoEngg0vfG2tcUxSjBcieChYeHJzcpABKw6BwdP2ukgBe8hgTs5HR3f9QX8Q8mUsabQK",
- "hvC+XcrAIs/aDW0SZE1X3n99+vSnUF5gzaZCVgWW5UJU6PwMy5KkUJpNiLEu2PehdeXazP8ik/rHhGUo",
- "m7aCPhi5uETFtIW5Vc/3g8GVCnOVwUN01mVjE1S+xbDWzATrsgP0L/pvbRotyDnj0s7yqi5ZWXS8naxd",
- "tP9YixwD+cZePjGu6klkvBDq5/J0U+BTM+gkydPMNF7MTCPYCElYikbxTKwVv2O30gKFV3paklgHlXVm",
- "sqTUc3/ScpT28jnYuDiXsh0rz72maXpt8mpXki6MJPk2s6rCKeVWT3fVg21kGMJ4waFs97vrmYooA6Zn",
- "zm2JSh8eHVdqJ/8jfTZiR7quzya9neR1E3dNKi8K1GIc+DjxgcRdvvZIOkqeRlsStxlxhzHaO61do2uG",
- "5L8+qT7T81FD6oxkvXY1ngpYHRdfxyxpHQPbG7l/BIpzJcnklX040fLNQPWWCjVRJHtpF70Y22st4dHo",
- "whHvDu1wAtaGxcZYOJjzjEREIBPeiIZEVXsWFr0XitsuUqp4uJe01zy+vET2GD2FyX5EVt9dKKfvbpXR",
- "h8Hd6SrvL1w3O8P3FT6Ofv8YZU79wznblD/xjHI+vzeiczhW97buALop/HMUeJnpBak5SYFaCkdcO01S",
- "zBWuf1v3uJkMvKTVosOKuPX61xLCCEkXC5CBxoo273epCJQLyLKrKTt0PXHQ1j1kh+4svv6Hf6gvedNz",
- "6TpdZRAvZWKx1K4MGWW2wzyPlzl93+B0Sq6vTI5Wwerr6t8AAAD//ygSomqZEwAA",
+ "H4sIAAAAAAAC/+xYX2/bNhD/KgS3p0KynDRPeluDotu6rYOTPg15oMWzzFYiuePJimHouw8UJf+pFS/O",
+ "7BgY+mbRd787/u4Pj1zxzJTWaNDkeLriCM4a7aD9mAqJ8HcFjvyXBJehsqSM5il/J+Sk+6+JOELlxLSA",
+ "Xt3LZ0YT6FZVWFuoTHjV5Ivz+ivusjmUwv/6EWHGU/5DsnElCf+6BB5FaQvgTdNE33jw6SOP+ByEBGy9",
+ "DT+vdrFpaYGn3BEqnXMPEsSuB8WUJsgBvTUv2jnhBXo/0hW3aCwgqcDRQhQVDFvqVsz0C2QUdqD0zOxz",
+ "eWs0CaUdk2o2AwRNrCOPeQzHXGWtQQLJpkvmLWTEHOACkEecFHnH+N32OuscdjziC0AXDF2NxqOxj5ex",
+ "oIVVPOVv26WIW0HzdkPrAFkzFPdf7z79wZRjoiJTClKZKIolKwW6uSgKkExpMt7HKiM34q0pbCP/i+zU",
+ "33dc+rRpM+idkctzZEybmFv5fD0ev1JiNhG/CcaGMNZOJVsV1sLMRFUMkP5Zf9Wm1gwQDXY7S8qqIGUF",
+ "0nawdtn+vRd5DuVrvGRmsIylIHEm1k9l6aLEd81gsEju5qZ2bG5qRoZJEAWrFc1Zr/hNdSvNBHNK5wWw",
+ "3qloMJIFdD33Jy0n3V7uPcbZaynaQXmM67qO2+BVWIDOjAT5MlhVihwSq/NddY8tiKd8uiSftvvd9URJ",
+ "FHGCR0psIZQ+fHS8Ujv5zvTJCjuUK0J7JMo4N/FXWNYGZWwFihII0CUrb73xwDkMlPKfa0mWCc2mwLQo",
+ "QTIxI0D2wbAO0u2V7KSz+8F8DCIbqPa8XX+kf624p6Q9g3nEvQGeBlZCXSv0QSesIDpA28O/5ud/CkDP",
+ "Zpj04h1Tw22wb1Fr6hBmzrfEocgN8BcsTbYkLjMwHM64vdn3Nc4gH8mnz/17eHzWkX/C1vfatX0sYVVY",
+ "fJqzTus5tL2wkz6DxYWSYJLS3hyJfDFSnYVMzRTIuNtFHHx7qiXcGp0h0O4I5O8T2hBbg/lrDs2BBQYi",
+ "5gyrgZWVI2aFc0xR20UKFa5KEvaax+eNZ7fB0v2mnR6K6pszxfTNpSJ6M746XuXtmfNmZ5R5oh4nv70P",
+ "MsfeF082Mx058Z3O7oXK2V9S4q0XleES/jkIbM70DNTCT0RaMgSqUINkCyX6R4C92uwANmEdmoWCG5tp",
+ "qH/dOWYgig5iXfPo0AvQw//4eeKc72bnztMm4uGJKyRLhYWPKJFNkyQ8jY1cLfIccKRMIqzizUPzTwAA",
+ "AP//O0NNuucUAAA=",
}
// GetSwagger returns the content of the embedded swagger specification file
diff --git a/internal/test/strict-server/gin/server.go b/internal/test/strict-server/gin/server.go
index 5b7026809e..b0724db19f 100644
--- a/internal/test/strict-server/gin/server.go
+++ b/internal/test/strict-server/gin/server.go
@@ -100,3 +100,7 @@ func (s StrictServer) HeadersExample(ctx context.Context, request HeadersExample
func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error) {
return ReusableResponses200JSONResponse{ReusableresponseJSONResponse: ReusableresponseJSONResponse{Body: *request.Body}}, nil
}
+
+func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) {
+ return ReservedGoKeywordParameters200TextResponse(""), nil
+}
diff --git a/internal/test/strict-server/strict-schema.yaml b/internal/test/strict-server/strict-schema.yaml
index a9a2c41097..da0ed07a74 100644
--- a/internal/test/strict-server/strict-schema.yaml
+++ b/internal/test/strict-server/strict-schema.yaml
@@ -228,6 +228,23 @@ paths:
$ref: "#/components/responses/badrequest"
default:
description: Unknown error
+ /reserved-go-keyword-parameters/{type}:
+ get:
+ operationId: ReservedGoKeywordParameters
+ description: Parameters can be named after Go keywords
+ parameters:
+ - name: type
+ in: path
+ required: true
+ schema:
+ type: string
+ responses:
+ 200:
+ description: OK
+ content:
+ text/plain:
+ schema:
+ type: string
components:
responses:
badrequest:
diff --git a/internal/test/strict-server/strict_test.go b/internal/test/strict-server/strict_test.go
index 76f236730d..bfbb9bc2ab 100644
--- a/internal/test/strict-server/strict_test.go
+++ b/internal/test/strict-server/strict_test.go
@@ -11,58 +11,70 @@ import (
"strings"
"testing"
- "github.com/deepmap/oapi-codegen/internal/test/strict-server/chi"
- api3 "github.com/deepmap/oapi-codegen/internal/test/strict-server/client"
- api4 "github.com/deepmap/oapi-codegen/internal/test/strict-server/echo"
- api2 "github.com/deepmap/oapi-codegen/internal/test/strict-server/gin"
- "github.com/deepmap/oapi-codegen/pkg/runtime"
- "github.com/deepmap/oapi-codegen/pkg/testutil"
"github.com/gin-gonic/gin"
"github.com/go-chi/chi/v5"
+ "github.com/gofiber/fiber/v2"
+ "github.com/gofiber/fiber/v2/middleware/adaptor"
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
+
+ chiAPI "github.com/deepmap/oapi-codegen/internal/test/strict-server/chi"
+ clientAPI "github.com/deepmap/oapi-codegen/internal/test/strict-server/client"
+ echoAPI "github.com/deepmap/oapi-codegen/internal/test/strict-server/echo"
+ fiberAPI "github.com/deepmap/oapi-codegen/internal/test/strict-server/fiber"
+ ginAPI "github.com/deepmap/oapi-codegen/internal/test/strict-server/gin"
+ "github.com/deepmap/oapi-codegen/pkg/runtime"
+ "github.com/deepmap/oapi-codegen/pkg/testutil"
)
func TestChiServer(t *testing.T) {
- server := api.StrictServer{}
- strictHandler := api.NewStrictHandler(server, nil)
+ server := chiAPI.StrictServer{}
+ strictHandler := chiAPI.NewStrictHandler(server, nil)
r := chi.NewRouter()
- handler := api.HandlerFromMux(strictHandler, r)
+ handler := chiAPI.HandlerFromMux(strictHandler, r)
testImpl(t, handler)
}
func TestEchoServer(t *testing.T) {
- server := api4.StrictServer{}
- strictHandler := api4.NewStrictHandler(server, nil)
+ server := echoAPI.StrictServer{}
+ strictHandler := echoAPI.NewStrictHandler(server, nil)
e := echo.New()
- api4.RegisterHandlers(e, strictHandler)
+ echoAPI.RegisterHandlers(e, strictHandler)
testImpl(t, e)
}
func TestGinServer(t *testing.T) {
- server := api2.StrictServer{}
- strictHandler := api2.NewStrictHandler(server, nil)
+ server := ginAPI.StrictServer{}
+ strictHandler := ginAPI.NewStrictHandler(server, nil)
gin.SetMode(gin.ReleaseMode)
r := gin.New()
- handler := api2.RegisterHandlers(r, strictHandler)
- testImpl(t, handler)
+ ginAPI.RegisterHandlers(r, strictHandler)
+ testImpl(t, r)
+}
+
+func TestFiberServer(t *testing.T) {
+ server := fiberAPI.StrictServer{}
+ strictHandler := fiberAPI.NewStrictHandler(server, nil)
+ r := fiber.New()
+ fiberAPI.RegisterHandlers(r, strictHandler)
+ testImpl(t, adaptor.FiberApp(r))
}
func testImpl(t *testing.T, handler http.Handler) {
t.Run("JSONExample", func(t *testing.T) {
value := "123"
- requestBody := api3.Example{Value: &value}
+ requestBody := clientAPI.Example{Value: &value}
rr := testutil.NewRequest().Post("/json").WithJsonBody(requestBody).GoWithHTTPHandler(t, handler).Recorder
assert.Equal(t, http.StatusOK, rr.Code)
assert.True(t, strings.HasPrefix(rr.Header().Get("Content-Type"), "application/json"))
- var responseBody api3.Example
+ var responseBody clientAPI.Example
err := json.NewDecoder(rr.Body).Decode(&responseBody)
assert.NoError(t, err)
assert.Equal(t, requestBody, responseBody)
})
t.Run("URLEncodedExample", func(t *testing.T) {
value := "456"
- requestBody := api3.Example{Value: &value}
+ requestBody := clientAPI.Example{Value: &value}
requestBodyEncoded, err := runtime.MarshalForm(&requestBody, nil)
assert.NoError(t, err)
rr := testutil.NewRequest().Post("/urlencoded").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(requestBodyEncoded.Encode())).GoWithHTTPHandler(t, handler).Recorder
@@ -70,7 +82,7 @@ func testImpl(t *testing.T, handler http.Handler) {
assert.Equal(t, "application/x-www-form-urlencoded", rr.Header().Get("Content-Type"))
values, err := url.ParseQuery(rr.Body.String())
assert.NoError(t, err)
- var responseBody api3.Example
+ var responseBody clientAPI.Example
err = runtime.BindForm(&responseBody, values, nil, nil)
assert.NoError(t, err)
assert.Equal(t, requestBody, responseBody)
@@ -115,18 +127,18 @@ func testImpl(t *testing.T, handler http.Handler) {
})
t.Run("MultipleRequestAndResponseTypesJSON", func(t *testing.T) {
value := "123"
- requestBody := api3.Example{Value: &value}
+ requestBody := clientAPI.Example{Value: &value}
rr := testutil.NewRequest().Post("/multiple").WithJsonBody(requestBody).GoWithHTTPHandler(t, handler).Recorder
assert.Equal(t, http.StatusOK, rr.Code)
assert.True(t, strings.HasPrefix(rr.Header().Get("Content-Type"), "application/json"))
- var responseBody api3.Example
+ var responseBody clientAPI.Example
err := json.NewDecoder(rr.Body).Decode(&responseBody)
assert.NoError(t, err)
assert.Equal(t, requestBody, responseBody)
})
t.Run("MultipleRequestAndResponseTypesFormdata", func(t *testing.T) {
value := "456"
- requestBody := api3.Example{Value: &value}
+ requestBody := clientAPI.Example{Value: &value}
requestBodyEncoded, err := runtime.MarshalForm(&requestBody, nil)
assert.NoError(t, err)
rr := testutil.NewRequest().Post("/multiple").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(requestBodyEncoded.Encode())).GoWithHTTPHandler(t, handler).Recorder
@@ -134,7 +146,7 @@ func testImpl(t *testing.T, handler http.Handler) {
assert.Equal(t, "application/x-www-form-urlencoded", rr.Header().Get("Content-Type"))
values, err := url.ParseQuery(rr.Body.String())
assert.NoError(t, err)
- var responseBody api3.Example
+ var responseBody clientAPI.Example
err = runtime.BindForm(&responseBody, values, nil, nil)
assert.NoError(t, err)
assert.Equal(t, requestBody, responseBody)
@@ -181,11 +193,11 @@ func testImpl(t *testing.T, handler http.Handler) {
header1 := "value1"
header2 := "890"
value := "asdf"
- requestBody := api3.Example{Value: &value}
+ requestBody := clientAPI.Example{Value: &value}
rr := testutil.NewRequest().Post("/with-headers").WithHeader("header1", header1).WithHeader("header2", header2).WithJsonBody(requestBody).GoWithHTTPHandler(t, handler).Recorder
assert.Equal(t, http.StatusOK, rr.Code)
assert.True(t, strings.HasPrefix(rr.Header().Get("Content-Type"), "application/json"))
- var responseBody api3.Example
+ var responseBody clientAPI.Example
err := json.NewDecoder(rr.Body).Decode(&responseBody)
assert.NoError(t, err)
assert.Equal(t, requestBody, responseBody)
@@ -202,11 +214,11 @@ func testImpl(t *testing.T, handler http.Handler) {
})
t.Run("ReusableResponses", func(t *testing.T) {
value := "jkl;"
- requestBody := api3.Example{Value: &value}
+ requestBody := clientAPI.Example{Value: &value}
rr := testutil.NewRequest().Post("/reusable-responses").WithJsonBody(requestBody).GoWithHTTPHandler(t, handler).Recorder
assert.Equal(t, http.StatusOK, rr.Code)
assert.True(t, strings.HasPrefix(rr.Header().Get("Content-Type"), "application/json"))
- var responseBody api3.Example
+ var responseBody clientAPI.Example
err := json.NewDecoder(rr.Body).Decode(&responseBody)
assert.NoError(t, err)
assert.Equal(t, requestBody, responseBody)
diff --git a/pkg/chi-middleware/oapi_validate.go b/pkg/chi-middleware/oapi_validate.go
index 8c37a79e13..b654dc3cf6 100644
--- a/pkg/chi-middleware/oapi_validate.go
+++ b/pkg/chi-middleware/oapi_validate.go
@@ -1,12 +1,13 @@
// Package middleware implements middleware function for go-chi or net/http,
// which validates incoming HTTP requests to make sure that they conform to the given OAPI 3.0 specification.
-// When OAPI validation failes on the request, we return an HTTP/400.
+// When OAPI validation fails on the request, we return an HTTP/400.
package middleware
import (
"context"
"errors"
"fmt"
+ "log"
"net/http"
"strings"
@@ -27,6 +28,8 @@ type Options struct {
Options openapi3filter.Options
ErrorHandler ErrorHandler
MultiErrorHandler MultiErrorHandler
+ // SilenceServersWarning allows silencing a warning for https://github.com/deepmap/oapi-codegen/issues/882 that reports when an OpenAPI spec has `spec.Servers != nil`
+ SilenceServersWarning bool
}
// OapiRequestValidator Creates middleware to validate request by swagger spec.
@@ -38,6 +41,10 @@ func OapiRequestValidator(swagger *openapi3.T) func(next http.Handler) http.Hand
// OapiRequestValidatorWithOptions Creates middleware to validate request by swagger spec.
// This middleware is good for net/http either since go-chi is 100% compatible with net/http.
func OapiRequestValidatorWithOptions(swagger *openapi3.T, options *Options) func(next http.Handler) http.Handler {
+ if swagger.Servers != nil && (options == nil || options.SilenceServersWarning) {
+ log.Println("WARN: OapiRequestValidatorWithOptions called with an OpenAPI spec that has `Servers` set. This may lead to an HTTP 400 with `no matching operation was found` when sending a valid request, as the validator performs `Host` header validation. If you're expecting `Host` header validation, you can silence this warning by setting `Options.SilenceServersWarning = true`. See https://github.com/deepmap/oapi-codegen/issues/882 for more information.")
+ }
+
router, err := gorillamux.NewRouter(swagger)
if err != nil {
panic(err)
diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go
index 50866917e8..6cb5fec5ad 100644
--- a/pkg/codegen/codegen.go
+++ b/pkg/codegen/codegen.go
@@ -19,7 +19,10 @@ import (
"bytes"
"embed"
"fmt"
+ "io"
"io/fs"
+ "net/http"
+ "os"
"runtime/debug"
"sort"
"strings"
@@ -37,8 +40,9 @@ var templates embed.FS
// globalState stores all global state. Please don't put global state anywhere
// else so that we can easily track it.
var globalState struct {
- options Configuration
- spec *openapi3.T
+ options Configuration
+ spec *openapi3.T
+ importMapping importMap
}
// goImport represents a go package to be imported in the generated code
@@ -67,8 +71,6 @@ func (im importMap) GoImports() []string {
return goImports
}
-var importMapping importMap
-
func constructImportMapping(importMapping map[string]string) importMap {
var (
pathToName = map[string]string{}
@@ -101,8 +103,7 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
// This is global state
globalState.options = opts
globalState.spec = spec
-
- importMapping = constructImportMapping(opts.ImportMapping)
+ globalState.importMapping = constructImportMapping(opts.ImportMapping)
filterOperationsByTag(spec, opts)
if !opts.OutputOptions.SkipPrune {
@@ -128,17 +129,22 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
return "", fmt.Errorf("error parsing oapi-codegen templates: %w", err)
}
- // Override built-in templates with user-provided versions
- for _, tpl := range t.Templates() {
- if _, ok := opts.OutputOptions.UserTemplates[tpl.Name()]; ok {
- utpl := t.New(tpl.Name())
- if _, err := utpl.Parse(opts.OutputOptions.UserTemplates[tpl.Name()]); err != nil {
- return "", fmt.Errorf("error parsing user-provided template %q: %w", tpl.Name(), err)
- }
+ // load user-provided templates. Will Override built-in versions.
+ for name, template := range opts.OutputOptions.UserTemplates {
+ utpl := t.New(name)
+
+ txt, err := GetUserTemplateText(template)
+ if err != nil {
+ return "", fmt.Errorf("error loading user-provided template %q: %w", name, err)
+ }
+
+ _, err = utpl.Parse(txt)
+ if err != nil {
+ return "", fmt.Errorf("error parsing user-provided template %q: %w", name, err)
}
}
- ops, err := OperationDefinitions(spec)
+ ops, err := OperationDefinitions(spec, opts.OutputOptions.InitialismOverrides)
if err != nil {
return "", fmt.Errorf("error creating operation definitions: %w", err)
}
@@ -183,6 +189,14 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
}
}
+ var fiberServerOut string
+ if opts.Generate.FiberServer {
+ fiberServerOut, err = GenerateFiberServer(t, ops)
+ if err != nil {
+ return "", fmt.Errorf("error generating Go handlers for Paths: %w", err)
+ }
+ }
+
var ginServerOut string
if opts.Generate.GinServer {
ginServerOut, err = GenerateGinServer(t, ops)
@@ -201,9 +215,12 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
var strictServerOut string
if opts.Generate.Strict {
- responses, err := GenerateResponseDefinitions("", spec.Components.Responses)
- if err != nil {
- return "", fmt.Errorf("error generation response definitions for schema: %w", err)
+ var responses []ResponseDefinition
+ if spec.Components != nil {
+ responses, err = GenerateResponseDefinitions("", spec.Components.Responses)
+ if err != nil {
+ return "", fmt.Errorf("error generation response definitions for schema: %w", err)
+ }
}
strictServerResponses, err := GenerateStrictResponses(t, responses)
if err != nil {
@@ -234,7 +251,7 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
var inlinedSpec string
if opts.Generate.EmbeddedSpec {
- inlinedSpec, err = GenerateInlinedSpec(t, importMapping, spec)
+ inlinedSpec, err = GenerateInlinedSpec(t, globalState.importMapping, spec)
if err != nil {
return "", fmt.Errorf("error generating Go handlers for Paths: %w", err)
}
@@ -243,7 +260,7 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
var buf bytes.Buffer
w := bufio.NewWriter(&buf)
- externalImports := append(importMapping.GoImports(), importMap(xGoTypeImports).GoImports()...)
+ externalImports := append(globalState.importMapping.GoImports(), importMap(xGoTypeImports).GoImports()...)
importsOut, err := GenerateImports(t, externalImports, opts.PackageName)
if err != nil {
return "", fmt.Errorf("error generating imports: %w", err)
@@ -289,6 +306,13 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
}
}
+ if opts.Generate.FiberServer {
+ _, err = w.WriteString(fiberServerOut)
+ if err != nil {
+ return "", fmt.Errorf("error writing server path handlers: %w", err)
+ }
+ }
+
if opts.Generate.GinServer {
_, err = w.WriteString(ginServerOut)
if err != nil {
@@ -339,28 +363,31 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
}
func GenerateTypeDefinitions(t *template.Template, swagger *openapi3.T, ops []OperationDefinition, excludeSchemas []string) (string, error) {
- schemaTypes, err := GenerateTypesForSchemas(t, swagger.Components.Schemas, excludeSchemas)
- if err != nil {
- return "", fmt.Errorf("error generating Go types for component schemas: %w", err)
- }
+ var allTypes []TypeDefinition
+ if swagger.Components != nil {
+ schemaTypes, err := GenerateTypesForSchemas(t, swagger.Components.Schemas, excludeSchemas)
+ if err != nil {
+ return "", fmt.Errorf("error generating Go types for component schemas: %w", err)
+ }
- paramTypes, err := GenerateTypesForParameters(t, swagger.Components.Parameters)
- if err != nil {
- return "", fmt.Errorf("error generating Go types for component parameters: %w", err)
- }
- allTypes := append(schemaTypes, paramTypes...)
+ paramTypes, err := GenerateTypesForParameters(t, swagger.Components.Parameters)
+ if err != nil {
+ return "", fmt.Errorf("error generating Go types for component parameters: %w", err)
+ }
+ allTypes = append(schemaTypes, paramTypes...)
- responseTypes, err := GenerateTypesForResponses(t, swagger.Components.Responses)
- if err != nil {
- return "", fmt.Errorf("error generating Go types for component responses: %w", err)
- }
- allTypes = append(allTypes, responseTypes...)
+ responseTypes, err := GenerateTypesForResponses(t, swagger.Components.Responses)
+ if err != nil {
+ return "", fmt.Errorf("error generating Go types for component responses: %w", err)
+ }
+ allTypes = append(allTypes, responseTypes...)
- bodyTypes, err := GenerateTypesForRequestBodies(t, swagger.Components.RequestBodies)
- if err != nil {
- return "", fmt.Errorf("error generating Go types for component request bodies: %w", err)
+ bodyTypes, err := GenerateTypesForRequestBodies(t, swagger.Components.RequestBodies)
+ if err != nil {
+ return "", fmt.Errorf("error generating Go types for component request bodies: %w", err)
+ }
+ allTypes = append(allTypes, bodyTypes...)
}
- allTypes = append(allTypes, bodyTypes...)
// Go through all operations, and add their types to allTypes, so that we can
// scan all of them for enums. Operation definitions are handled differently
@@ -396,7 +423,12 @@ func GenerateTypeDefinitions(t *template.Template, swagger *openapi3.T, ops []Op
return "", fmt.Errorf("error generating union boilerplate: %w", err)
}
- typeDefinitions := strings.Join([]string{enumsOut, typesOut, operationsOut, allOfBoilerplate, unionBoilerplate}, "")
+ unionAndAdditionalBoilerplate, err := GenerateUnionAndAdditionalProopertiesBoilerplate(t, allTypes)
+ if err != nil {
+ return "", fmt.Errorf("error generating boilerplate for union types with additionalProperties: %w", err)
+ }
+
+ typeDefinitions := strings.Join([]string{enumsOut, typesOut, operationsOut, allOfBoilerplate, unionBoilerplate, unionAndAdditionalBoilerplate}, "")
return typeDefinitions, nil
}
@@ -778,12 +810,70 @@ func GenerateUnionBoilerplate(t *template.Template, typeDefs []TypeDefinition) (
return GenerateTemplates([]string{"union.tmpl"}, t, context)
}
+func GenerateUnionAndAdditionalProopertiesBoilerplate(t *template.Template, typeDefs []TypeDefinition) (string, error) {
+ var filteredTypes []TypeDefinition
+ for _, t := range typeDefs {
+ if len(t.Schema.UnionElements) != 0 && t.Schema.HasAdditionalProperties {
+ filteredTypes = append(filteredTypes, t)
+ }
+ }
+
+ if len(filteredTypes) == 0 {
+ return "", nil
+ }
+ context := struct {
+ Types []TypeDefinition
+ }{
+ Types: filteredTypes,
+ }
+
+ return GenerateTemplates([]string{"union-and-additional-properties.tmpl"}, t, context)
+}
+
// SanitizeCode runs sanitizers across the generated Go code to ensure the
// generated code will be able to compile.
func SanitizeCode(goCode string) string {
// remove any byte-order-marks which break Go-Code
// See: https://groups.google.com/forum/#!topic/golang-nuts/OToNIPdfkks
- return strings.Replace(goCode, "\uFEFF", "", -1)
+ return strings.ReplaceAll(goCode, "\uFEFF", "")
+}
+
+// GetUserTemplateText attempts to retrieve the template text from a passed in URL or file
+// path when inputData is more than one line.
+// This function will attempt to load a file first, and if it fails, will try to get the
+// data from the remote endpoint.
+func GetUserTemplateText(inputData string) (template string, err error) {
+ //if the input data is more than one line, assume its a template and return that data.
+ if strings.Contains(inputData, "\n") {
+ return inputData, nil
+ }
+
+ //load data from file
+ data, err := os.ReadFile(inputData)
+ //return data if found and loaded
+ if err == nil {
+ return string(data), nil
+ }
+
+ //check for non "not found" errors
+ if !os.IsNotExist(err) {
+ return "", fmt.Errorf("failed to open file %s: %w", inputData, err)
+ }
+
+ //attempt to get data from url
+ resp, err := http.Get(inputData)
+ if err != nil {
+ return "", fmt.Errorf("failed to execute GET request data from %s: %w", inputData, err)
+ }
+ if resp.StatusCode < 200 || resp.StatusCode >= 300 {
+ return "", fmt.Errorf("got non %d status code on GET %s", resp.StatusCode, inputData)
+ }
+ data, err = io.ReadAll(resp.Body)
+ if err != nil {
+ return "", fmt.Errorf("failed to read response body from GET %s: %w", inputData, err)
+ }
+
+ return string(data), nil
}
// LoadTemplates loads all of our template files into a text/template. The
@@ -868,6 +958,10 @@ func OperationImports(ops []OperationDefinition) (map[string]goImport, error) {
func GetTypeDefinitionsImports(swagger *openapi3.T, excludeSchemas []string) (map[string]goImport, error) {
res := map[string]goImport{}
+ if swagger.Components == nil {
+ return res, nil
+ }
+
schemaImports, err := GetSchemaImports(swagger.Components.Schemas, excludeSchemas)
if err != nil {
return nil, err
diff --git a/pkg/codegen/codegen_test.go b/pkg/codegen/codegen_test.go
index 4a85eb1e92..a127bf0a28 100644
--- a/pkg/codegen/codegen_test.go
+++ b/pkg/codegen/codegen_test.go
@@ -3,8 +3,10 @@ package codegen
import (
"bytes"
_ "embed"
+ "fmt"
"go/format"
"io"
+ "net"
"net/http"
"testing"
@@ -77,7 +79,7 @@ func TestExamplePetStoreCodeGeneration(t *testing.T) {
func TestExamplePetStoreCodeGenerationWithUserTemplates(t *testing.T) {
- userTemplates := map[string]string{"typedef.tmpl": "//blah"}
+ userTemplates := map[string]string{"typedef.tmpl": "//blah\n//blah"}
// Input vars for code generation:
packageName := "api"
@@ -107,7 +109,92 @@ func TestExamplePetStoreCodeGenerationWithUserTemplates(t *testing.T) {
// Check that we have a package:
assert.Contains(t, code, "package api")
- // Check that the built-in template has been overriden
+ // Check that the built-in template has been overridden
+ assert.Contains(t, code, "//blah")
+}
+
+func TestExamplePetStoreCodeGenerationWithFileUserTemplates(t *testing.T) {
+
+ userTemplates := map[string]string{"typedef.tmpl": "./templates/typedef.tmpl"}
+
+ // Input vars for code generation:
+ packageName := "api"
+ opts := Configuration{
+ PackageName: packageName,
+ Generate: GenerateOptions{
+ Models: true,
+ },
+ OutputOptions: OutputOptions{
+ UserTemplates: userTemplates,
+ },
+ }
+
+ // Get a spec from the example PetStore definition:
+ swagger, err := examplePetstore.GetSwagger()
+ assert.NoError(t, err)
+
+ // Run our code generation:
+ code, err := Generate(swagger, opts)
+ assert.NoError(t, err)
+ assert.NotEmpty(t, code)
+
+ // Check that we have valid (formattable) code:
+ _, err = format.Source([]byte(code))
+ assert.NoError(t, err)
+
+ // Check that we have a package:
+ assert.Contains(t, code, "package api")
+
+ // Check that the built-in template has been overridden
+ assert.Contains(t, code, "// Package api provides primitives to interact with the openapi")
+}
+
+func TestExamplePetStoreCodeGenerationWithHTTPUserTemplates(t *testing.T) {
+
+ ln, err := net.Listen("tcp", "127.0.0.1:0")
+ assert.NoError(t, err)
+ defer ln.Close()
+
+ //nolint:errcheck
+ //Does not matter if the server returns an error on close etc.
+ go http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ _, writeErr := w.Write([]byte("//blah"))
+ assert.NoError(t, writeErr)
+ }))
+
+ t.Logf("Listening on %s", ln.Addr().String())
+
+ userTemplates := map[string]string{"typedef.tmpl": fmt.Sprintf("http://%s", ln.Addr().String())}
+
+ // Input vars for code generation:
+ packageName := "api"
+ opts := Configuration{
+ PackageName: packageName,
+ Generate: GenerateOptions{
+ Models: true,
+ },
+ OutputOptions: OutputOptions{
+ UserTemplates: userTemplates,
+ },
+ }
+
+ // Get a spec from the example PetStore definition:
+ swagger, err := examplePetstore.GetSwagger()
+ assert.NoError(t, err)
+
+ // Run our code generation:
+ code, err := Generate(swagger, opts)
+ assert.NoError(t, err)
+ assert.NotEmpty(t, code)
+
+ // Check that we have valid (formattable) code:
+ _, err = format.Source([]byte(code))
+ assert.NoError(t, err)
+
+ // Check that we have a package:
+ assert.Contains(t, code, "package api")
+
+ // Check that the built-in template has been overridden
assert.Contains(t, code, "//blah")
}
@@ -145,8 +232,11 @@ func TestExampleOpenAPICodeGeneration(t *testing.T) {
},
}
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+
// Get a spec from the test definition in this file:
- swagger, err := openapi3.NewLoader().LoadFromData([]byte(testOpenAPIDefinition))
+ swagger, err := loader.LoadFromData([]byte(testOpenAPIDefinition))
assert.NoError(t, err)
// Run our code generation:
@@ -188,6 +278,11 @@ type GetTestByNameResponse struct {
assert.Contains(t, code, "func (c *Client) GetTestByName(ctx context.Context, name string, params *GetTestByNameParams, reqEditors ...RequestEditorFn) (*http.Response, error) {")
assert.Contains(t, code, "func (c *ClientWithResponses) GetTestByNameWithResponse(ctx context.Context, name string, params *GetTestByNameParams, reqEditors ...RequestEditorFn) (*GetTestByNameResponse, error) {")
assert.Contains(t, code, "DeadSince *time.Time `json:\"dead_since,omitempty\" tag1:\"value1\" tag2:\"value2\"`")
+ assert.Contains(t, code, "type EnumTestNumerics int")
+ assert.Contains(t, code, "N2 EnumTestNumerics = 2")
+ assert.Contains(t, code, "type EnumTestEnumNames int")
+ assert.Contains(t, code, "Two EnumTestEnumNames = 2")
+ assert.Contains(t, code, "Double EnumTestEnumVarnames = 2")
// Make sure the generated code is valid:
checkLint(t, "test.gen.go", []byte(code))
diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go
index 1400c3c740..9b64bfe25f 100644
--- a/pkg/codegen/configuration.go
+++ b/pkg/codegen/configuration.go
@@ -23,6 +23,7 @@ type Configuration struct {
// GenerateOptions specifies which supported output formats to generate.
type GenerateOptions struct {
ChiServer bool `yaml:"chi-server,omitempty"` // ChiServer specifies whether to generate chi server boilerplate
+ FiberServer bool `yaml:"fiber-server,omitempty"` // FiberServer specifies whether to generate fiber server boilerplate
EchoServer bool `yaml:"echo-server,omitempty"` // EchoServer specifies whether to generate echo server boilerplate
GinServer bool `yaml:"gin-server,omitempty"` // GinServer specifies whether to generate gin server boilerplate
GorillaServer bool `yaml:"gorilla-server,omitempty"` // GorillaServer specifies whether to generate Gorilla server boilerplate
@@ -69,6 +70,11 @@ type CompatibilityOptions struct {
// This resolves the behavior such that middlewares are chained in the order they are invoked.
// Please see https://github.com/deepmap/oapi-codegen/issues/786
ApplyChiMiddlewareFirstToLast bool `yaml:"apply-chi-middleware-first-to-last,omitempty"`
+ // Our generated code for gorilla/mux has historically inverted the order in which gorilla/mux middleware is
+ // applied such that the last invoked middleware ends up executing first in the middlewares chain
+ // This resolves the behavior such that middlewares are chained in the order they are invoked.
+ // Please see https://github.com/deepmap/oapi-codegen/issues/841
+ ApplyGorillaMiddlewareFirstToLast bool `yaml:"apply-gorilla-middleware-first-to-last,omitempty"`
}
// OutputOptions are used to modify the output code in some way.
@@ -79,9 +85,10 @@ type OutputOptions struct {
ExcludeTags []string `yaml:"exclude-tags,omitempty"` // Exclude operations that have one of these tags. Ignored when empty.
UserTemplates map[string]string `yaml:"user-templates,omitempty"` // Override built-in templates from user-provided files
- ExcludeSchemas []string `yaml:"exclude-schemas,omitempty"` // Exclude from generation schemas with given names. Ignored when empty.
- ResponseTypeSuffix string `yaml:"response-type-suffix,omitempty"` // The suffix used for responses types
- ClientTypeName string `yaml:"client-type-name,omitempty"` // Override the default generated client type with the value
+ ExcludeSchemas []string `yaml:"exclude-schemas,omitempty"` // Exclude from generation schemas with given names. Ignored when empty.
+ ResponseTypeSuffix string `yaml:"response-type-suffix,omitempty"` // The suffix used for responses types
+ ClientTypeName string `yaml:"client-type-name,omitempty"` // Override the default generated client type with the value
+ InitialismOverrides bool `yaml:"initialism-overrides,omitempty"` // Whether to use the initialism overrides
}
// UpdateDefaults sets reasonable default values for unset fields in Configuration
@@ -107,6 +114,9 @@ func (o Configuration) Validate() error {
if o.Generate.ChiServer {
nServers++
}
+ if o.Generate.FiberServer {
+ nServers++
+ }
if o.Generate.EchoServer {
nServers++
}
diff --git a/pkg/codegen/extension.go b/pkg/codegen/extension.go
index 69c462142d..ca4c3b6693 100644
--- a/pkg/codegen/extension.go
+++ b/pkg/codegen/extension.go
@@ -1,7 +1,6 @@
package codegen
import (
- "encoding/json"
"fmt"
)
@@ -13,22 +12,20 @@ const (
// extGoName is used to override a field name
extGoName = "x-go-name"
// extGoTypeName is used to override a generated typename for something.
- extGoTypeName = "x-go-type-name"
- extPropGoJsonIgnore = "x-go-json-ignore"
- extPropOmitEmpty = "x-omitempty"
- extPropExtraTags = "x-oapi-codegen-extra-tags"
+ extGoTypeName = "x-go-type-name"
+ extPropGoJsonIgnore = "x-go-json-ignore"
+ extPropOmitEmpty = "x-omitempty"
+ extPropExtraTags = "x-oapi-codegen-extra-tags"
+ extEnumVarNames = "x-enum-varnames"
+ extEnumNames = "x-enumNames"
+ extDeprecationReason = "x-deprecated-reason"
)
func extString(extPropValue interface{}) (string, error) {
- raw, ok := extPropValue.(json.RawMessage)
+ str, ok := extPropValue.(string)
if !ok {
return "", fmt.Errorf("failed to convert type: %T", extPropValue)
}
- var str string
- if err := json.Unmarshal(raw, &str); err != nil {
- return "", fmt.Errorf("failed to unmarshal json: %w", err)
- }
-
return str, nil
}
func extTypeName(extPropValue interface{}) (string, error) {
@@ -40,41 +37,53 @@ func extParseGoFieldName(extPropValue interface{}) (string, error) {
}
func extParseOmitEmpty(extPropValue interface{}) (bool, error) {
- raw, ok := extPropValue.(json.RawMessage)
+ omitEmpty, ok := extPropValue.(bool)
if !ok {
return false, fmt.Errorf("failed to convert type: %T", extPropValue)
}
-
- var omitEmpty bool
- if err := json.Unmarshal(raw, &omitEmpty); err != nil {
- return false, fmt.Errorf("failed to unmarshal json: %w", err)
- }
-
return omitEmpty, nil
}
func extExtraTags(extPropValue interface{}) (map[string]string, error) {
- raw, ok := extPropValue.(json.RawMessage)
+ tagsI, ok := extPropValue.(map[string]interface{})
if !ok {
return nil, fmt.Errorf("failed to convert type: %T", extPropValue)
}
- var tags map[string]string
- if err := json.Unmarshal(raw, &tags); err != nil {
- return nil, fmt.Errorf("failed to unmarshal json: %w", err)
+ tags := make(map[string]string, len(tagsI))
+ for k, v := range tagsI {
+ vs, ok := v.(string)
+ if !ok {
+ return nil, fmt.Errorf("failed to convert type: %T", v)
+ }
+ tags[k] = vs
}
return tags, nil
}
func extParseGoJsonIgnore(extPropValue interface{}) (bool, error) {
- raw, ok := extPropValue.(json.RawMessage)
+ goJsonIgnore, ok := extPropValue.(bool)
if !ok {
return false, fmt.Errorf("failed to convert type: %T", extPropValue)
}
+ return goJsonIgnore, nil
+}
- var goJsonIgnore bool
- if err := json.Unmarshal(raw, &goJsonIgnore); err != nil {
- return false, fmt.Errorf("failed to unmarshal json: %w", err)
+func extParseEnumVarNames(extPropValue interface{}) ([]string, error) {
+ namesI, ok := extPropValue.([]interface{})
+ if !ok {
+ return nil, fmt.Errorf("failed to convert type: %T", extPropValue)
+ }
+ names := make([]string, len(namesI))
+ for i, v := range namesI {
+ vs, ok := v.(string)
+ if !ok {
+ return nil, fmt.Errorf("failed to convert type: %T", v)
+ }
+ names[i] = vs
}
+ return names, nil
+}
- return goJsonIgnore, nil
+func extParseDeprecationReason(extPropValue interface{}) (string, error) {
+ return extString(extPropValue)
}
diff --git a/pkg/codegen/extension_test.go b/pkg/codegen/extension_test.go
index 64681a604b..1d5a215639 100644
--- a/pkg/codegen/extension_test.go
+++ b/pkg/codegen/extension_test.go
@@ -9,7 +9,7 @@ import (
func Test_extTypeName(t *testing.T) {
type args struct {
- extPropValue interface{}
+ extPropValue json.RawMessage
}
tests := []struct {
name string
@@ -24,21 +24,27 @@ func Test_extTypeName(t *testing.T) {
wantErr: false,
},
{
- name: "type conversion error",
+ name: "nil conversion error",
args: args{nil},
want: "",
wantErr: true,
},
{
- name: "json unmarshal error",
- args: args{json.RawMessage("invalid json format")},
+ name: "type conversion error",
+ args: args{json.RawMessage(`12`)},
want: "",
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- got, err := extTypeName(tt.args.extPropValue)
+ // kin-openapi no longer returns these as RawMessage
+ var extPropValue interface{}
+ if tt.args.extPropValue != nil {
+ err := json.Unmarshal(tt.args.extPropValue, &extPropValue)
+ assert.NoError(t, err)
+ }
+ got, err := extTypeName(extPropValue)
if tt.wantErr {
assert.Error(t, err)
return
diff --git a/pkg/codegen/filter_test.go b/pkg/codegen/filter_test.go
index d3a5aec546..774d016a84 100644
--- a/pkg/codegen/filter_test.go
+++ b/pkg/codegen/filter_test.go
@@ -23,8 +23,11 @@ func TestFilterOperationsByTag(t *testing.T) {
},
}
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+
// Get a spec from the test definition in this file:
- swagger, err := openapi3.NewLoader().LoadFromData([]byte(testOpenAPIDefinition))
+ swagger, err := loader.LoadFromData([]byte(testOpenAPIDefinition))
assert.NoError(t, err)
// Run our code generation:
@@ -49,8 +52,11 @@ func TestFilterOperationsByTag(t *testing.T) {
},
}
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+
// Get a spec from the test definition in this file:
- swagger, err := openapi3.NewLoader().LoadFromData([]byte(testOpenAPIDefinition))
+ swagger, err := loader.LoadFromData([]byte(testOpenAPIDefinition))
assert.NoError(t, err)
// Run our code generation:
diff --git a/pkg/codegen/merge_schemas.go b/pkg/codegen/merge_schemas.go
index 610f0d2dec..84256b172e 100644
--- a/pkg/codegen/merge_schemas.go
+++ b/pkg/codegen/merge_schemas.go
@@ -37,7 +37,7 @@ func mergeSchemas(allOf []*openapi3.SchemaRef, path []string) (Schema, error) {
if err != nil {
return Schema{}, err
}
- schema, err = mergeOpenapiSchemas(schema, oneOfSchema)
+ schema, err = mergeOpenapiSchemas(schema, oneOfSchema, true)
if err != nil {
return Schema{}, fmt.Errorf("error merging schemas for AllOf: %w", err)
}
@@ -53,10 +53,10 @@ func valueWithPropagatedRef(ref *openapi3.SchemaRef) (openapi3.Schema, error) {
}
pathParts := strings.Split(ref.Ref, "#")
- if len(pathParts) != 2 {
+ if len(pathParts) < 1 || len(pathParts) > 2 {
return openapi3.Schema{}, fmt.Errorf("unsupported reference: %s", ref.Ref)
}
- remoteComponent, _ := pathParts[0], pathParts[1]
+ remoteComponent := pathParts[0]
// remote ref
schema := *ref.Value
@@ -74,7 +74,7 @@ func mergeAllOf(allOf []*openapi3.SchemaRef) (openapi3.Schema, error) {
var schema openapi3.Schema
for _, schemaRef := range allOf {
var err error
- schema, err = mergeOpenapiSchemas(schema, *schemaRef.Value)
+ schema, err = mergeOpenapiSchemas(schema, *schemaRef.Value, true)
if err != nil {
return openapi3.Schema{}, fmt.Errorf("error merging schemas for AllOf: %w", err)
}
@@ -84,7 +84,7 @@ func mergeAllOf(allOf []*openapi3.SchemaRef) (openapi3.Schema, error) {
// mergeOpenapiSchemas merges two openAPI schemas and returns the schema
// all of whose fields are composed.
-func mergeOpenapiSchemas(s1, s2 openapi3.Schema) (openapi3.Schema, error) {
+func mergeOpenapiSchemas(s1, s2 openapi3.Schema, allOf bool) (openapi3.Schema, error) {
var result openapi3.Schema
if s1.Extensions != nil || s2.Extensions != nil {
result.Extensions = make(map[string]interface{})
@@ -212,15 +212,15 @@ func mergeOpenapiSchemas(s1, s2 openapi3.Schema) (openapi3.Schema, error) {
if SchemaHasAdditionalProperties(&s1) && SchemaHasAdditionalProperties(&s2) {
return openapi3.Schema{}, errors.New("merging two schemas with additional properties, this is unhandled")
}
- if s1.AdditionalProperties != nil {
- result.AdditionalProperties = s1.AdditionalProperties
+ if s1.AdditionalProperties.Schema != nil {
+ result.AdditionalProperties.Schema = s1.AdditionalProperties.Schema
}
- if s2.AdditionalProperties != nil {
- result.AdditionalProperties = s2.AdditionalProperties
+ if s2.AdditionalProperties.Schema != nil {
+ result.AdditionalProperties.Schema = s2.AdditionalProperties.Schema
}
- // Unhandled for now
- if s1.Discriminator != nil || s2.Discriminator != nil {
+ // Allow discriminators for allOf merges, but disallow for one/anyOfs.
+ if !allOf && (s1.Discriminator != nil || s2.Discriminator != nil) {
return openapi3.Schema{}, errors.New("merging two schemas with discriminators is not supported")
}
diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go
index 314e89462d..55cc1bad51 100644
--- a/pkg/codegen/operations.go
+++ b/pkg/codegen/operations.go
@@ -126,8 +126,8 @@ func (pd ParameterDefinition) GoVariableName() string {
func (pd ParameterDefinition) GoName() string {
goName := pd.ParamName
- if _, ok := pd.Spec.ExtensionProps.Extensions[extGoName]; ok {
- if extGoFieldName, err := extParseGoFieldName(pd.Spec.ExtensionProps.Extensions[extGoName]); err == nil {
+ if _, ok := pd.Spec.Extensions[extGoName]; ok {
+ if extGoFieldName, err := extParseGoFieldName(pd.Spec.Extensions[extGoName]); err == nil {
goName = extGoFieldName
}
}
@@ -293,8 +293,18 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]ResponseTypeDefini
var typeName string
switch {
- case StringInArray(contentTypeName, contentTypesJSON):
+
+ // HAL+JSON:
+ case StringInArray(contentTypeName, contentTypesHalJSON):
+ typeName = fmt.Sprintf("HALJSON%s", ToCamelCase(responseName))
+ case "application/json" == contentTypeName:
+ // if it's the standard application/json
typeName = fmt.Sprintf("JSON%s", ToCamelCase(responseName))
+ // Vendored JSON
+ case StringInArray(contentTypeName, contentTypesJSON) || util.IsMediaTypeJson(contentTypeName):
+ baseTypeName := fmt.Sprintf("%s%s", ToCamelCase(contentTypeName), ToCamelCase(responseName))
+
+ typeName = strings.ReplaceAll(baseTypeName, "Json", "JSON")
// YAML:
case StringInArray(contentTypeName, contentTypesYAML):
typeName = fmt.Sprintf("YAML%s", ToCamelCase(responseName))
@@ -483,9 +493,16 @@ func FilterParameterDefinitionByType(params []ParameterDefinition, in string) []
}
// OperationDefinitions returns all operations for a swagger definition.
-func OperationDefinitions(swagger *openapi3.T) ([]OperationDefinition, error) {
+func OperationDefinitions(swagger *openapi3.T, initialismOverrides bool) ([]OperationDefinition, error) {
var operations []OperationDefinition
+ var toCamelCaseFunc func(string) string
+ if initialismOverrides {
+ toCamelCaseFunc = ToCamelCaseWithInitialism
+ } else {
+ toCamelCaseFunc = ToCamelCase
+ }
+
for _, requestPath := range SortedPathsKeys(swagger.Paths) {
pathItem := swagger.Paths[requestPath]
// These are parameters defined for all methods on a given path. They
@@ -505,13 +522,13 @@ func OperationDefinitions(swagger *openapi3.T) ([]OperationDefinition, error) {
}
// We rely on OperationID to generate function names, it's required
if op.OperationID == "" {
- op.OperationID, err = generateDefaultOperationID(opName, requestPath)
+ op.OperationID, err = generateDefaultOperationID(opName, requestPath, toCamelCaseFunc)
if err != nil {
return nil, fmt.Errorf("error generating default OperationID for %s/%s: %s",
opName, requestPath, err)
}
} else {
- op.OperationID = ToCamelCase(op.OperationID)
+ op.OperationID = toCamelCaseFunc(op.OperationID)
}
op.OperationID = typeNamePrefix(op.OperationID) + op.OperationID
@@ -550,7 +567,7 @@ func OperationDefinitions(swagger *openapi3.T) ([]OperationDefinition, error) {
HeaderParams: FilterParameterDefinitionByType(allParams, "header"),
QueryParams: FilterParameterDefinitionByType(allParams, "query"),
CookieParams: FilterParameterDefinitionByType(allParams, "cookie"),
- OperationId: ToCamelCase(op.OperationID),
+ OperationId: toCamelCaseFunc(op.OperationID),
// Replace newlines in summary.
Summary: op.Summary,
Method: opName,
@@ -588,7 +605,7 @@ func OperationDefinitions(swagger *openapi3.T) ([]OperationDefinition, error) {
return operations, nil
}
-func generateDefaultOperationID(opName string, requestPath string) (string, error) {
+func generateDefaultOperationID(opName string, requestPath string, toCamelCaseFunc func(string) string) (string, error) {
var operationId = strings.ToLower(opName)
if opName == "" {
@@ -605,7 +622,7 @@ func generateDefaultOperationID(opName string, requestPath string) (string, erro
}
}
- return ToCamelCase(operationId), nil
+ return toCamelCaseFunc(operationId), nil
}
// GenerateBodyDefinitions turns the Swagger body definitions into a list of our body
@@ -650,7 +667,7 @@ func GenerateBodyDefinitions(operationID string, bodyOrRef *openapi3.RequestBody
}
// If the body is a pre-defined type
- if IsGoTypeReference(content.Schema.Ref) {
+ if content.Schema != nil && IsGoTypeReference(content.Schema.Ref) {
// Convert the reference path to Go type
refType, err := RefPathToGoType(content.Schema.Ref)
if err != nil {
@@ -663,6 +680,17 @@ func GenerateBodyDefinitions(operationID string, bodyOrRef *openapi3.RequestBody
// type under #/components, we'll define a type for it, so
// that we have an easy to use type for marshaling.
if bodySchema.RefType == "" {
+ if contentType == "application/x-www-form-urlencoded" {
+ // Apply the appropriate structure tag if the request
+ // schema was defined under the operations' section.
+ for i := range bodySchema.Properties {
+ bodySchema.Properties[i].NeedsFormTag = true
+ }
+
+ // Regenerate the Golang struct adding the new form tag.
+ bodySchema.GoType = GenStructFromSchema(bodySchema)
+ }
+
td := TypeDefinition{
TypeName: bodyTypeName,
Schema: bodySchema,
@@ -825,12 +853,12 @@ func GenerateParamsTypes(op OperationDefinition) []TypeDefinition {
})
}
prop := Property{
- Description: param.Spec.Description,
- JsonFieldName: param.ParamName,
- Required: param.Required,
- Schema: pSchema,
- NeedsFormTag: param.Style() == "form",
- ExtensionProps: ¶m.Spec.ExtensionProps,
+ Description: param.Spec.Description,
+ JsonFieldName: param.ParamName,
+ Required: param.Required,
+ Schema: pSchema,
+ NeedsFormTag: param.Style() == "form",
+ Extensions: param.Spec.Extensions,
}
s.Properties = append(s.Properties, prop)
}
@@ -891,6 +919,12 @@ func GenerateChiServer(t *template.Template, operations []OperationDefinition) (
return GenerateTemplates([]string{"chi/chi-interface.tmpl", "chi/chi-middleware.tmpl", "chi/chi-handler.tmpl"}, t, operations)
}
+// GenerateFiberServer This function generates all the go code for the ServerInterface as well as
+// all the wrapper functions around our handlers.
+func GenerateFiberServer(t *template.Template, operations []OperationDefinition) (string, error) {
+ return GenerateTemplates([]string{"fiber/fiber-interface.tmpl", "fiber/fiber-middleware.tmpl", "fiber/fiber-handler.tmpl"}, t, operations)
+}
+
// GenerateEchoServer This function generates all the go code for the ServerInterface as well as
// all the wrapper functions around our handlers.
func GenerateEchoServer(t *template.Template, operations []OperationDefinition) (string, error) {
@@ -910,16 +944,22 @@ func GenerateGorillaServer(t *template.Template, operations []OperationDefinitio
}
func GenerateStrictServer(t *template.Template, operations []OperationDefinition, opts Configuration) (string, error) {
- templates := []string{"strict/strict-interface.tmpl"}
+
+ var templates []string
+
if opts.Generate.ChiServer || opts.Generate.GorillaServer {
- templates = append(templates, "strict/strict-http.tmpl")
+ templates = append(templates, "strict/strict-interface.tmpl", "strict/strict-http.tmpl")
}
if opts.Generate.EchoServer {
- templates = append(templates, "strict/strict-echo.tmpl")
+ templates = append(templates, "strict/strict-interface.tmpl", "strict/strict-echo.tmpl")
}
if opts.Generate.GinServer {
- templates = append(templates, "strict/strict-gin.tmpl")
+ templates = append(templates, "strict/strict-interface.tmpl", "strict/strict-gin.tmpl")
}
+ if opts.Generate.FiberServer {
+ templates = append(templates, "strict/strict-fiber-interface.tmpl", "strict/strict-fiber.tmpl")
+ }
+
return GenerateTemplates(templates, t, operations)
}
diff --git a/pkg/codegen/operations_test.go b/pkg/codegen/operations_test.go
index 0eff03e2c2..77a54a8c25 100644
--- a/pkg/codegen/operations_test.go
+++ b/pkg/codegen/operations_test.go
@@ -131,7 +131,7 @@ func TestGenerateDefaultOperationID(t *testing.T) {
}
for _, test := range suite {
- got, err := generateDefaultOperationID(test.op, test.path)
+ got, err := generateDefaultOperationID(test.op, test.path, ToCamelCase)
if err != nil {
if !test.wantErr {
t.Fatalf("did not expected error but got %v", err)
diff --git a/pkg/codegen/prune.go b/pkg/codegen/prune.go
index 03df80fecd..9dc4fd8719 100644
--- a/pkg/codegen/prune.go
+++ b/pkg/codegen/prune.go
@@ -35,7 +35,7 @@ func walkSwagger(swagger *openapi3.T, doFn func(RefWrapper) (bool, error)) error
}
}
- _ = walkComponents(&swagger.Components, doFn)
+ _ = walkComponents(swagger.Components, doFn)
return nil
}
@@ -144,7 +144,7 @@ func walkSchemaRef(ref *openapi3.SchemaRef, doFn func(RefWrapper) (bool, error))
_ = walkSchemaRef(ref, doFn)
}
- _ = walkSchemaRef(ref.Value.AdditionalProperties, doFn)
+ _ = walkSchemaRef(ref.Value.AdditionalProperties.Schema, doFn)
return nil
}
@@ -392,6 +392,10 @@ func findComponentRefs(swagger *openapi3.T) []string {
}
func removeOrphanedComponents(swagger *openapi3.T, refs []string) int {
+ if swagger.Components == nil {
+ return 0
+ }
+
countRemoved := 0
for key := range swagger.Components.Schemas {
diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go
index d8001f1998..eec2ad9240 100644
--- a/pkg/codegen/schema.go
+++ b/pkg/codegen/schema.go
@@ -1,6 +1,7 @@
package codegen
import (
+ "errors"
"fmt"
"strings"
@@ -75,15 +76,16 @@ func (s Schema) GetAdditionalTypeDefs() []TypeDefinition {
}
type Property struct {
- Description string
- JsonFieldName string
- Schema Schema
- Required bool
- Nullable bool
- ReadOnly bool
- WriteOnly bool
- NeedsFormTag bool
- ExtensionProps *openapi3.ExtensionProps
+ Description string
+ JsonFieldName string
+ Schema Schema
+ Required bool
+ Nullable bool
+ ReadOnly bool
+ WriteOnly bool
+ NeedsFormTag bool
+ Extensions map[string]interface{}
+ Deprecated bool
}
func (p Property) GoFieldName() string {
@@ -260,7 +262,8 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
return mergedSchema, nil
}
- // Check for custom Go type extension
+ // Check x-go-type, which will completely override the definition of this
+ // schema with the provided type.
if extension, ok := schema.Extensions[extPropGoType]; ok {
typeName, err := extTypeName(extension)
if err != nil {
@@ -268,6 +271,7 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
}
outSchema.GoType = typeName
outSchema.DefineViaAlias = true
+
return outSchema, nil
}
@@ -308,8 +312,8 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
// If additional properties are defined, we will override the default
// above with the specific definition.
- if schema.AdditionalProperties != nil {
- additionalSchema, err := GenerateGoSchema(schema.AdditionalProperties, path)
+ if schema.AdditionalProperties.Schema != nil {
+ additionalSchema, err := GenerateGoSchema(schema.AdditionalProperties.Schema, path)
if err != nil {
return Schema{}, fmt.Errorf("error generating type for additional properties: %w", err)
}
@@ -379,14 +383,15 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
description = p.Value.Description
}
prop := Property{
- JsonFieldName: pName,
- Schema: pSchema,
- Required: required,
- Description: description,
- Nullable: p.Value.Nullable,
- ReadOnly: p.Value.ReadOnly,
- WriteOnly: p.Value.WriteOnly,
- ExtensionProps: &p.Value.ExtensionProps,
+ JsonFieldName: pName,
+ Schema: pSchema,
+ Required: required,
+ Description: description,
+ Nullable: p.Value.Nullable,
+ ReadOnly: p.Value.ReadOnly,
+ WriteOnly: p.Value.WriteOnly,
+ Extensions: p.Value.Extensions,
+ Deprecated: p.Value.Deprecated,
}
outSchema.Properties = append(outSchema.Properties, prop)
}
@@ -404,6 +409,28 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
outSchema.GoType = GenStructFromSchema(outSchema)
}
+
+ // Check for x-go-type-name. It behaves much like x-go-type, however, it will
+ // create a type definition for the named type, and use the named type in place
+ // of this schema.
+ if extension, ok := schema.Extensions[extGoTypeName]; ok {
+ typeName, err := extTypeName(extension)
+ if err != nil {
+ return outSchema, fmt.Errorf("invalid value for %q: %w", extGoTypeName, err)
+ }
+
+ newTypeDef := TypeDefinition{
+ TypeName: typeName,
+ Schema: outSchema,
+ }
+ outSchema = Schema{
+ Description: newTypeDef.Schema.Description,
+ GoType: typeName,
+ DefineViaAlias: true,
+ AdditionalTypes: []TypeDefinition{newTypeDef},
+ }
+ }
+
return outSchema, nil
} else if len(schema.Enum) > 0 {
err := oapiSchemaToGoType(schema, path, &outSchema)
@@ -420,7 +447,17 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
enumValues[i] = fmt.Sprintf("%v", enumValue)
}
- sanitizedValues := SanitizeEnumNames(enumValues)
+ enumNames := enumValues
+ for _, key := range []string{extEnumVarNames, extEnumNames} {
+ if _, ok := schema.Extensions[key]; ok {
+ if extEnumNames, err := extParseEnumVarNames(schema.Extensions[key]); err == nil {
+ enumNames = extEnumNames
+ break
+ }
+ }
+ }
+
+ sanitizedValues := SanitizeEnumNames(enumNames, enumValues)
outSchema.EnumValues = make(map[string]string, len(sanitizedValues))
for k, v := range sanitizedValues {
@@ -595,8 +632,8 @@ func GenFieldsFromProperties(props []Property) []string {
field := ""
goFieldName := p.GoFieldName()
- if _, ok := p.ExtensionProps.Extensions[extGoName]; ok {
- if extGoFieldName, err := extParseGoFieldName(p.ExtensionProps.Extensions[extGoName]); err == nil {
+ if _, ok := p.Extensions[extGoName]; ok {
+ if extGoFieldName, err := extParseGoFieldName(p.Extensions[extGoName]); err == nil {
goFieldName = extGoFieldName
}
}
@@ -611,19 +648,34 @@ func GenFieldsFromProperties(props []Property) []string {
field += fmt.Sprintf("%s\n", StringWithTypeNameToGoComment(p.Description, p.GoFieldName()))
}
+ if p.Deprecated {
+ // This comment has to be on its own line for godoc & IDEs to pick up
+ var deprecationReason string
+ if _, ok := p.Extensions[extDeprecationReason]; ok {
+ if extOmitEmpty, err := extParseDeprecationReason(p.Extensions[extDeprecationReason]); err == nil {
+ deprecationReason = extOmitEmpty
+ }
+ }
+
+ field += fmt.Sprintf("%s\n", DeprecationComment(deprecationReason))
+ }
+
field += fmt.Sprintf(" %s %s", goFieldName, p.GoTypeDef())
+ omitEmpty := !p.Nullable &&
+ (!p.Required || p.ReadOnly || p.WriteOnly) &&
+ (!p.Required || !p.ReadOnly || !globalState.options.Compatibility.DisableRequiredReadOnlyAsPointer)
+
// Support x-omitempty
- overrideOmitEmpty := true
- if _, ok := p.ExtensionProps.Extensions[extPropOmitEmpty]; ok {
- if extOmitEmpty, err := extParseOmitEmpty(p.ExtensionProps.Extensions[extPropOmitEmpty]); err == nil {
- overrideOmitEmpty = extOmitEmpty
+ if extOmitEmptyValue, ok := p.Extensions[extPropOmitEmpty]; ok {
+ if extOmitEmpty, err := extParseOmitEmpty(extOmitEmptyValue); err == nil {
+ omitEmpty = extOmitEmpty
}
}
fieldTags := make(map[string]string)
- if (p.Required && !p.ReadOnly && !p.WriteOnly) || p.Nullable || !overrideOmitEmpty || (p.Required && p.ReadOnly && globalState.options.Compatibility.DisableRequiredReadOnlyAsPointer) {
+ if !omitEmpty {
fieldTags["json"] = p.JsonFieldName
if p.NeedsFormTag {
fieldTags["form"] = p.JsonFieldName
@@ -636,14 +688,14 @@ func GenFieldsFromProperties(props []Property) []string {
}
// Support x-go-json-ignore
- if _, ok := p.ExtensionProps.Extensions[extPropGoJsonIgnore]; ok {
- if goJsonIgnore, err := extParseGoJsonIgnore(p.ExtensionProps.Extensions[extPropGoJsonIgnore]); err == nil && goJsonIgnore {
+ if _, ok := p.Extensions[extPropGoJsonIgnore]; ok {
+ if goJsonIgnore, err := extParseGoJsonIgnore(p.Extensions[extPropGoJsonIgnore]); err == nil && goJsonIgnore {
fieldTags["json"] = "-"
}
}
// Support x-oapi-codegen-extra-tags
- if extension, ok := p.ExtensionProps.Extensions[extPropExtraTags]; ok {
+ if extension, ok := p.Extensions[extPropExtraTags]; ok {
if tags, err := extExtraTags(extension); err == nil {
keys := SortedStringKeys(tags)
for _, k := range keys {
@@ -749,15 +801,30 @@ func generateUnion(outSchema *Schema, elements openapi3.SchemaRefs, discriminato
}
if discriminator != nil {
+ if len(discriminator.Mapping) != 0 && element.Ref == "" {
+ return errors.New("ambiguous discriminator.mapping: please replace inlined object with $ref")
+ }
+
+ // Explicit mapping.
+ var mapped bool
for k, v := range discriminator.Mapping {
if v == element.Ref {
outSchema.Discriminator.Mapping[k] = elementSchema.GoType
+ mapped = true
break
}
}
+ // Implicit mapping.
+ if !mapped {
+ outSchema.Discriminator.Mapping[RefPathToObjName(element.Ref)] = elementSchema.GoType
+ }
}
outSchema.UnionElements = append(outSchema.UnionElements, UnionElement(elementSchema.GoType))
}
+ if (outSchema.Discriminator != nil) && len(outSchema.Discriminator.Mapping) != len(elements) {
+ return errors.New("discriminator: not all schemas were mapped")
+ }
+
return nil
}
diff --git a/pkg/codegen/template_helpers.go b/pkg/codegen/template_helpers.go
index 7585a26801..d0c440f286 100644
--- a/pkg/codegen/template_helpers.go
+++ b/pkg/codegen/template_helpers.go
@@ -34,9 +34,10 @@ const (
)
var (
- contentTypesJSON = []string{echo.MIMEApplicationJSON, "text/x-json", "application/problem+json"}
- contentTypesYAML = []string{"application/yaml", "application/x-yaml", "text/yaml", "text/x-yaml"}
- contentTypesXML = []string{echo.MIMEApplicationXML, echo.MIMETextXML, "application/problems+xml"}
+ contentTypesJSON = []string{echo.MIMEApplicationJSON, "text/x-json", "application/problem+json"}
+ contentTypesHalJSON = []string{"application/hal+json"}
+ contentTypesYAML = []string{"application/yaml", "application/x-yaml", "text/yaml", "text/x-yaml"}
+ contentTypesXML = []string{echo.MIMEApplicationXML, echo.MIMETextXML, "application/problems+xml"}
responseTypeSuffix = "Response"
@@ -263,7 +264,11 @@ func getConditionOfResponseName(statusCodeVar, responseName string) string {
// This outputs a string array
func toStringArray(sarr []string) string {
- return `[]string{"` + strings.Join(sarr, `","`) + `"}`
+ s := strings.Join(sarr, `","`)
+ if len(s) > 0 {
+ s = `"` + s + `"`
+ }
+ return `[]string{` + s + `}`
}
func stripNewLines(s string) string {
@@ -279,6 +284,7 @@ var TemplateFunctions = template.FuncMap{
"genParamNames": genParamNames,
"genParamFmtString": ReplacePathParamsWithStr,
"swaggerUriToEchoUri": SwaggerUriToEchoUri,
+ "swaggerUriToFiberUri": SwaggerUriToFiberUri,
"swaggerUriToChiUri": SwaggerUriToChiUri,
"swaggerUriToGinUri": SwaggerUriToGinUri,
"swaggerUriToGorillaUri": SwaggerUriToGorillaUri,
diff --git a/pkg/codegen/templates/additional-properties.tmpl b/pkg/codegen/templates/additional-properties.tmpl
index 8a37647bf4..c83cc107ed 100644
--- a/pkg/codegen/templates/additional-properties.tmpl
+++ b/pkg/codegen/templates/additional-properties.tmpl
@@ -17,6 +17,7 @@ func (a *{{.TypeName}}) Set(fieldName string, value {{$addType}}) {
a.AdditionalProperties[fieldName] = value
}
+{{if eq 0 (len .Schema.UnionElements) -}}
// Override default JSON handling for {{.TypeName}} to handle AdditionalProperties
func (a *{{.TypeName}}) UnmarshalJSON(b []byte) error {
object := make(map[string]json.RawMessage)
@@ -68,3 +69,4 @@ func (a {{.TypeName}}) MarshalJSON() ([]byte, error) {
return json.Marshal(object)
}
{{end}}
+{{end}}
\ No newline at end of file
diff --git a/pkg/codegen/templates/client.tmpl b/pkg/codegen/templates/client.tmpl
index 58df443c76..f3afe84288 100644
--- a/pkg/codegen/templates/client.tmpl
+++ b/pkg/codegen/templates/client.tmpl
@@ -194,36 +194,38 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr
}
{{if .QueryParams}}
- queryValues := queryURL.Query()
-{{range $paramIdx, $param := .QueryParams}}
- {{if not .Required}} if params.{{.GoName}} != nil { {{end}}
- {{if .IsPassThrough}}
- queryValues.Add("{{.ParamName}}", {{if not .Required}}*{{end}}params.{{.GoName}})
- {{end}}
- {{if .IsJson}}
- if queryParamBuf, err := json.Marshal({{if not .Required}}*{{end}}params.{{.GoName}}); err != nil {
- return nil, err
- } else {
- queryValues.Add("{{.ParamName}}", string(queryParamBuf))
- }
+ if params != nil {
+ queryValues := queryURL.Query()
+ {{range $paramIdx, $param := .QueryParams}}
+ {{if not .Required}} if params.{{.GoName}} != nil { {{end}}
+ {{if .IsPassThrough}}
+ queryValues.Add("{{.ParamName}}", {{if not .Required}}*{{end}}params.{{.GoName}})
+ {{end}}
+ {{if .IsJson}}
+ if queryParamBuf, err := json.Marshal({{if not .Required}}*{{end}}params.{{.GoName}}); err != nil {
+ return nil, err
+ } else {
+ queryValues.Add("{{.ParamName}}", string(queryParamBuf))
+ }
- {{end}}
- {{if .IsStyled}}
- if queryFrag, err := runtime.StyleParamWithLocation("{{.Style}}", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationQuery, {{if not .Required}}*{{end}}params.{{.GoName}}); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
- return nil, err
- } else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
- }
- }
+ {{end}}
+ {{if .IsStyled}}
+ if queryFrag, err := runtime.StyleParamWithLocation("{{.Style}}", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationQuery, {{if not .Required}}*{{end}}params.{{.GoName}}); err != nil {
+ return nil, err
+ } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ return nil, err
+ } else {
+ for k, v := range parsed {
+ for _, v2 := range v {
+ queryValues.Add(k, v2)
+ }
+ }
+ }
+ {{end}}
+ {{if not .Required}}}{{end}}
+ {{end}}
+ queryURL.RawQuery = queryValues.Encode()
}
- {{end}}
- {{if not .Required}}}{{end}}
-{{end}}
- queryURL.RawQuery = queryValues.Encode()
{{end}}{{/* if .QueryParams */}}
req, err := http.NewRequest("{{.Method}}", queryURL.String(), {{if .HasBody}}body{{else}}nil{{end}})
if err != nil {
diff --git a/pkg/codegen/templates/fiber/fiber-handler.tmpl b/pkg/codegen/templates/fiber/fiber-handler.tmpl
new file mode 100644
index 0000000000..4a55b3c512
--- /dev/null
+++ b/pkg/codegen/templates/fiber/fiber-handler.tmpl
@@ -0,0 +1,25 @@
+// FiberServerOptions provides options for the Fiber server.
+type FiberServerOptions struct {
+ BaseURL string
+ Middlewares []MiddlewareFunc
+}
+
+// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
+func RegisterHandlers(router fiber.Router, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, FiberServerOptions{})
+}
+
+// RegisterHandlersWithOptions creates http.Handler with additional options
+func RegisterHandlersWithOptions(router fiber.Router, si ServerInterface, options FiberServerOptions) {
+{{if .}}wrapper := ServerInterfaceWrapper{
+Handler: si,
+}
+
+for _, m := range options.Middlewares {
+ router.Use(m)
+}
+{{end}}
+{{range .}}
+router.{{.Method | lower | title }}(options.BaseURL+"{{.Path | swaggerUriToFiberUri}}", wrapper.{{.OperationId}})
+{{end}}
+}
diff --git a/pkg/codegen/templates/fiber/fiber-interface.tmpl b/pkg/codegen/templates/fiber/fiber-interface.tmpl
new file mode 100644
index 0000000000..8ef90a851a
--- /dev/null
+++ b/pkg/codegen/templates/fiber/fiber-interface.tmpl
@@ -0,0 +1,7 @@
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+{{range .}}{{.SummaryAsComment }}
+// ({{.Method}} {{.Path}})
+{{.OperationId}}(c *fiber.Ctx{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params {{.OperationId}}Params{{end}}) error
+{{end}}
+}
diff --git a/pkg/codegen/templates/fiber/fiber-middleware.tmpl b/pkg/codegen/templates/fiber/fiber-middleware.tmpl
new file mode 100644
index 0000000000..fd8d00dc15
--- /dev/null
+++ b/pkg/codegen/templates/fiber/fiber-middleware.tmpl
@@ -0,0 +1,169 @@
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+}
+
+type MiddlewareFunc fiber.Handler
+
+{{range .}}{{$opid := .OperationId}}
+
+// {{$opid}} operation middleware
+func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error {
+
+ {{if or .RequiresParamObject (gt (len .PathParams) 0) }}
+ var err error
+ {{end}}
+
+ {{range .PathParams}}// ------------- Path parameter "{{.ParamName}}" -------------
+ var {{$varName := .GoVariableName}}{{$varName}} {{.TypeDef}}
+
+ {{if .IsPassThrough}}
+ {{$varName}} = c.Query("{{.ParamName}}")
+ {{end}}
+ {{if .IsJson}}
+ err = json.Unmarshal([]byte(c.Query("{{.ParamName}}")), &{{$varName}})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unmarshalling parameter '{{.ParamName}}' as JSON: %w", err).Error())
+ }
+ {{end}}
+ {{if .IsStyled}}
+ err = runtime.BindStyledParameter("{{.Style}}",{{.Explode}}, "{{.ParamName}}", c.Params("{{.ParamName}}"), &{{$varName}})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %w", err).Error())
+ }
+ {{end}}
+
+ {{end}}
+
+{{range .SecurityDefinitions}}
+ c.Context().SetUserValue({{.ProviderName | ucFirst}}Scopes, {{toStringArray .Scopes}})
+{{end}}
+
+ {{if .RequiresParamObject}}
+ // Parameter object where we will unmarshal all parameters from the context
+ var params {{.OperationId}}Params
+
+ {{if .QueryParams}}
+ var query url.Values
+ query, err = url.ParseQuery(string(c.Request().URI().QueryString()))
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for query string: %w", err).Error())
+ }
+ {{end}}
+
+ {{range $paramIdx, $param := .QueryParams}}
+ {{- if (or (or .Required .IsPassThrough) (or .IsJson .IsStyled)) -}}
+ // ------------- {{if .Required}}Required{{else}}Optional{{end}} query parameter "{{.ParamName}}" -------------
+ {{ end }}
+ {{ if (or (or .Required .IsPassThrough) .IsJson) }}
+ if paramValue := c.Query("{{.ParamName}}"); paramValue != "" {
+
+ {{if .IsPassThrough}}
+ params.{{.GoName}} = {{if not .Required}}&{{end}}paramValue
+ {{end}}
+
+ {{if .IsJson}}
+ var value {{.TypeDef}}
+ err = json.Unmarshal([]byte(paramValue), &value)
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unmarshalling parameter '{{.ParamName}}' as JSON: %w", err).Error())
+ }
+
+ params.{{.GoName}} = {{if not .Required}}&{{end}}value
+ {{end}}
+ }{{if .Required}} else {
+ err = fmt.Errorf("Query argument {{.ParamName}} is required, but not found")
+ c.Status(fiber.StatusBadRequest).JSON(err)
+ return err
+ }{{end}}
+ {{end}}
+ {{if .IsStyled}}
+ err = runtime.BindQueryParameter("{{.Style}}", {{.Explode}}, {{.Required}}, "{{.ParamName}}", query, ¶ms.{{.GoName}})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %w", err).Error())
+ }
+ {{end}}
+ {{end}}
+
+ {{if .HeaderParams}}
+ headers := c.GetReqHeaders()
+
+ {{range .HeaderParams}}// ------------- {{if .Required}}Required{{else}}Optional{{end}} header parameter "{{.ParamName}}" -------------
+ if value, found := headers[http.CanonicalHeaderKey("{{.ParamName}}")]; found {
+ var {{.GoName}} {{.TypeDef}}
+
+ {{if .IsPassThrough}}
+ params.{{.GoName}} = {{if not .Required}}&{{end}}value
+ {{end}}
+
+ {{if .IsJson}}
+ err = json.Unmarshal([]byte(value), &{{.GoName}})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unmarshalling parameter '{{.ParamName}}' as JSON: %w", err).Error())
+ }
+ {{end}}
+
+ {{if .IsStyled}}
+ err = runtime.BindStyledParameterWithLocation("{{.Style}}",{{.Explode}}, "{{.ParamName}}", runtime.ParamLocationHeader, value, &{{.GoName}})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %w", err).Error())
+ }
+ {{end}}
+
+ params.{{.GoName}} = {{if not .Required}}&{{end}}{{.GoName}}
+
+ } {{if .Required}}else {
+ err = fmt.Errorf("Header parameter {{.ParamName}} is required, but not found: %w", err)
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }{{end}}
+
+ {{end}}
+ {{end}}
+
+ {{range .CookieParams}}
+ var cookie string
+
+ if cookie = c.Cookies("{{.ParamName}}"); cookie == "" {
+
+ {{- if .IsPassThrough}}
+ params.{{.GoName}} = {{if not .Required}}&{{end}}cookie
+ {{end}}
+
+ {{- if .IsJson}}
+ var value {{.TypeDef}}
+ var decoded string
+ decoded, err := url.QueryUnescape(cookie)
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unescaping cookie parameter '{{.ParamName}}': %w", err).Error())
+ }
+
+ err = json.Unmarshal([]byte(decoded), &value)
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unmarshalling parameter '{{.ParamName}}' as JSON: %w", err).Error())
+ }
+
+ params.{{.GoName}} = {{if not .Required}}&{{end}}value
+ {{end}}
+
+ {{- if .IsStyled}}
+ var value {{.TypeDef}}
+ err = runtime.BindStyledParameter("simple",{{.Explode}}, "{{.ParamName}}", cookie, &value)
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %w", err).Error())
+ }
+ params.{{.GoName}} = {{if not .Required}}&{{end}}value
+ {{end}}
+
+ }
+
+ {{- if .Required}} else {
+ err = fmt.Errorf("Query argument {{.ParamName}} is required, but not found")
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ {{- end}}
+ {{end}}
+ {{end}}
+
+ return siw.Handler.{{.OperationId}}(c{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}})
+}
+{{end}}
diff --git a/pkg/codegen/templates/gin/gin-register.tmpl b/pkg/codegen/templates/gin/gin-register.tmpl
index 188cbb83ea..8f03722ab1 100644
--- a/pkg/codegen/templates/gin/gin-register.tmpl
+++ b/pkg/codegen/templates/gin/gin-register.tmpl
@@ -6,15 +6,14 @@ type GinServerOptions struct {
}
// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
-func RegisterHandlers(router *gin.Engine, si ServerInterface) *gin.Engine {
- return RegisterHandlersWithOptions(router, si, GinServerOptions{})
+func RegisterHandlers(router gin.IRouter, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, GinServerOptions{})
}
// RegisterHandlersWithOptions creates http.Handler with additional options
-func RegisterHandlersWithOptions(router *gin.Engine, si ServerInterface, options GinServerOptions) *gin.Engine {
- {{if .}}
+func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options GinServerOptions) {
+ {{- if . -}}
errorHandler := options.ErrorHandler
-
if errorHandler == nil {
errorHandler = func(c *gin.Context, err error, statusCode int) {
c.JSON(statusCode, gin.H{"msg": err.Error()})
@@ -27,8 +26,8 @@ func RegisterHandlersWithOptions(router *gin.Engine, si ServerInterface, options
ErrorHandler: errorHandler,
}
{{end}}
- {{range .}}
+
+ {{range . -}}
router.{{.Method }}(options.BaseURL+"{{.Path | swaggerUriToGinUri }}", wrapper.{{.OperationId}})
- {{end}}
- return router
+ {{end -}}
}
diff --git a/pkg/codegen/templates/gin/gin-wrappers.tmpl b/pkg/codegen/templates/gin/gin-wrappers.tmpl
index a0beee4855..e30e839f5d 100644
--- a/pkg/codegen/templates/gin/gin-wrappers.tmpl
+++ b/pkg/codegen/templates/gin/gin-wrappers.tmpl
@@ -69,7 +69,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
params.{{.GoName}} = {{if not .Required}}&{{end}}value
{{end}}
}{{if .Required}} else {
- siw.ErrorHandler(c, fmt.Errorf("Query argument {{.ParamName}} is required, but not found: %s", err), http.StatusBadRequest)
+ siw.ErrorHandler(c, fmt.Errorf("Query argument {{.ParamName}} is required, but not found"), http.StatusBadRequest)
return
}{{end}}
{{end}}
@@ -118,7 +118,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
params.{{.GoName}} = {{if not .Required}}&{{end}}{{.GoName}}
} {{if .Required}}else {
- siw.ErrorHandler(c, fmt.Errorf("Header parameter {{.ParamName}} is required, but not found: %s", err), http.StatusBadRequest)
+ siw.ErrorHandler(c, fmt.Errorf("Header parameter {{.ParamName}} is required, but not found"), http.StatusBadRequest)
return
}{{end}}
@@ -126,18 +126,19 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
{{end}}
{{range .CookieParams}}
- var cookie *http.Cookie
+ {
+ var cookie string
if cookie, err = c.Cookie("{{.ParamName}}"); err == nil {
{{- if .IsPassThrough}}
- params.{{.GoName}} = {{if not .Required}}&{{end}}cookie.Value
+ params.{{.GoName}} = {{if not .Required}}&{{end}}cookie
{{end}}
{{- if .IsJson}}
var value {{.TypeDef}}
var decoded string
- decoded, err := url.QueryUnescape(cookie.Value)
+ decoded, err := url.QueryUnescape(cookie)
if err != nil {
siw.ErrorHandler(c, fmt.Errorf("Error unescaping cookie parameter '{{.ParamName}}'"), http.StatusBadRequest)
return
@@ -154,7 +155,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
{{- if .IsStyled}}
var value {{.TypeDef}}
- err = runtime.BindStyledParameter("simple",{{.Explode}}, "{{.ParamName}}", cookie.Value, &value)
+ err = runtime.BindStyledParameter("simple",{{.Explode}}, "{{.ParamName}}", cookie, &value)
if err != nil {
siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %s", err), http.StatusBadRequest)
return
@@ -169,11 +170,15 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
return
}
{{- end}}
+ }
{{end}}
{{end}}
for _, middleware := range siw.HandlerMiddlewares {
middleware(c)
+ if c.IsAborted() {
+ return
+ }
}
siw.Handler.{{.OperationId}}(c{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}})
diff --git a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl
index 5150186b04..1360891137 100644
--- a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl
+++ b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl
@@ -177,9 +177,15 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
siw.Handler.{{.OperationId}}(w, r{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}})
}
+ {{if opts.Compatibility.ApplyGorillaMiddlewareFirstToLast}}
+ for i := len(siw.HandlerMiddlewares) -1; i >= 0; i-- {
+ handler = siw.HandlerMiddlewares[i](handler)
+ }
+ {{else}}
for _, middleware := range siw.HandlerMiddlewares {
handler = middleware(handler)
}
+ {{end}}
handler(w, r.WithContext(ctx))
}
diff --git a/pkg/codegen/templates/imports.tmpl b/pkg/codegen/templates/imports.tmpl
index ef43ef390f..f69a492038 100644
--- a/pkg/codegen/templates/imports.tmpl
+++ b/pkg/codegen/templates/imports.tmpl
@@ -27,6 +27,7 @@ import (
"github.com/go-chi/chi/v5"
"github.com/labstack/echo/v4"
"github.com/gin-gonic/gin"
+ "github.com/gofiber/fiber/v2"
"github.com/gorilla/mux"
{{- range .ExternalImports}}
{{ . }}
diff --git a/pkg/codegen/templates/strict/strict-echo.tmpl b/pkg/codegen/templates/strict/strict-echo.tmpl
index c858c09f8e..86def37a35 100644
--- a/pkg/codegen/templates/strict/strict-echo.tmpl
+++ b/pkg/codegen/templates/strict/strict-echo.tmpl
@@ -1,6 +1,5 @@
-type StrictHandlerFunc func(ctx echo.Context, args interface{}) (interface{}, error)
-
-type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+type StrictHandlerFunc = runtime.StrictEchoHandlerFunc
+type StrictMiddlewareFunc = runtime.StrictEchoMiddlewareFunc
func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
return &strictHandler{ssi: ssi, middlewares: middlewares}
@@ -18,8 +17,7 @@ type strictHandler struct {
var request {{$opid | ucFirst}}RequestObject
{{range .PathParams -}}
- {{$varName := .GoVariableName -}}
- request.{{$varName | ucFirst}} = {{$varName}}
+ request.{{.GoName}} = {{.GoVariableName}}
{{end -}}
{{if .RequiresParamObject -}}
diff --git a/pkg/codegen/templates/strict/strict-fiber-interface.tmpl b/pkg/codegen/templates/strict/strict-fiber-interface.tmpl
new file mode 100644
index 0000000000..6fdef0981f
--- /dev/null
+++ b/pkg/codegen/templates/strict/strict-fiber-interface.tmpl
@@ -0,0 +1,137 @@
+{{range .}}
+ {{$opid := .OperationId -}}
+ type {{$opid | ucFirst}}RequestObject struct {
+ {{range .PathParams -}}
+ {{.GoName | ucFirst}} {{.TypeDef}} {{.JsonTag}}
+ {{end -}}
+ {{if .RequiresParamObject -}}
+ Params {{$opid}}Params
+ {{end -}}
+ {{if .HasMaskedRequestContentTypes -}}
+ ContentType string
+ {{end -}}
+ {{$multipleBodies := gt (len .Bodies) 1 -}}
+ {{range .Bodies -}}
+ {{if $multipleBodies}}{{.NameTag}}{{end}}Body {{if eq .NameTag "Multipart"}}*multipart.Reader{{else if ne .NameTag ""}}*{{$opid}}{{.NameTag}}RequestBody{{else}}io.Reader{{end}}
+ {{end -}}
+ }
+
+ type {{$opid | ucFirst}}ResponseObject interface {
+ Visit{{$opid}}Response(ctx *fiber.Ctx) error
+ }
+
+ {{range .Responses}}
+ {{$statusCode := .StatusCode -}}
+ {{$hasHeaders := ne 0 (len .Headers) -}}
+ {{$fixedStatusCode := .HasFixedStatusCode -}}
+ {{$isRef := .IsRef -}}
+ {{$ref := .Ref | ucFirst -}}
+ {{$headers := .Headers -}}
+
+ {{if (and $hasHeaders (not $isRef)) -}}
+ type {{$opid}}{{$statusCode}}ResponseHeaders struct {
+ {{range .Headers -}}
+ {{.GoName}} {{.Schema.TypeDecl}}
+ {{end -}}
+ }
+ {{end}}
+
+ {{range .Contents}}
+ {{$receiverTypeName := printf "%s%s%s%s" $opid $statusCode .NameTagOrContentType "Response"}}
+ {{if and $fixedStatusCode $isRef -}}
+ type {{$receiverTypeName}} struct{ {{$ref}}{{.NameTagOrContentType}}Response }
+ {{else if and (not $hasHeaders) ($fixedStatusCode) (.IsSupported) -}}
+ type {{$receiverTypeName}} {{if eq .NameTag "Multipart"}}func(writer *multipart.Writer)error{{else if .IsSupported}}{{if .Schema.IsRef}}={{end}} {{.Schema.TypeDecl}}{{else}}io.Reader{{end}}
+ {{else -}}
+ type {{$receiverTypeName}} struct {
+ Body {{if eq .NameTag "Multipart"}}func(writer *multipart.Writer)error{{else if .IsSupported}}{{.Schema.TypeDecl}}{{else}}io.Reader{{end}}
+ {{if $hasHeaders -}}
+ Headers {{if $isRef}}{{$ref}}{{else}}{{$opid}}{{$statusCode}}{{end}}ResponseHeaders
+ {{end -}}
+
+ {{if not $fixedStatusCode -}}
+ StatusCode int
+ {{end -}}
+
+ {{if not .HasFixedContentType -}}
+ ContentType string
+ {{end -}}
+
+ {{if not .IsSupported -}}
+ ContentLength int64
+ {{end -}}
+ }
+ {{end}}
+
+ func (response {{$receiverTypeName}}) Visit{{$opid}}Response(ctx *fiber.Ctx) error {
+ {{range $headers -}}
+ ctx.Response().Header.Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}))
+ {{end -}}
+ {{if eq .NameTag "Multipart" -}}
+ writer := multipart.NewWriter(ctx.Response().BodyWriter())
+ {{end -}}
+ ctx.Response().Header.Set("Content-Type", {{if eq .NameTag "Multipart"}}writer.FormDataContentType(){{else if .HasFixedContentType }}"{{.ContentType}}"{{else}}response.ContentType{{end}})
+ {{if not .IsSupported -}}
+ if response.ContentLength != 0 {
+ ctx.Response().Header.Set("Content-Length", fmt.Sprint(response.ContentLength))
+ }
+ {{end -}}
+ ctx.Status({{if $fixedStatusCode}}{{$statusCode}}{{else}}response.StatusCode{{end}})
+ {{$hasBodyVar := or ($hasHeaders) (not $fixedStatusCode) (not .IsSupported)}}
+ {{if eq .NameTag "JSON" -}}
+ return ctx.JSON(&{{if $hasBodyVar}}response.Body{{else}}response{{end}})
+ {{else if eq .NameTag "Text" -}}
+ _, err := ctx.WriteString(string({{if $hasBodyVar}}response.Body{{else}}response{{end}}))
+ return err
+ {{else if eq .NameTag "Formdata" -}}
+ if form, err := runtime.MarshalForm({{if $hasBodyVar}}response.Body{{else}}response{{end}}, nil); err != nil {
+ return err
+ } else {
+ _, err := ctx.WriteString(form.Encode())
+ return err
+ }
+ {{else if eq .NameTag "Multipart" -}}
+ defer writer.Close()
+ return {{if $hasBodyVar}}response.Body{{else}}response{{end}}(writer);
+ {{else -}}
+ if closer, ok := response.Body.(io.ReadCloser); ok {
+ defer closer.Close()
+ }
+ _, err := io.Copy(ctx.Response().BodyWriter(), response.Body)
+ return err
+ {{end}}{{/* if eq .NameTag "JSON" */ -}}
+ }
+ {{end}}
+
+ {{if eq 0 (len .Contents) -}}
+ {{if and $fixedStatusCode $isRef -}}
+ type {{$opid}}{{$statusCode}}Response = {{$ref}}Response
+ {{else -}}
+ type {{$opid}}{{$statusCode}}Response struct {
+ {{if $hasHeaders -}}
+ Headers {{if $isRef}}{{$ref}}{{else}}{{$opid}}{{$statusCode}}{{end}}ResponseHeaders
+ {{end}}
+ {{if not $fixedStatusCode -}}
+ StatusCode int
+ {{end -}}
+ }
+ {{end -}}
+ func (response {{$opid}}{{$statusCode}}Response) Visit{{$opid}}Response(ctx *fiber.Ctx) error {
+ {{range $headers -}}
+ ctx.Response().Header.Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}))
+ {{end -}}
+ ctx.Status({{if $fixedStatusCode}}{{$statusCode}}{{else}}response.StatusCode{{end}})
+ return nil
+ }
+ {{end}}
+ {{end}}
+{{end}}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+{{range .}}{{.SummaryAsComment }}
+// ({{.Method}} {{.Path}})
+{{$opid := .OperationId -}}
+{{$opid}}(ctx context.Context, request {{$opid | ucFirst}}RequestObject) ({{$opid | ucFirst}}ResponseObject, error)
+{{end}}{{/* range . */ -}}
+}
diff --git a/pkg/codegen/templates/strict/strict-fiber.tmpl b/pkg/codegen/templates/strict/strict-fiber.tmpl
new file mode 100644
index 0000000000..38a819f71b
--- /dev/null
+++ b/pkg/codegen/templates/strict/strict-fiber.tmpl
@@ -0,0 +1,80 @@
+type StrictHandlerFunc func(ctx *fiber.Ctx, args interface{}) (interface{}, error)
+
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+}
+
+{{range .}}
+ {{$opid := .OperationId}}
+ // {{$opid}} operation middleware
+ func (sh *strictHandler) {{.OperationId}}(ctx *fiber.Ctx{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params {{.OperationId}}Params{{end}}) error {
+ var request {{$opid | ucFirst}}RequestObject
+
+ {{range .PathParams -}}
+ {{$varName := .GoVariableName -}}
+ request.{{.GoName}} = {{.GoVariableName}}
+ {{end -}}
+
+ {{if .RequiresParamObject -}}
+ request.Params = params
+ {{end -}}
+
+ {{ if .HasMaskedRequestContentTypes -}}
+ request.ContentType = string(ctx.Request().Header.ContentType())
+ {{end -}}
+
+ {{$multipleBodies := gt (len .Bodies) 1 -}}
+ {{range .Bodies -}}
+ {{if $multipleBodies}}if strings.HasPrefix(string(ctx.Request().Header.ContentType()), "{{.ContentType}}") { {{end}}
+ {{if eq .NameTag "JSON" -}}
+ var body {{$opid}}{{.NameTag}}RequestBody
+ if err := ctx.BodyParser(&body); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body
+ {{else if eq .NameTag "Formdata" -}}
+ var body {{$opid}}{{.NameTag}}RequestBody
+ if err := ctx.BodyParser(&body); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body
+ {{else if eq .NameTag "Multipart" -}}
+ request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = multipart.NewReader(bytes.NewReader(ctx.Request().Body()), string(ctx.Request().Header.MultipartFormBoundary()))
+ {{else if eq .NameTag "Text" -}}
+ data := ctx.Request().Body()
+ body := {{$opid}}{{.NameTag}}RequestBody(data)
+ request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body
+ {{else -}}
+ request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = bytes.NewReader(ctx.Request().Body())
+ {{end}}{{/* if eq .NameTag "JSON" */ -}}
+ {{if $multipleBodies}}}{{end}}
+ {{end}}{{/* range .Bodies */}}
+
+ handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+ return sh.ssi.{{.OperationId}}(ctx.UserContext(), request.({{$opid | ucFirst}}RequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "{{.OperationId}}")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ } else if validResponse, ok := response.({{$opid | ucFirst}}ResponseObject); ok {
+ if err := validResponse.Visit{{$opid}}Response(ctx); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else if response != nil {
+ return fmt.Errorf("Unexpected response type: %T", response)
+ }
+ return nil
+ }
+{{end}}
diff --git a/pkg/codegen/templates/strict/strict-gin.tmpl b/pkg/codegen/templates/strict/strict-gin.tmpl
index 8097e2801c..0c36f40eeb 100644
--- a/pkg/codegen/templates/strict/strict-gin.tmpl
+++ b/pkg/codegen/templates/strict/strict-gin.tmpl
@@ -1,6 +1,5 @@
-type StrictHandlerFunc func(ctx *gin.Context, args interface{}) (interface{}, error)
-
-type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+type StrictHandlerFunc = runtime.StrictGinHandlerFunc
+type StrictMiddlewareFunc = runtime.StrictGinMiddlewareFunc
func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
return &strictHandler{ssi: ssi, middlewares: middlewares}
@@ -18,8 +17,7 @@ type strictHandler struct {
var request {{$opid | ucFirst}}RequestObject
{{range .PathParams -}}
- {{$varName := .GoVariableName -}}
- request.{{$varName | ucFirst}} = {{$varName}}
+ request.{{.GoName}} = {{.GoVariableName}}
{{end -}}
{{if .RequiresParamObject -}}
@@ -84,6 +82,7 @@ type strictHandler struct {
if err != nil {
ctx.Error(err)
+ ctx.Status(http.StatusInternalServerError)
} else if validResponse, ok := response.({{$opid | ucFirst}}ResponseObject); ok {
if err := validResponse.Visit{{$opid}}Response(ctx.Writer); err != nil {
ctx.Error(err)
diff --git a/pkg/codegen/templates/strict/strict-http.tmpl b/pkg/codegen/templates/strict/strict-http.tmpl
index b1d2e9dba4..b16ed1d399 100644
--- a/pkg/codegen/templates/strict/strict-http.tmpl
+++ b/pkg/codegen/templates/strict/strict-http.tmpl
@@ -1,6 +1,5 @@
-type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, args interface{}) (interface{}, error)
-
-type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+type StrictHandlerFunc = runtime.StrictHttpHandlerFunc
+type StrictMiddlewareFunc = runtime.StrictHttpMiddlewareFunc
type StrictHTTPServerOptions struct {
RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
@@ -35,8 +34,7 @@ type strictHandler struct {
var request {{$opid | ucFirst}}RequestObject
{{range .PathParams -}}
- {{$varName := .GoVariableName -}}
- request.{{$varName | ucFirst}} = {{$varName}}
+ request.{{.GoName}} = {{.GoVariableName}}
{{end -}}
{{if .RequiresParamObject -}}
diff --git a/pkg/codegen/templates/union-and-additional-properties.tmpl b/pkg/codegen/templates/union-and-additional-properties.tmpl
new file mode 100644
index 0000000000..79b4c67b2e
--- /dev/null
+++ b/pkg/codegen/templates/union-and-additional-properties.tmpl
@@ -0,0 +1,72 @@
+{{range .Types}}
+
+{{$addType := .Schema.AdditionalPropertiesType.TypeDecl}}
+{{$typeName := .TypeName -}}
+{{$discriminator := .Schema.Discriminator}}
+{{$properties := .Schema.Properties -}}
+
+// Override default JSON handling for {{.TypeName}} to handle AdditionalProperties and union
+func (a *{{.TypeName}}) UnmarshalJSON(b []byte) error {
+ err := a.union.UnmarshalJSON(b)
+ if err != nil {
+ return err
+ }
+ object := make(map[string]json.RawMessage)
+ err = json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
+{{range .Schema.Properties}}
+ if raw, found := object["{{.JsonFieldName}}"]; found {
+ err = json.Unmarshal(raw, &a.{{.GoFieldName}})
+ if err != nil {
+ return fmt.Errorf("error reading '{{.JsonFieldName}}': %w", err)
+ }
+ delete(object, "{{.JsonFieldName}}")
+ }
+{{end}}
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]{{$addType}})
+ for fieldName, fieldBuf := range object {
+ var fieldVal {{$addType}}
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
+}
+
+// Override default JSON handling for {{.TypeName}} to handle AdditionalProperties and union
+func (a {{.TypeName}}) MarshalJSON() ([]byte, error) {
+ var err error
+ b, err := a.union.MarshalJSON()
+ if err != nil {
+ return nil, err
+ }
+ object := make(map[string]json.RawMessage)
+ if a.union != nil {
+ err = json.Unmarshal(b, &object)
+ if err != nil {
+ return nil, err
+ }
+ }
+{{range .Schema.Properties}}
+{{if not .Required}}if a.{{.GoFieldName}} != nil { {{end}}
+ object["{{.JsonFieldName}}"], err = json.Marshal(a.{{.GoFieldName}})
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '{{.JsonFieldName}}': %w", err)
+ }
+{{if not .Required}} }{{end}}
+{{end}}
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
+}
+{{end}}
diff --git a/pkg/codegen/templates/union.tmpl b/pkg/codegen/templates/union.tmpl
index b758a82c64..8bb34a2562 100644
--- a/pkg/codegen/templates/union.tmpl
+++ b/pkg/codegen/templates/union.tmpl
@@ -53,7 +53,7 @@
return err
}
- merged, err := runtime.JsonMerge(b, t.union)
+ merged, err := runtime.JsonMerge(t.union, b)
t.union = merged
return err
}
@@ -86,6 +86,8 @@
{{end}}
{{end}}
+ {{if not .Schema.HasAdditionalProperties}}
+
func (t {{.TypeName}}) MarshalJSON() ([]byte, error) {
b, err := t.union.MarshalJSON()
{{if ne 0 (len .Schema.Properties) -}}
@@ -134,4 +136,5 @@
{{end -}}
return err
}
+ {{end}}
{{end}}
diff --git a/pkg/codegen/test_schema.json b/pkg/codegen/test_schema.json
new file mode 100644
index 0000000000..d64939498e
--- /dev/null
+++ b/pkg/codegen/test_schema.json
@@ -0,0 +1,15 @@
+{
+ "title": "node",
+ "type": "object",
+ "description": "Represents a node",
+ "properties": {
+ "id": {
+ "type": "string",
+ "format": "uri-reference"
+ },
+ "type": {
+ "type": "string",
+ "pattern": "^[A-Z][a-zA-Z0-9]*$"
+ }
+ }
+}
\ No newline at end of file
diff --git a/pkg/codegen/test_spec.yaml b/pkg/codegen/test_spec.yaml
index 62a987123a..b50f7491c5 100644
--- a/pkg/codegen/test_spec.yaml
+++ b/pkg/codegen/test_spec.yaml
@@ -87,6 +87,46 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Error'
+ /enum:
+ get:
+ tags:
+ - enum
+ summary: References enum
+ operationId: getEnum
+ responses:
+ 200:
+ description: Success
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/EnumTest'
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /user:
+ get:
+ tags:
+ - mergeAllOf
+ summary: Merges allOf ref-ing a JSON schema
+ operationId: getUser
+ responses:
+ 200:
+ description: Success
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
components:
schemas:
@@ -136,3 +176,32 @@ components:
cause:
type: string
enum: [ car, dog, oldage ]
+
+ EnumTest:
+ properties:
+ numerics:
+ type: integer
+ enum: [0, 1, 2]
+ enumNames:
+ type: integer
+ enum: [0, 1, 2]
+ x-enumNames:
+ - zero
+ - one
+ - two
+ enumVarnames:
+ type: integer
+ enum: [0, 1, 2]
+ x-enum-varnames:
+ - na
+ - single
+ - double
+ User:
+ allOf:
+ - $ref: ./test_schema.json
+ - type: object
+ additionalProperties: false
+ properties:
+ name:
+ type: string
+ description: User name
diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go
index 52274c0a67..cf8826e39f 100644
--- a/pkg/codegen/utils.go
+++ b/pkg/codegen/utils.go
@@ -14,10 +14,10 @@
package codegen
import (
- "encoding/json"
"fmt"
"go/token"
"net/url"
+ "reflect"
"regexp"
"sort"
"strconv"
@@ -161,6 +161,24 @@ func ToCamelCase(str string) string {
return n
}
+func ToCamelCaseWithInitialism(str string) string {
+ return replaceInitialism(ToCamelCase(str))
+}
+
+func replaceInitialism(s string) string {
+ // These strings do not apply CamelCase
+ // Do not do CamelCase when these characters match when the preceding character is lowercase
+ // ["Acl", "Api", "Ascii", "Cpu", "Css", "Dns", "Eof", "Guid", "Html", "Http", "Https", "Id", "Ip", "Json", "Qps", "Ram", "Rpc", "Sla", "Smtp", "Sql", "Ssh", "Tcp", "Tls", "Ttl", "Udp", "Ui", "Gid", "Uid", "Uuid", "Uri", "Url", "Utf8", "Vm", "Xml", "Xmpp", "Xsrf", "Xss", "Sip", "Rtp", "Amqp", "Db", "Ts"]
+ targetWordRegex := regexp.MustCompile(`(?i)(Acl|Api|Ascii|Cpu|Css|Dns|Eof|Guid|Html|Http|Https|Id|Ip|Json|Qps|Ram|Rpc|Sla|Smtp|Sql|Ssh|Tcp|Tls|Ttl|Udp|Ui|Gid|Uid|Uuid|Uri|Url|Utf8|Vm|Xml|Xmpp|Xsrf|Xss|Sip|Rtp|Amqp|Db|Ts)`)
+ return targetWordRegex.ReplaceAllStringFunc(s, func(s string) string {
+ // If the preceding character is lowercase, do not do CamelCase
+ if unicode.IsLower(rune(s[0])) {
+ return s
+ }
+ return strings.ToUpper(s)
+ })
+}
+
// SortedSchemaKeys returns the keys of the given SchemaRef dictionary in sorted
// order, since Golang scrambles dictionary keys
func SortedSchemaKeys(dict map[string]*openapi3.SchemaRef) []string {
@@ -291,6 +309,23 @@ func StringInArray(str string, array []string) bool {
return false
}
+// RefPathToObjName returns the name of referenced object without changes.
+//
+// #/components/schemas/Foo -> Foo
+// #/components/parameters/Bar -> Bar
+// #/components/responses/baz_baz -> baz_baz
+// document.json#/Foo -> Foo
+// http://deepmap.com/schemas/document.json#/objObj -> objObj
+//
+// Does not check refPath correctness.
+func RefPathToObjName(refPath string) string {
+ parts := strings.Split(refPath, "/")
+ if len(parts) > 0 {
+ return parts[len(parts)-1]
+ }
+ return ""
+}
+
// RefPathToGoType takes a $ref value and converts it to a Go typename.
// #/components/schemas/Foo -> Foo
// #/components/parameters/Bar -> Bar
@@ -334,7 +369,7 @@ func refPathToGoType(refPath string, local bool) (string, error) {
return "", fmt.Errorf("unsupported reference: %s", refPath)
}
remoteComponent, flatComponent := pathParts[0], pathParts[1]
- if goImport, ok := importMapping[remoteComponent]; !ok {
+ if goImport, ok := globalState.importMapping[remoteComponent]; !ok {
return "", fmt.Errorf("unrecognized external reference '%s'; please provide the known import for this reference using option --import-mapping", remoteComponent)
} else {
goType, err := refPathToGoType("#"+flatComponent, false)
@@ -486,7 +521,7 @@ func IsGoKeyword(str string) bool {
}
// IsPredeclaredGoIdentifier returns whether the given string
-// is a predefined go indentifier.
+// is a predefined go identifier.
//
// See https://golang.org/ref/spec#Predeclared_identifiers
func IsPredeclaredGoIdentifier(str string) bool {
@@ -554,13 +589,17 @@ func SanitizeGoIdentity(str string) string {
// SanitizeEnumNames fixes illegal chars in the enum names
// and removes duplicates
-func SanitizeEnumNames(enumNames []string) map[string]string {
- dupCheck := make(map[string]int, len(enumNames))
- deDup := make([]string, 0, len(enumNames))
-
- for _, n := range enumNames {
+func SanitizeEnumNames(enumNames, enumValues []string) map[string]string {
+ dupCheck := make(map[string]int, len(enumValues))
+ deDup := make([][]string, 0, len(enumValues))
+
+ for i, v := range enumValues {
+ n := v
+ if i < len(enumNames) {
+ n = enumNames[i]
+ }
if _, dup := dupCheck[n]; !dup {
- deDup = append(deDup, n)
+ deDup = append(deDup, []string{n, v})
}
dupCheck[n] = 0
}
@@ -568,13 +607,14 @@ func SanitizeEnumNames(enumNames []string) map[string]string {
dupCheck = make(map[string]int, len(deDup))
sanitizedDeDup := make(map[string]string, len(deDup))
- for _, n := range deDup {
+ for _, p := range deDup {
+ n, v := p[0], p[1]
sanitized := SanitizeGoIdentity(SchemaNameToTypeName(n))
if _, dup := dupCheck[sanitized]; !dup {
- sanitizedDeDup[sanitized] = n
+ sanitizedDeDup[sanitized] = v
} else {
- sanitizedDeDup[sanitized+strconv.Itoa(dupCheck[sanitized])] = n
+ sanitizedDeDup[sanitized+strconv.Itoa(dupCheck[sanitized])] = v
}
dupCheck[sanitized]++
}
@@ -641,11 +681,11 @@ func SchemaNameToTypeName(name string) string {
// you must specify an additionalProperties type
// If additionalProperties it true/false, this field will be non-nil.
func SchemaHasAdditionalProperties(schema *openapi3.Schema) bool {
- if schema.AdditionalPropertiesAllowed != nil && *schema.AdditionalPropertiesAllowed {
+ if schema.AdditionalProperties.Has != nil && *schema.AdditionalProperties.Has {
return true
}
- if schema.AdditionalProperties != nil {
+ if schema.AdditionalProperties.Schema != nil {
return true
}
return false
@@ -673,14 +713,23 @@ func StringWithTypeNameToGoComment(in, typeName string) string {
return stringToGoCommentWithPrefix(in, typeName)
}
+func DeprecationComment(reason string) string {
+ var content = "Deprecated:" // The colon is required at the end even without reason
+ if reason != "" {
+ content += fmt.Sprintf(" %s", reason)
+ }
+
+ return stringToGoCommentWithPrefix(content, "")
+}
+
func stringToGoCommentWithPrefix(in, prefix string) string {
if len(in) == 0 || len(strings.TrimSpace(in)) == 0 { // ignore empty comment
return ""
}
// Normalize newlines from Windows/Mac to Linux
- in = strings.Replace(in, "\r\n", "\n", -1)
- in = strings.Replace(in, "\r", "\n", -1)
+ in = strings.ReplaceAll(in, "\r\n", "\n")
+ in = strings.ReplaceAll(in, "\r", "\n")
// Add comment to each line
var lines []string
@@ -835,15 +884,30 @@ func ParseGoImportExtension(v *openapi3.SchemaRef) (*goImport, error) {
goTypeImportExt := v.Value.Extensions[extPropGoImport]
- if raw, ok := goTypeImportExt.(json.RawMessage); ok {
- gi := goImport{}
- if err := json.Unmarshal(raw, &gi); err != nil {
- return nil, err
+ importI, ok := goTypeImportExt.(map[string]interface{})
+ if !ok {
+ return nil, fmt.Errorf("failed to convert type: %T", goTypeImportExt)
+ }
+
+ gi := goImport{}
+ // replicate the case-insensitive field mapping json.Unmarshal would do
+ for k, v := range importI {
+ if strings.EqualFold(k, "name") {
+ if vs, ok := v.(string); ok {
+ gi.Name = vs
+ } else {
+ return nil, fmt.Errorf("failed to convert type: %T", v)
+ }
+ } else if strings.EqualFold(k, "path") {
+ if vs, ok := v.(string); ok {
+ gi.Path = vs
+ } else {
+ return nil, fmt.Errorf("failed to convert type: %T", v)
+ }
}
- return &gi, nil
}
- return nil, nil
+ return &gi, nil
}
func MergeImports(dst, src map[string]goImport) {
@@ -859,5 +923,5 @@ func TypeDefinitionsEquivalent(t1, t2 TypeDefinition) bool {
if t1.TypeName != t2.TypeName {
return false
}
- return t1.Schema.OAPISchema == t2.Schema.OAPISchema
+ return reflect.DeepEqual(t1.Schema.OAPISchema, t2.Schema.OAPISchema)
}
diff --git a/pkg/codegen/utils_test.go b/pkg/codegen/utils_test.go
index 518e287f5e..67765264cc 100644
--- a/pkg/codegen/utils_test.go
+++ b/pkg/codegen/utils_test.go
@@ -134,12 +134,12 @@ func TestSortedRequestBodyKeys(t *testing.T) {
}
func TestRefPathToGoType(t *testing.T) {
- old := importMapping
- importMapping = constructImportMapping(map[string]string{
+ old := globalState.importMapping
+ globalState.importMapping = constructImportMapping(map[string]string{
"doc.json": "externalref0",
"http://deepmap.com/doc.json": "externalref1",
})
- defer func() { importMapping = old }()
+ defer func() { globalState.importMapping = old }()
tests := []struct {
name string
@@ -280,6 +280,23 @@ func TestSwaggerUriToGorillaUri(t *testing.T) { // TODO
assert.Equal(t, "/path/{arg}/foo", SwaggerUriToGorillaUri("/path/{?arg*}/foo"))
}
+func TestSwaggerUriToFiberUri(t *testing.T) {
+ assert.Equal(t, "/path", SwaggerUriToFiberUri("/path"))
+ assert.Equal(t, "/path/:arg", SwaggerUriToFiberUri("/path/{arg}"))
+ assert.Equal(t, "/path/:arg1/:arg2", SwaggerUriToFiberUri("/path/{arg1}/{arg2}"))
+ assert.Equal(t, "/path/:arg1/:arg2/foo", SwaggerUriToFiberUri("/path/{arg1}/{arg2}/foo"))
+
+ // Make sure all the exploded and alternate formats match too
+ assert.Equal(t, "/path/:arg/foo", SwaggerUriToFiberUri("/path/{arg}/foo"))
+ assert.Equal(t, "/path/:arg/foo", SwaggerUriToFiberUri("/path/{arg*}/foo"))
+ assert.Equal(t, "/path/:arg/foo", SwaggerUriToFiberUri("/path/{.arg}/foo"))
+ assert.Equal(t, "/path/:arg/foo", SwaggerUriToFiberUri("/path/{.arg*}/foo"))
+ assert.Equal(t, "/path/:arg/foo", SwaggerUriToFiberUri("/path/{;arg}/foo"))
+ assert.Equal(t, "/path/:arg/foo", SwaggerUriToFiberUri("/path/{;arg*}/foo"))
+ assert.Equal(t, "/path/:arg/foo", SwaggerUriToFiberUri("/path/{?arg}/foo"))
+ assert.Equal(t, "/path/:arg/foo", SwaggerUriToFiberUri("/path/{?arg*}/foo"))
+}
+
func TestOrderedParamsFromUri(t *testing.T) {
result := OrderedParamsFromUri("/path/{param1}/{.param2}/{;param3*}/foo")
assert.EqualValues(t, []string{"param1", "param2", "param3"}, result)
@@ -432,3 +449,71 @@ func TestSchemaNameToTypeName(t *testing.T) {
assert.Equal(t, want, SchemaNameToTypeName(in))
}
}
+
+
+func TestTypeDefinitionsEquivalent(t *testing.T) {
+ def1 := TypeDefinition{TypeName: "name", Schema: Schema{
+ OAPISchema: &openapi3.Schema{},
+ }}
+ def2 := TypeDefinition{TypeName: "name", Schema: Schema{
+ OAPISchema: &openapi3.Schema{},
+ }}
+ assert.True(t, TypeDefinitionsEquivalent(def1, def2))
+}
+
+
+func TestRefPathToObjName(t *testing.T) {
+ t.Parallel()
+
+ for in, want := range map[string]string{
+ "#/components/schemas/Foo": "Foo",
+ "#/components/parameters/Bar": "Bar",
+ "#/components/responses/baz_baz": "baz_baz",
+ "document.json#/Foo": "Foo",
+ "http://deepmap.com/schemas/document.json#/objObj": "objObj",
+ } {
+ assert.Equal(t, want, RefPathToObjName(in))
+ }
+}
+
+func Test_replaceInitialisms(t *testing.T) {
+ type args struct {
+ s string
+ }
+ tests := []struct {
+ name string
+ args args
+ want string
+ }{
+ {
+ name: "empty string",
+ args: args{s: ""},
+ want: "",
+ },
+ {
+ name: "no initialism",
+ args: args{s: "foo"},
+ want: "foo",
+ },
+ {
+ name: "one initialism",
+ args: args{s: "fooId"},
+ want: "fooID",
+ },
+ {
+ name: "two initialism",
+ args: args{s: "fooIdBarApi"},
+ want: "fooIDBarAPI",
+ },
+ {
+ name: "already initialism",
+ args: args{s: "fooIDBarAPI"},
+ want: "fooIDBarAPI",
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ assert.Equalf(t, tt.want, replaceInitialism(tt.args.s), "replaceInitialism(%v)", tt.args.s)
+ })
+ }
+}
diff --git a/pkg/fiber-middleware/oapi_validate.go b/pkg/fiber-middleware/oapi_validate.go
new file mode 100644
index 0000000000..ef30dd8f75
--- /dev/null
+++ b/pkg/fiber-middleware/oapi_validate.go
@@ -0,0 +1,196 @@
+// Package middleware implements middleware function for server implementations,
+// which validates incoming HTTP requests to make sure that they conform to the given OAPI 3.0 specification.
+// When OAPI validation fails on the request, we return an HTTP/400.
+package middleware
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net/http"
+ "os"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/getkin/kin-openapi/openapi3filter"
+ "github.com/getkin/kin-openapi/routers"
+ "github.com/getkin/kin-openapi/routers/gorillamux"
+ "github.com/gofiber/fiber/v2"
+ "github.com/gofiber/fiber/v2/middleware/adaptor"
+)
+
+type ctxKeyFiberContext struct{}
+type ctxKeyUserData struct{}
+
+// OapiValidatorFromYamlFile creates a validator middleware from a YAML file path
+func OapiValidatorFromYamlFile(path string) (fiber.Handler, error) {
+
+ data, err := os.ReadFile(path)
+ if err != nil {
+ return nil, fmt.Errorf("error reading %s: %s", path, err)
+ }
+
+ swagger, err := openapi3.NewLoader().LoadFromData(data)
+ if err != nil {
+ return nil, fmt.Errorf("error parsing %s as Swagger YAML: %s",
+ path, err)
+ }
+
+ return OapiRequestValidator(swagger), nil
+}
+
+// OapiRequestValidator is a fiber middleware function which validates incoming HTTP requests
+// to make sure that they conform to the given OAPI 3.0 specification. When
+// OAPI validation fails on the request, we return an HTTP/400 with error message
+func OapiRequestValidator(swagger *openapi3.T) fiber.Handler {
+ return OapiRequestValidatorWithOptions(swagger, nil)
+}
+
+// ErrorHandler is called when there is an error in validation
+type ErrorHandler func(c *fiber.Ctx, message string, statusCode int)
+
+// MultiErrorHandler is called when oapi returns a MultiError type
+type MultiErrorHandler func(openapi3.MultiError) error
+
+// Options to customize request validation. These are passed through to
+// openapi3filter.
+type Options struct {
+ Options openapi3filter.Options
+ ErrorHandler ErrorHandler
+ ParamDecoder openapi3filter.ContentParameterDecoder
+ UserData interface{}
+ MultiErrorHandler MultiErrorHandler
+}
+
+// OapiRequestValidatorWithOptions creates a validator from a swagger object, with validation options
+func OapiRequestValidatorWithOptions(swagger *openapi3.T, options *Options) fiber.Handler {
+
+ router, err := gorillamux.NewRouter(swagger)
+ if err != nil {
+ panic(err)
+ }
+
+ return func(c *fiber.Ctx) error {
+
+ err := ValidateRequestFromContext(c, router, options)
+ if err != nil {
+ if options != nil && options.ErrorHandler != nil {
+ options.ErrorHandler(c, err.Error(), http.StatusBadRequest)
+ // in case the handler didn't internally call Abort, stop the chain
+ return nil
+ } else {
+ // note: I am not sure if this is the best way to handle this
+ return fiber.NewError(http.StatusBadRequest, err.Error())
+ }
+ }
+ return c.Next()
+ }
+}
+
+// ValidateRequestFromContext is called from the middleware above and actually does the work
+// of validating a request.
+func ValidateRequestFromContext(c *fiber.Ctx, router routers.Router, options *Options) error {
+
+ r, err := adaptor.ConvertRequest(c, false)
+ if err != nil {
+ return err
+ }
+
+ route, pathParams, err := router.FindRoute(r)
+
+ // We failed to find a matching route for the request.
+ if err != nil {
+ switch e := err.(type) {
+ case *routers.RouteError:
+ // We've got a bad request, the path requested doesn't match
+ // either server, or path, or something.
+ return errors.New(e.Reason)
+ default:
+ // This should never happen today, but if our upstream code changes,
+ // we don't want to crash the server, so handle the unexpected error.
+ return fmt.Errorf("error validating route: %s", err.Error())
+ }
+ }
+
+ // Validate request
+ requestValidationInput := &openapi3filter.RequestValidationInput{
+ Request: r,
+ PathParams: pathParams,
+ Route: route,
+ }
+
+ // Pass the fiber context into the request validator, so that any callbacks
+ // which it invokes make it available.
+ requestContext := context.WithValue(context.Background(), ctxKeyFiberContext{}, c) //nolint:staticcheck
+
+ if options != nil {
+ requestValidationInput.Options = &options.Options
+ requestValidationInput.ParamDecoder = options.ParamDecoder
+ requestContext = context.WithValue(requestContext, ctxKeyUserData{}, options.UserData) //nolint:staticcheck
+ }
+
+ err = openapi3filter.ValidateRequest(requestContext, requestValidationInput)
+ if err != nil {
+ me := openapi3.MultiError{}
+ if errors.As(err, &me) {
+ errFunc := getMultiErrorHandlerFromOptions(options)
+ return errFunc(me)
+ }
+
+ switch e := err.(type) {
+ case *openapi3filter.RequestError:
+ // We've got a bad request
+ // Split up the verbose error by lines and return the first one
+ // openapi errors seem to be multi-line with a decent message on the first
+ errorLines := strings.Split(e.Error(), "\n")
+ return fmt.Errorf("error in openapi3filter.RequestError: %s", errorLines[0])
+ case *openapi3filter.SecurityRequirementsError:
+ return fmt.Errorf("error in openapi3filter.SecurityRequirementsError: %s", e.Error())
+ default:
+ // This should never happen today, but if our upstream code changes,
+ // we don't want to crash the server, so handle the unexpected error.
+ return fmt.Errorf("error validating request: %s", err)
+ }
+ }
+ return nil
+}
+
+// GetFiberContext gets the fiber context from within requests. It returns
+// nil if not found or wrong type.
+func GetFiberContext(c context.Context) *fiber.Ctx {
+ iface := c.Value(ctxKeyFiberContext{})
+ if iface == nil {
+ return nil
+ }
+
+ fiberCtx, ok := iface.(*fiber.Ctx)
+ if ok {
+ return fiberCtx
+ }
+ return nil
+}
+
+func GetUserData(c context.Context) interface{} {
+ return c.Value(ctxKeyUserData{})
+}
+
+// getMultiErrorHandlerFromOptions attempts to get the MultiErrorHandler from the options. If it is not set,
+// return a default handler
+func getMultiErrorHandlerFromOptions(options *Options) MultiErrorHandler {
+ if options == nil {
+ return defaultMultiErrorHandler
+ }
+
+ if options.MultiErrorHandler == nil {
+ return defaultMultiErrorHandler
+ }
+
+ return options.MultiErrorHandler
+}
+
+// defaultMultiErrorHandler returns a StatusBadRequest (400) and a list
+// of all the errors. This method is called if there are no other
+// methods defined on the options.
+func defaultMultiErrorHandler(me openapi3.MultiError) error {
+ return fmt.Errorf("multiple errors encountered: %s", me)
+}
diff --git a/pkg/fiber-middleware/oapi_validate_test.go b/pkg/fiber-middleware/oapi_validate_test.go
new file mode 100644
index 0000000000..9201e13fb8
--- /dev/null
+++ b/pkg/fiber-middleware/oapi_validate_test.go
@@ -0,0 +1,434 @@
+package middleware
+
+import (
+ "bytes"
+ "context"
+ _ "embed"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "net/http/httptest"
+ "net/url"
+ "testing"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/getkin/kin-openapi/openapi3filter"
+ "github.com/gofiber/fiber/v2"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+//go:embed test_spec.yaml
+var testSchema []byte
+
+func doGet(t *testing.T, app *fiber.App, rawURL string) *http.Response {
+ t.Helper()
+
+ u, err := url.Parse(rawURL)
+ if err != nil {
+ t.Fatalf("invalid URL %q: %v", rawURL, err)
+ }
+
+ req := httptest.NewRequest("GET", u.RequestURI(), nil)
+ req.Header.Add("Accept", "application/json")
+ req.Host = u.Host
+
+ r, err := app.Test(req)
+ if err != nil {
+ t.Fatalf("Failed to test request, URL=%q: %v", rawURL, err)
+ }
+
+ return r
+}
+
+func doPost(t *testing.T, app *fiber.App, rawURL string, jsonBody interface{}) *http.Response {
+ t.Helper()
+
+ u, err := url.Parse(rawURL)
+ if err != nil {
+ t.Fatalf("invalid url %q: %v", rawURL, err)
+ }
+
+ buf, err := json.Marshal(jsonBody)
+ if err != nil {
+ t.Fatalf("failed to marshal: %v", err)
+ }
+
+ req := httptest.NewRequest("POST", u.RequestURI(), bytes.NewReader(buf))
+ req.Header.Add("Accept", "application/json")
+ req.Header.Add("Content-Type", "application/json")
+ req.Host = u.Host
+
+ r, err := app.Test(req)
+ if err != nil {
+ t.Fatalf("Failed to test request, URL=%q: %v", rawURL, err)
+ }
+
+ return r
+}
+
+func TestOapiRequestValidator(t *testing.T) {
+
+ swagger, err := openapi3.NewLoader().LoadFromData(testSchema)
+ require.NoError(t, err, "Error initializing swagger")
+
+ // Create a new fiber router
+ app := fiber.New()
+
+ // Set up an authenticator to check authenticated function. It will allow
+ // access to "someScope", but disallow others.
+ options := Options{
+ ErrorHandler: func(c *fiber.Ctx, message string, statusCode int) {
+ _ = c.Status(statusCode).SendString("test: " + message)
+ },
+ Options: openapi3filter.Options{
+ AuthenticationFunc: func(c context.Context, input *openapi3filter.AuthenticationInput) error {
+ // The fiber context should be propagated into here.
+ gCtx := GetFiberContext(c)
+ assert.NotNil(t, gCtx)
+ // As should user data
+ assert.EqualValues(t, "hi!", GetUserData(c))
+
+ for _, s := range input.Scopes {
+ if s == "someScope" {
+ return nil
+ }
+ if s == "unauthorized" {
+ return errors.New("unauthorized")
+ }
+ }
+ return errors.New("forbidden")
+ },
+ },
+ UserData: "hi!",
+ }
+
+ // Install our OpenApi based request validator
+ app.Use(OapiRequestValidatorWithOptions(swagger, &options))
+
+ called := false
+
+ // Install a request handler for /resource. We want to make sure it doesn't
+ // get called.
+ app.Get("/resource", func(c *fiber.Ctx) error {
+ called = true
+ return nil
+ })
+ // Let's send the request to the wrong server, this should fail validation
+ {
+ res := doGet(t, app, "https://not.deepmap.ai/resource")
+ assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+ assert.False(t, called, "Handler should not have been called")
+ }
+
+ // Let's send a good request, it should pass
+ {
+ res := doGet(t, app, "https://deepmap.ai/resource")
+ assert.Equal(t, http.StatusOK, res.StatusCode)
+ assert.True(t, called, "Handler should have been called")
+ called = false
+ }
+
+ // Send an out-of-spec parameter
+ {
+ res := doGet(t, app, "https://deepmap.ai/resource?id=500")
+ assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+ assert.False(t, called, "Handler should not have been called")
+ called = false
+ }
+
+ // Send a bad parameter type
+ {
+ res := doGet(t, app, "https://deepmap.ai/resource?id=foo")
+ assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+ assert.False(t, called, "Handler should not have been called")
+ called = false
+ }
+
+ // Add a handler for the POST message
+ app.Post("/resource", func(c *fiber.Ctx) error {
+ called = true
+ return c.SendStatus(http.StatusNoContent)
+ })
+
+ called = false
+ // Send a good request body
+ {
+ body := struct {
+ Name string `json:"name"`
+ }{
+ Name: "Marcin",
+ }
+ res := doPost(t, app, "https://deepmap.ai/resource", body)
+ assert.Equal(t, http.StatusNoContent, res.StatusCode)
+ assert.True(t, called, "Handler should have been called")
+ called = false
+ }
+
+ // Send a malformed body
+ {
+ body := struct {
+ Name int `json:"name"`
+ }{
+ Name: 7,
+ }
+ res := doPost(t, app, "https://deepmap.ai/resource", body)
+ assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+ assert.False(t, called, "Handler should not have been called")
+ called = false
+ }
+
+ app.Get("/protected_resource", func(c *fiber.Ctx) error {
+ called = true
+ return c.SendStatus(http.StatusNoContent)
+ })
+
+ // Call a protected function to which we have access
+ {
+ res := doGet(t, app, "https://deepmap.ai/protected_resource")
+ assert.Equal(t, http.StatusNoContent, res.StatusCode)
+ assert.True(t, called, "Handler should have been called")
+ called = false
+ }
+
+ app.Get("/protected_resource2", func(c *fiber.Ctx) error {
+ called = true
+ return c.SendStatus(http.StatusNoContent)
+ })
+ // Call a protected function to which we don't have access
+ {
+ res := doGet(t, app, "https://deepmap.ai/protected_resource2")
+ assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+ assert.False(t, called, "Handler should not have been called")
+ called = false
+ }
+
+ app.Get("/protected_resource_401", func(c *fiber.Ctx) error {
+ called = true
+ return c.SendStatus(http.StatusNoContent)
+ })
+ // Call a protected function without credentials
+ {
+ res := doGet(t, app, "https://deepmap.ai/protected_resource_401")
+ assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+ body, err := io.ReadAll(res.Body)
+ if assert.NoError(t, err) {
+ assert.Equal(t, "test: error in openapi3filter.SecurityRequirementsError: security requirements failed: unauthorized", string(body))
+ }
+ assert.False(t, called, "Handler should not have been called")
+ called = false
+ }
+}
+
+func TestOapiRequestValidatorWithOptionsMultiError(t *testing.T) {
+ swagger, err := openapi3.NewLoader().LoadFromData(testSchema)
+ require.NoError(t, err, "Error initializing swagger")
+
+ app := fiber.New()
+
+ // Set up an authenticator to check authenticated function. It will allow
+ // access to "someScope", but disallow others.
+ options := Options{
+ Options: openapi3filter.Options{
+ ExcludeRequestBody: false,
+ ExcludeResponseBody: false,
+ IncludeResponseStatus: true,
+ MultiError: true,
+ },
+ }
+
+ // register middleware
+ app.Use(OapiRequestValidatorWithOptions(swagger, &options))
+
+ called := false
+
+ // Install a request handler for /resource. We want to make sure it doesn't
+ // get called.
+ app.Get("/multiparamresource", func(c *fiber.Ctx) error {
+ called = true
+ return nil
+ })
+
+ // Let's send a good request, it should pass
+ {
+ res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=50&id2=50")
+ assert.Equal(t, http.StatusOK, res.StatusCode)
+ assert.True(t, called, "Handler should have been called")
+ called = false
+ }
+
+ // Let's send a request with a missing parameter, it should return
+ // a bad status
+ {
+ res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=50")
+ assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+ body, err := io.ReadAll(res.Body)
+ if assert.NoError(t, err) {
+ assert.Contains(t, string(body), "multiple errors encountered")
+ assert.Contains(t, string(body), "parameter \"id2\"")
+ assert.Contains(t, string(body), "value is required but missing")
+ }
+ assert.False(t, called, "Handler should not have been called")
+ called = false
+ }
+
+ // Let's send a request with a 2 missing parameters, it should return
+ // a bad status
+ {
+ res := doGet(t, app, "https://deepmap.ai/multiparamresource")
+ assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+ body, err := io.ReadAll(res.Body)
+ if assert.NoError(t, err) {
+ assert.Contains(t, string(body), "multiple errors encountered")
+ assert.Contains(t, string(body), "parameter \"id\"")
+ assert.Contains(t, string(body), "value is required but missing")
+ assert.Contains(t, string(body), "parameter \"id2\"")
+ assert.Contains(t, string(body), "value is required but missing")
+ }
+ assert.False(t, called, "Handler should not have been called")
+ called = false
+ }
+
+ // Let's send a request with a 1 missing parameter, and another outside
+ // or the parameters. It should return a bad status
+ {
+ res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=500")
+ assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+ body, err := io.ReadAll(res.Body)
+ if assert.NoError(t, err) {
+ assert.Contains(t, string(body), "multiple errors encountered")
+ assert.Contains(t, string(body), "parameter \"id\"")
+ assert.Contains(t, string(body), "number must be at most 100")
+ assert.Contains(t, string(body), "parameter \"id2\"")
+ assert.Contains(t, string(body), "value is required but missing")
+ }
+ assert.False(t, called, "Handler should not have been called")
+ called = false
+ }
+
+ // Let's send a request with a parameters that do not meet spec. It should
+ // return a bad status
+ {
+ res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=abc&id2=1")
+ assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+ body, err := io.ReadAll(res.Body)
+ if assert.NoError(t, err) {
+ assert.Contains(t, string(body), "multiple errors encountered")
+ assert.Contains(t, string(body), "parameter \"id\"")
+ assert.Contains(t, string(body), "value abc: an invalid integer: invalid syntax")
+ assert.Contains(t, string(body), "parameter \"id2\"")
+ assert.Contains(t, string(body), "number must be at least 10")
+ }
+ assert.False(t, called, "Handler should not have been called")
+ called = false
+ }
+}
+
+func TestOapiRequestValidatorWithOptionsMultiErrorAndCustomHandler(t *testing.T) {
+ swagger, err := openapi3.NewLoader().LoadFromData(testSchema)
+ require.NoError(t, err, "Error initializing swagger")
+
+ app := fiber.New()
+
+ // Set up an authenticator to check authenticated function. It will allow
+ // access to "someScope", but disallow others.
+ options := Options{
+ Options: openapi3filter.Options{
+ ExcludeRequestBody: false,
+ ExcludeResponseBody: false,
+ IncludeResponseStatus: true,
+ MultiError: true,
+ },
+ MultiErrorHandler: func(me openapi3.MultiError) error {
+ return fmt.Errorf("Bad stuff - %s", me.Error())
+ },
+ }
+
+ // register middleware
+ app.Use(OapiRequestValidatorWithOptions(swagger, &options))
+
+ called := false
+
+ // Install a request handler for /resource. We want to make sure it doesn't
+ // get called.
+ app.Get("/multiparamresource", func(c *fiber.Ctx) error {
+ called = true
+ return nil
+ })
+
+ // Let's send a good request, it should pass
+ {
+ res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=50&id2=50")
+ assert.Equal(t, http.StatusOK, res.StatusCode)
+ assert.True(t, called, "Handler should have been called")
+ called = false
+ }
+
+ // Let's send a request with a missing parameter, it should return
+ // a bad status
+ {
+ res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=50")
+ assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+ body, err := io.ReadAll(res.Body)
+ if assert.NoError(t, err) {
+ assert.Contains(t, string(body), "Bad stuff")
+ assert.Contains(t, string(body), "parameter \"id2\"")
+ assert.Contains(t, string(body), "value is required but missing")
+ }
+ assert.False(t, called, "Handler should not have been called")
+ called = false
+ }
+
+ // Let's send a request with a 2 missing parameters, it should return
+ // a bad status
+ {
+ res := doGet(t, app, "https://deepmap.ai/multiparamresource")
+ assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+ body, err := io.ReadAll(res.Body)
+ if assert.NoError(t, err) {
+ assert.Contains(t, string(body), "Bad stuff")
+ assert.Contains(t, string(body), "parameter \"id\"")
+ assert.Contains(t, string(body), "value is required but missing")
+ assert.Contains(t, string(body), "parameter \"id2\"")
+ assert.Contains(t, string(body), "value is required but missing")
+ }
+ assert.False(t, called, "Handler should not have been called")
+ called = false
+ }
+
+ // Let's send a request with a 1 missing parameter, and another outside
+ // or the parameters. It should return a bad status
+ {
+ res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=500")
+ assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+ body, err := io.ReadAll(res.Body)
+ if assert.NoError(t, err) {
+ assert.Contains(t, string(body), "Bad stuff")
+ assert.Contains(t, string(body), "parameter \"id\"")
+ assert.Contains(t, string(body), "number must be at most 100")
+ assert.Contains(t, string(body), "parameter \"id2\"")
+ assert.Contains(t, string(body), "value is required but missing")
+ }
+ assert.False(t, called, "Handler should not have been called")
+ called = false
+ }
+
+ // Let's send a request with a parameters that do not meet spec. It should
+ // return a bad status
+ {
+ res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=abc&id2=1")
+ assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+ body, err := io.ReadAll(res.Body)
+ if assert.NoError(t, err) {
+ assert.Contains(t, string(body), "Bad stuff")
+ assert.Contains(t, string(body), "parameter \"id\"")
+ assert.Contains(t, string(body), "value abc: an invalid integer: invalid syntax")
+ assert.Contains(t, string(body), "parameter \"id2\"")
+ assert.Contains(t, string(body), "number must be at least 10")
+ }
+ assert.False(t, called, "Handler should not have been called")
+ called = false
+ }
+}
diff --git a/pkg/fiber-middleware/test_spec.yaml b/pkg/fiber-middleware/test_spec.yaml
new file mode 100644
index 0000000000..6e0a2415d2
--- /dev/null
+++ b/pkg/fiber-middleware/test_spec.yaml
@@ -0,0 +1,103 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: TestServer
+servers:
+ - url: http://deepmap.ai/
+paths:
+ /resource:
+ get:
+ operationId: getResource
+ parameters:
+ - name: id
+ in: query
+ schema:
+ type: integer
+ minimum: 10
+ maximum: 100
+ responses:
+ '200':
+ description: success
+ content:
+ application/json:
+ schema:
+ properties:
+ name:
+ type: string
+ id:
+ type: integer
+ post:
+ operationId: createResource
+ responses:
+ '204':
+ description: No content
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ properties:
+ name:
+ type: string
+ /protected_resource:
+ get:
+ operationId: getProtectedResource
+ security:
+ - BearerAuth:
+ - someScope
+ responses:
+ '204':
+ description: no content
+ /protected_resource2:
+ get:
+ operationId: getProtectedResource
+ security:
+ - BearerAuth:
+ - otherScope
+ responses:
+ '204':
+ description: no content
+ /protected_resource_401:
+ get:
+ operationId: getProtectedResource
+ security:
+ - BearerAuth:
+ - unauthorized
+ responses:
+ '401':
+ description: no content
+ /multiparamresource:
+ get:
+ operationId: getResource
+ parameters:
+ - name: id
+ in: query
+ required: true
+ schema:
+ type: integer
+ minimum: 10
+ maximum: 100
+ - name: id2
+ required: true
+ in: query
+ schema:
+ type: integer
+ minimum: 10
+ maximum: 100
+ responses:
+ '200':
+ description: success
+ content:
+ application/json:
+ schema:
+ properties:
+ name:
+ type: string
+ id:
+ type: integer
+components:
+ securitySchemes:
+ BearerAuth:
+ type: http
+ scheme: bearer
+ bearerFormat: JWT
diff --git a/pkg/gin-middleware/oapi_validate.go b/pkg/gin-middleware/oapi_validate.go
index 82c1f52cb6..3406134a68 100644
--- a/pkg/gin-middleware/oapi_validate.go
+++ b/pkg/gin-middleware/oapi_validate.go
@@ -18,6 +18,7 @@ import (
"context"
"errors"
"fmt"
+ "log"
"net/http"
"os"
"strings"
@@ -70,10 +71,16 @@ type Options struct {
ParamDecoder openapi3filter.ContentParameterDecoder
UserData interface{}
MultiErrorHandler MultiErrorHandler
+ // SilenceServersWarning allows silencing a warning for https://github.com/deepmap/oapi-codegen/issues/882 that reports when an OpenAPI spec has `spec.Servers != nil`
+ SilenceServersWarning bool
}
// OapiRequestValidatorWithOptions creates a validator from a swagger object, with validation options
func OapiRequestValidatorWithOptions(swagger *openapi3.T, options *Options) gin.HandlerFunc {
+ if swagger.Servers != nil && (options == nil || options.SilenceServersWarning) {
+ log.Println("WARN: OapiRequestValidatorWithOptions called with an OpenAPI spec that has `Servers` set. This may lead to an HTTP 400 with `no matching operation was found` when sending a valid request, as the validator performs `Host` header validation. If you're expecting `Host` header validation, you can silence this warning by setting `Options.SilenceServersWarning = true`. See https://github.com/deepmap/oapi-codegen/issues/882 for more information.")
+ }
+
router, err := gorillamux.NewRouter(swagger)
if err != nil {
panic(err)
diff --git a/pkg/middleware/oapi_validate.go b/pkg/middleware/oapi_validate.go
index a665b3dfcb..0318d29610 100644
--- a/pkg/middleware/oapi_validate.go
+++ b/pkg/middleware/oapi_validate.go
@@ -18,6 +18,7 @@ import (
"context"
"errors"
"fmt"
+ "log"
"net/http"
"os"
"strings"
@@ -73,10 +74,16 @@ type Options struct {
UserData interface{}
Skipper echomiddleware.Skipper
MultiErrorHandler MultiErrorHandler
+ // SilenceServersWarning allows silencing a warning for https://github.com/deepmap/oapi-codegen/issues/882 that reports when an OpenAPI spec has `spec.Servers != nil`
+ SilenceServersWarning bool
}
// OapiRequestValidatorWithOptions creates a validator from a swagger object, with validation options
func OapiRequestValidatorWithOptions(swagger *openapi3.T, options *Options) echo.MiddlewareFunc {
+ if swagger.Servers != nil && (options == nil || options.SilenceServersWarning) {
+ log.Println("WARN: OapiRequestValidatorWithOptions called with an OpenAPI spec that has `Servers` set. This may lead to an HTTP 400 with `no matching operation was found` when sending a valid request, as the validator performs `Host` header validation. If you're expecting `Host` header validation, you can silence this warning by setting `Options.SilenceServersWarning = true`. See https://github.com/deepmap/oapi-codegen/issues/882 for more information.")
+ }
+
router, err := gorillamux.NewRouter(swagger)
if err != nil {
panic(err)
diff --git a/pkg/runtime/bindstring.go b/pkg/runtime/bindstring.go
index 72f74dd1bf..efc98670fc 100644
--- a/pkg/runtime/bindstring.go
+++ b/pkg/runtime/bindstring.go
@@ -42,7 +42,7 @@ func BindStringToObject(src string, dst interface{}) error {
t = v.Type()
}
- // For some optioinal args
+ // For some optional args
if t.Kind() == reflect.Ptr {
if v.IsNil() {
v.Set(reflect.New(t.Elem()))
diff --git a/pkg/runtime/deepobject.go b/pkg/runtime/deepobject.go
index f18ace374e..35286b303c 100644
--- a/pkg/runtime/deepobject.go
+++ b/pkg/runtime/deepobject.go
@@ -200,6 +200,19 @@ func assignPathValues(dst interface{}, pathValues fieldOrValue) error {
it := iv.Type()
switch it.Kind() {
+ case reflect.Map:
+ dstMap := reflect.MakeMap(iv.Type())
+ for key, value := range pathValues.fields {
+ dstKey := reflect.ValueOf(key)
+ dstVal := reflect.New(iv.Type().Elem())
+ err := assignPathValues(dstVal.Interface(), value)
+ if err != nil {
+ return fmt.Errorf("error binding map: %w", err)
+ }
+ dstMap.SetMapIndex(dstKey, dstVal.Elem())
+ }
+ iv.Set(dstMap)
+ return nil
case reflect.Slice:
sliceLength := len(pathValues.fields)
dstSlice := reflect.MakeSlice(it, sliceLength, sliceLength)
@@ -245,7 +258,7 @@ func assignPathValues(dst interface{}, pathValues fieldOrValue) error {
// TODO: why is this marked as an ineffassign?
tm, err = time.Parse(types.DateFormat, pathValues.value) //nolint:ineffassign,staticcheck
if err != nil {
- return fmt.Errorf("error parsing tim as RFC3339 or 2006-01-02 time: %s", err)
+ return fmt.Errorf("error parsing '%s' as RFC3339 or 2006-01-02 time: %s", pathValues.value, err)
}
return fmt.Errorf("invalid date format: %w", err)
}
diff --git a/pkg/runtime/deepobject_test.go b/pkg/runtime/deepobject_test.go
index d1a5a16377..237673ad31 100644
--- a/pkg/runtime/deepobject_test.go
+++ b/pkg/runtime/deepobject_test.go
@@ -17,18 +17,20 @@ type InnerObject struct {
// These are all possible field types, mandatory and optional.
type AllFields struct {
- I int `json:"i"`
- Oi *int `json:"oi,omitempty"`
- F float32 `json:"f"`
- Of *float32 `json:"of,omitempty"`
- B bool `json:"b"`
- Ob *bool `json:"ob,omitempty"`
- As []string `json:"as"`
- Oas *[]string `json:"oas,omitempty"`
- O InnerObject `json:"o"`
- Oo *InnerObject `json:"oo,omitempty"`
- D MockBinder `json:"d"`
- Od *MockBinder `json:"od,omitempty"`
+ I int `json:"i"`
+ Oi *int `json:"oi,omitempty"`
+ F float32 `json:"f"`
+ Of *float32 `json:"of,omitempty"`
+ B bool `json:"b"`
+ Ob *bool `json:"ob,omitempty"`
+ As []string `json:"as"`
+ Oas *[]string `json:"oas,omitempty"`
+ O InnerObject `json:"o"`
+ Oo *InnerObject `json:"oo,omitempty"`
+ D MockBinder `json:"d"`
+ Od *MockBinder `json:"od,omitempty"`
+ M map[string]int `json:"m"`
+ Om *map[string]int `json:"om,omitempty"`
}
func TestDeepObject(t *testing.T) {
@@ -40,6 +42,9 @@ func TestDeepObject(t *testing.T) {
Name: "Marcin Romaszewicz",
ID: 123,
}
+ om := map[string]int{
+ "additional": 1,
+ }
d := MockBinder{Time: time.Date(2020, 2, 1, 0, 0, 0, 0, time.UTC)}
srcObj := AllFields{
@@ -58,6 +63,8 @@ func TestDeepObject(t *testing.T) {
Oo: &oo,
D: d,
Od: &d,
+ M: om,
+ Om: &om,
}
marshaled, err := MarshalDeepObject(srcObj, "p")
diff --git a/pkg/runtime/strictmiddleware.go b/pkg/runtime/strictmiddleware.go
new file mode 100644
index 0000000000..fac240e12d
--- /dev/null
+++ b/pkg/runtime/strictmiddleware.go
@@ -0,0 +1,21 @@
+package runtime
+
+import (
+ "context"
+ "net/http"
+
+ "github.com/gin-gonic/gin"
+ "github.com/labstack/echo/v4"
+)
+
+type StrictEchoHandlerFunc func(ctx echo.Context, request interface{}) (response interface{}, err error)
+
+type StrictEchoMiddlewareFunc func(f StrictEchoHandlerFunc, operationID string) StrictEchoHandlerFunc
+
+type StrictHttpHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (response interface{}, err error)
+
+type StrictHttpMiddlewareFunc func(f StrictHttpHandlerFunc, operationID string) StrictHttpHandlerFunc
+
+type StrictGinHandlerFunc func(ctx *gin.Context, request interface{}) (response interface{}, err error)
+
+type StrictGinMiddlewareFunc func(f StrictGinHandlerFunc, operationID string) StrictGinHandlerFunc
diff --git a/pkg/runtime/styleparam.go b/pkg/runtime/styleparam.go
index 8f7e12927a..06b2e2506e 100644
--- a/pkg/runtime/styleparam.go
+++ b/pkg/runtime/styleparam.go
@@ -27,6 +27,7 @@ import (
"time"
"github.com/deepmap/oapi-codegen/pkg/types"
+ "github.com/google/uuid"
)
// Parameter escaping works differently based on where a header is found
@@ -428,6 +429,10 @@ func primitiveToString(value interface{}) (string, error) {
case reflect.Struct:
// If input has Marshaler, such as object has Additional Property or AnyOf,
// We use this Marshaler and convert into interface{} before styling.
+ if v, ok := value.(uuid.UUID); ok {
+ output = v.String()
+ break
+ }
if m, ok := value.(json.Marshaler); ok {
buf, err := m.MarshalJSON()
if err != nil {
diff --git a/pkg/util/inputmapping.go b/pkg/util/inputmapping.go
index fb2ac756aa..7b475dbdd7 100644
--- a/pkg/util/inputmapping.go
+++ b/pkg/util/inputmapping.go
@@ -5,7 +5,7 @@ import (
"strings"
)
-// The input mapping is experessed on the command line as `key1:value1,key2:value2,...`
+// The input mapping is expressed on the command line as `key1:value1,key2:value2,...`
// We parse it here, but need to keep in mind that keys or values may contain
// commas and colons. We will allow escaping those using double quotes, so
// when passing in "key1":"value1", we will not look inside the quoted sections.
@@ -47,7 +47,7 @@ func ParseCommandLineList(input string) []string {
return args
}
-// This function splits a string along the specifed separator, but it
+// This function splits a string along the specified separator, but it
// ignores anything between double quotes for splitting. We do simple
// inside/outside quote counting. Quotes are not stripped from output.
func splitString(s string, sep rune) []string {