From 8b2d0ced879bca082a8849e3595cd9610c55c31c Mon Sep 17 00:00:00 2001 From: Big_Boulard Date: Wed, 31 May 2023 10:02:45 +0200 Subject: [PATCH] add links to source in the README.md file --- README.md | 266 +++++++++++++++++++++++++++++------------------------- 1 file changed, 143 insertions(+), 123 deletions(-) diff --git a/README.md b/README.md index dd123c3a66..467ce1f187 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -OpenAPI Client and Server Code Generator ----------------------------------------- +## OpenAPI Client and Server Code Generator ⚠️ This README may be for the latest development version, which may contain unreleased changes. Please ensure you're looking at the README for the latest @@ -45,12 +44,12 @@ directory does a lot of that for you. You would run it like so: Let's go through that `petstore.gen.go` file to show you everything which was generated. - ## Generated Server Boilerplate The `/components/schemas` section in OpenAPI defines reusable objects, so Go types are generated for these. The Pet Store example defines `Error`, `Pet`, `Pets` and `NewPet`, so we do the same in Go: + ```go // Error defines model for Error. type Error struct { @@ -121,11 +120,12 @@ will be passed as arguments to your function, since they are mandatory. Remaining arguments can be passed in headers, query arguments or cookies. Those will be written to a `params` object. Look at the `FindPets` function above, it takes as input `FindPetsParams`, which is defined as follows: - ```go + +```go // Parameters object for FindPets type FindPetsParams struct { - Tags *[]string `json:"tags,omitempty"` - Limit *int32 `json:"limit,omitempty"` + Tags *[]string `json:"tags,omitempty"` + Limit *int32 `json:"limit,omitempty"` } ``` @@ -135,6 +135,7 @@ specified, the pointer will be non-`nil`, and you can read its value. If you changed the OpenAPI specification to make the parameter required, the `FindPetsParams` structure will contain the type by value: + ```go type FindPetsParams struct { Tags *[]string `json:"tags,omitempty"` @@ -143,6 +144,7 @@ type FindPetsParams struct { ``` ### Registering handlers + There are a few ways of registering your http handler based on the type of server generated i.e. `-generate server` or `-generate chi-server`
Echo @@ -152,6 +154,7 @@ Code generated using `-generate server`. The usage of `Echo` is out of scope of this doc, but once you have an echo instance, we generate a utility function to help you associate your handlers with this autogenerated code. For the pet store, it looks like this: + ```go func RegisterHandlers(router codegen.EchoRouter, si ServerInterface) { wrapper := ServerInterfaceWrapper{ @@ -168,6 +171,7 @@ The wrapper functions referenced above contain generated code which pulls parameters off the `Echo` request context, and unmarshals them into Go objects. You would register the generated handlers as follows: + ```go func SetupHandler() { var myApi PetStoreImpl // This implements the pet store interface @@ -196,6 +200,7 @@ func SetupHandler() { r.Mount("/", Handler(&myApi)) } ``` +
Gin @@ -205,6 +210,7 @@ Code generated using `-generate gin`. The usage of `gin` is out of scope of this doc, but once you have an gin instance, we generate a utility function to help you associate your handlers with this autogenerated code. For the pet store, it looks like this: + ```go // RegisterHandlersWithOptions creates http.Handler with additional options func RegisterHandlersWithOptions(router *gin.Engine, si ServerInterface, options GinServerOptions) *gin.Engine { @@ -241,6 +247,7 @@ func SetupHandler() { r = api.RegisterHandlers(r, petStore) } ``` +
net/http @@ -266,8 +273,8 @@ Alternatively, [Gorilla](https://github.com/gorilla/mux) is also 100% compatible #### Strict server generation -oapi-codegen also supports generating RPC inspired strict server, that will parse request bodies and encode responses. -The main points of this code is to automate some parsing, abstract user code from server specific code, +oapi-codegen also supports generating RPC inspired strict server, that will parse request bodies and encode responses. +The main points of this code is to automate some parsing, abstract user code from server specific code, and also to force user code to comply with the schema. It supports binding of `application/json` and `application/x-www-form-urlencoded` to a struct, for `multipart` requests it generates a `multipart.Reader`, which can be used to either manually iterating over parts or using `runtime.BindMultipart` @@ -279,6 +286,7 @@ Content-Type header, status code and will marshal the response data. You can als cause an `Internal Server Error` response. Short example: + ```go type PetStoreImpl struct {} func (*PetStoreImpl) GetPets(ctx context.Context, request GetPetsRequestObject) (GetPetsResponseObject, error) { @@ -287,10 +295,12 @@ func (*PetStoreImpl) GetPets(ctx context.Context, request GetPetsRequestObject) return GetPets200JSONResponse(result), nil } ``` -For a complete example see `/examples/petstore-expanded/strict`. + +For a complete example see [`examples/petstore-expanded/strict`](https://github.com/deepmap/oapi-codegen/tree/master/examples/petstore-expanded/strict). Code is generated with a configuration flag `generate: strict-server: true` along with any other server (echo, chi, gin and gorilla are supported). The generated strict wrapper can then be used as an implementation for `ServerInterface`. Setup example: + ```go func SetupHandler() { var myApi PetStoreImpl @@ -317,20 +327,22 @@ defaults to `false` and we don't generate this boilerplate. If you would like an object to accept `additionalProperties`, specify a schema for `additionalProperties`. Say we declared `NewPet` above like so: + ```yaml - NewPet: - required: - - name - properties: - name: - type: string - tag: - type: string - additionalProperties: - type: string +NewPet: + required: + - name + properties: + name: + type: string + tag: + type: string + additionalProperties: + type: string ``` The Go code for `NewPet` would now look like this: + ```go // NewPet defines model for NewPet. type NewPet struct { @@ -342,6 +354,7 @@ type NewPet struct { The additionalProperties, of type `string` become `map[string]string`, which maps field names to instances of the `additionalProperties` schema. + ```go // Getter for additional properties for NewPet. Returns the specified // element and whether it was found @@ -359,23 +372,25 @@ func (a NewPet) MarshalJSON() ([]byte, error) {...}w There are many special cases for `additionalProperties`, such as having to define types for inner fields which themselves support additionalProperties, and -all of them are tested via the `internal/test/components` schemas and tests. Please +all of them are tested via the [`internal/test/components`](https://github.com/deepmap/oapi-codegen/tree/master/internal/test/components) schemas and tests. Please look through those tests for more usage examples. #### oneOf/anyOf/allOf support - `oneOf` and `anyOf` are implemented using delayed parsing with the help of `json.RawMessage`. -The following schema will result in a type that has methods such as `AsCat`, `AsDog`, `FromCat`, `FromDog`, `MergeCat`, `MergeDog`. If the schema also includes a discriminator the generated code will also have methods such as `Discriminator`, `ValueByDiscriminator` and will force discriminator value in `From` methods. + The following schema will result in a type that has methods such as `AsCat`, `AsDog`, `FromCat`, `FromDog`, `MergeCat`, `MergeDog`. If the schema also includes a discriminator the generated code will also have methods such as `Discriminator`, `ValueByDiscriminator` and will force discriminator value in `From` methods. + ```yaml schema: oneOf: - $ref: '#/components/schemas/Cat' - $ref: '#/components/schemas/Dog' ``` + - `allOf` is supported, by taking the union of all the fields in all the - component schemas. This is the most useful of these operations, and is - commonly used to merge objects with an identifier, as in the - `petstore-expanded` example. + component schemas. This is the most useful of these operations, and is + commonly used to merge objects with an identifier, as in the + `petstore-expanded` example. ## Generated Client Boilerplate @@ -427,21 +442,21 @@ takes the same arguments. It's difficult to handle any arbitrary body that Swagger supports, so we've done some special casing for bodies, and you may get more than one function for an operation with a request body. -1) If you have more than one request body type, meaning more than one media - type, you will have a generic handler of this form: +1. If you have more than one request body type, meaning more than one media + type, you will have a generic handler of this form: - AddPet(ctx context.Context, contentType string, body io.Reader) + AddPet(ctx context.Context, contentType string, body io.Reader) -2) If you have only a JSON request body, you will get: +2. If you have only a JSON request body, you will get: - AddPet(ctx context.Context, body NewPet) + AddPet(ctx context.Context, body NewPet) -3) If you have multiple request body types, which include a JSON type you will - get two functions. We've chosen to give the JSON version a shorter name, as - we work with JSON and don't want to wear out our keyboards. +3. If you have multiple request body types, which include a JSON type you will + get two functions. We've chosen to give the JSON version a shorter name, as + we work with JSON and don't want to wear out our keyboards. - AddPet(ctx context.Context, body NewPet) - AddPetWithBody(ctx context.Context, contentType string, body io.Reader) + AddPet(ctx context.Context, body NewPet) + AddPetWithBody(ctx context.Context, contentType string, body io.Reader) The Client object above is fairly flexible, since you can pass in your own `http.Client` and a request editing callback. You can use that callback to add @@ -473,30 +488,30 @@ will correspond to your request schema. They map one-to-one to the functions on the client, except that we always generate the generic non-JSON body handler. There are some caveats to using this code. + - exploded, form style query arguments, which are the default argument format - in OpenAPI 3.0 are undecidable. Say that I have two objects, one composed of - the fields `(name=bob, id=5)` and another which has `(name=shoe, color=brown)`. - The first parameter is named `person` and the second is named `item`. The - default marshaling style for query args would result in - `/path/?name=bob,id=5&name=shoe,color=brown`. In order to tell what belongs - to which object, we'd have to look at all the parameters and try to deduce it, - but we're lazy, so we didn't. Don't use exploded form style arguments if - you're passing around objects which have similar field names. If you - used unexploded form parameters, you'd have - `/path/?person=name,bob,id,5&item=name,shoe,color,brown`, which an be - parsed unambiguously. + in OpenAPI 3.0 are undecidable. Say that I have two objects, one composed of + the fields `(name=bob, id=5)` and another which has `(name=shoe, color=brown)`. + The first parameter is named `person` and the second is named `item`. The + default marshaling style for query args would result in + `/path/?name=bob,id=5&name=shoe,color=brown`. In order to tell what belongs + to which object, we'd have to look at all the parameters and try to deduce it, + but we're lazy, so we didn't. Don't use exploded form style arguments if + you're passing around objects which have similar field names. If you + used unexploded form parameters, you'd have + `/path/?person=name,bob,id,5&item=name,shoe,color,brown`, which an be + parsed unambiguously. - Parameters can be defined via `schema` or via `content`. Use the `content` form - for anything other than trivial objects, they can marshal to arbitrary JSON - structures. When you send them as cookie (`in: cookie`) arguments, we will - URL encode them, since JSON delimiters aren't allowed in cookies. + for anything other than trivial objects, they can marshal to arbitrary JSON + structures. When you send them as cookie (`in: cookie`) arguments, we will + URL encode them, since JSON delimiters aren't allowed in cookies. ## Using SecurityProviders If you generate client-code, you can use some default-provided security providers which help you to use the various OpenAPI 3 Authentication mechanism. - ```go import ( "github.com/deepmap/oapi-codegen/pkg/securityprovider" @@ -563,51 +578,56 @@ which help you to use the various OpenAPI 3 Authentication mechanism. - `x-go-json-ignore`: sets tag to `-` to ignore the field in json completely. - `x-oapi-codegen-extra-tags`: adds extra Go field tags to the generated struct field. This is useful for interfacing with tag based ORM or validation libraries. The extra tags that - are added are in addition to the regular json tags that are generated. If you specify your - own `json` tag, you will override the default one. - - ```yaml - components: - schemas: - Object: - properties: - name: - type: string - x-oapi-codegen-extra-tags: - tag1: value1 - tag2: value2 - ``` - In the example above, field `name` will be declared as: - + are added are in addition to the regular json tags that are generated. If you specify your + own `json` tag, you will override the default one. + + ```yaml + components: + schemas: + Object: + properties: + name: + type: string + x-oapi-codegen-extra-tags: + tag1: value1 + tag2: value2 + ``` + + In the example above, field `name` will be declared as: + ``` Name string `json:"name" tag1:"value1" tag2:"value2"` ``` + - `x-go-type-import`: adds extra Go imports to your generated code. It can help you, when you want to - choose your own import package for `x-go-type`. + choose your own import package for `x-go-type`. ```yaml - schemas: - Pet: - properties: - age: - x-go-type: myuuid.UUID - x-go-type-import: - name: myuuid - path: github.com/google/uuid + schemas: + Pet: + properties: + age: + x-go-type: myuuid.UUID + x-go-type-import: + name: myuuid + path: github.com/google/uuid ``` + After code generation you will get this: + ```go import ( ... myuuid "github.com/google/uuid" ) - + //Pet defines model for Pet. type Pet struct { Age *myuuid.UUID `json:"age,omitempty"` } ``` + `name` is an optional parameter. Example: ```yaml @@ -627,44 +647,44 @@ which help you to use the various OpenAPI 3 Authentication mechanism. ```go import ( - "github.com/google/uuid" + "github.com/google/uuid" ) // Pet defines model for Pet. type Pet struct { - Age uuid.UUID `json:"age"` + Age uuid.UUID `json:"age"` } ``` - `x-enum-varnames`: supplies other enum names for the corresponding values. (alias: `x-enumNames`) - ```yaml - components: - schemas: - Object: - properties: - category: - type: integer - enum: [0, 1, 2] - x-enum-varnames: - - notice - - warning - - urgent - ``` - - After code generation you will get this result: - - ```go - // Defines values for ObjectCategory. - const ( - Notice ObjectCategory = 0 - Urgent ObjectCategory = 2 - Warning ObjectCategory = 1 - ) + ```yaml + components: + schemas: + Object: + properties: + category: + type: integer + enum: [0, 1, 2] + x-enum-varnames: + - notice + - warning + - urgent + ``` - // ObjectCategory defines model for Object.Category. - type ObjectCategory int - ``` + After code generation you will get this result: + + ```go + // Defines values for ObjectCategory. + const ( + Notice ObjectCategory = 0 + Urgent ObjectCategory = 2 + Warning ObjectCategory = 1 + ) + + // ObjectCategory defines model for Object.Category. + type ObjectCategory int + ``` ## Using `oapi-codegen` @@ -674,23 +694,23 @@ those via the `-generate` flag. It defaults to `types,client,server,spec`, but you can specify any combination of those. - `types`: generate all type definitions for all types in the OpenAPI spec. This - will be everything under `#components`, as well as request parameter, request - body, and response type objects. + will be everything under `#components`, as well as request parameter, request + body, and response type objects. - `server`: generate the Echo server boilerplate. `server` requires the types in the - same package to compile. + same package to compile. - `chi-server`: generate the Chi server boilerplate. This code is dependent on - that produced by the `types` target. + that produced by the `types` target. - `client`: generate the client boilerplate. It, too, requires the types to be - present in its package. + present in its package. - `spec`: embed the OpenAPI spec into the generated code as a gzipped blob. This is then usable with the `OapiRequestValidator`, or to be used by other methods that need access to the parsed OpenAPI specification - `skip-fmt`: skip running `goimports` on the generated code. This is useful for debugging - the generated file in case the spec contains weird strings. + the generated file in case the spec contains weird strings. - `skip-prune`: skip pruning unused components from the spec prior to generating - the code. + the code. - `import-mapping`: specifies a map of references external OpenAPI specs to go - Go include paths. Please see below. + Go include paths. Please see below. So, for example, if you would like to produce only the server code, you could run `oapi-codegen -generate types,server`. You could generate `types` and @@ -715,7 +735,7 @@ them pretty unwieldy, so you can specify all of the options in a configuration file via the `--config` option. Please see the test under [`/internal/test/externalref/`](https://github.com/deepmap/oapi-codegen/blob/master/internal/test/externalref/externalref.cfg.yaml) for an example. The structure of the file is as follows: - + ```yaml package: externalref generate: @@ -729,7 +749,7 @@ output-options: skip-prune: true ``` -Have a look at [`cmd/oapi-codegen/oapi-codegen.go`](https://github.com/deepmap/oapi-codegen/blob/master/cmd/oapi-codegen/oapi-codegen.go#L48) +Have a look at [`cmd/oapi-codegen/oapi-codegen.go`](https://github.com/deepmap/oapi-codegen/blob/master/cmd/oapi-codegen/oapi-codegen.go#L48) to see all the fields on the configuration structure. ### Import Mappings @@ -760,10 +780,9 @@ This code is still young, and not complete, since we're filling it in as we need it. We've not yet implemented several things: - `patternProperties` isn't yet supported and will exit with an error. Pattern - properties were defined in JSONSchema, and the `kin-openapi` Swagger object - knows how to parse them, but they're not part of OpenAPI 3.0, so we've left - them out, as support is very complicated. - + properties were defined in JSONSchema, and the `kin-openapi` Swagger object + knows how to parse them, but they're not part of OpenAPI 3.0, so we've left + them out, as support is very complicated. ## Making changes to code generation @@ -778,7 +797,7 @@ All this command does is inline the files ending in `.tmpl` into the specified Go file. Afterwards you should run `go generate ./...`, and the templates will be updated - accordingly. +accordingly. Alternatively, you can provide custom templates to override built-in ones using the `-templates` flag specifying a path to a directory containing templates @@ -807,7 +826,8 @@ HTTP request returns a non 200 response code, the generator will error. instead of a branch like `main`. Tracking a branch can lead to unexpected API drift, and loss of the ability to reproduce a build. -Examples: +Examples: + ```yaml output: api.gen.go package: api @@ -817,8 +837,8 @@ output-options: client-with-responses.tmpl: /home/username/workspace/templatesProject/my-client-with-responses.tmpl # The following are referencing a versuion of the default - # client-with-responses.tmpl file, but loaded in through - # github's raw.githubusercontent.com. The general form + # client-with-responses.tmpl file, but loaded in through + # github's raw.githubusercontent.com. The general form # to use raw.githubusercontent.com is as follows # https://raw.githubusercontent.com////path/to/template/template.tmpl @@ -840,7 +860,7 @@ output-options: ``` -Using the configuration file to load in templates **will** load in templates +Using the configuration file to load in templates **will** load in templates with names other than those defined by the built in templates. These user templates will not be called unless the user overrides a built in template to -call them however. \ No newline at end of file +call them however.