diff --git a/Makefile b/Makefile
index f09a336c11..91a47fe0b9 100644
--- a/Makefile
+++ b/Makefile
@@ -45,6 +45,16 @@ tidy:
# then, for all child modules, use a module-managed `Makefile`
git ls-files '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && make tidy'
+# Generate/update the Table of Contents in Markdown files.
+# Requires mdtoc: go install sigs.k8s.io/mdtoc@latest
+# Files must contain / sentinel comments.
+# Use "make readme-toc-check" in CI to verify TOCs are up-to-date.
+readme-toc:
+ mdtoc --inplace README.md
+
+readme-toc-check:
+ mdtoc --inplace --dryrun README.md
+
tidy-ci:
# for the root module, explicitly run the step, to prevent recursive calls
tidied -verbose
diff --git a/README.md b/README.md
index aa4dc860ee..f829740d06 100644
--- a/README.md
+++ b/README.md
@@ -9,17 +9,73 @@ Using `oapi-codegen` allows you to reduce the boilerplate required to create or
With `oapi-codegen`, there are a few [Key Design Decisions](#key-design-decisions) we've made, including:
- idiomatic Go, where possible
-- fairly simple generated code, erring on the side of duplicate code over nicely refactored code
-- supporting as much of OpenAPI 3.x as is possible, alongside Go's type system
+- fairly simple generated code, erring on the side of verbose code over complex modular code
+- supporting as much of OpenAPI 3.0 as is possible, alongside Go's type system
`oapi-codegen` is one part of a wider ecosystem, which can be found described in further detail in the [oapi-codegen organisation on GitHub](https://github.com/oapi-codegen).
⚠️ 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 release version.
-## Action Required: The repository for this project has changed
+## Table of Contents
+
+
+- [Installation](#installation)
+ - [Action Required: The repository for this project has changed](#action-required-the-repository-for-this-project-has-changed)
+ - [For Go 1.24+](#for-go-124)
+ - [Pinning to commits](#pinning-to-commits)
+- [Usage](#usage)
+ - [Backwards compatibility](#backwards-compatibility)
+- [Features](#features)
+- [What does it look like?](#what-does-it-look-like)
+- [Key design decisions](#key-design-decisions)
+- [Generating server-side boilerplate](#generating-server-side-boilerplate)
+ - [Supported Servers](#supported-servers)
+ - [Strict server](#strict-server)
+- [Generating API clients](#generating-api-clients)
+ - [With Server URLs](#with-server-urls)
+ - [Duplicate types generated for clients's response object types](#duplicate-types-generated-for-clientss-response-object-types)
+- [Generating API models](#generating-api-models)
+- [Splitting large OpenAPI specs across multiple packages (aka "Import Mapping" or "external references")](#splitting-large-openapi-specs-across-multiple-packages-aka-import-mapping-or-external-references)
+ - [Using a single package with multiple OpenAPI specs](#using-a-single-package-with-multiple-openapi-specs)
+ - [Using multiple packages, with one OpenAPI spec per package](#using-multiple-packages-with-one-openapi-spec-per-package)
+- [Modifying the input OpenAPI Specification (with OpenAPI Overlay)](#modifying-the-input-openapi-specification-with-openapi-overlay)
+- [Generating Nullable types](#generating-nullable-types)
+- [OpenAPI extensions](#openapi-extensions)
+- [Request/response validation middleware](#requestresponse-validation-middleware)
+- [Implementing security](#implementing-security)
+ - [On the server](#on-the-server)
+ - [On the client](#on-the-client)
+- [Custom code generation](#custom-code-generation)
+ - [Local paths](#local-paths)
+ - [HTTPS paths](#https-paths)
+ - [Inline template](#inline-template)
+ - [Using the Go package](#using-the-go-package)
+- [Additional Properties (additionalProperties)](#additional-properties-additionalproperties)
+ - [Implicit additionalProperties: true / no additionalProperties set](#implicit-additionalproperties-true--no-additionalproperties-set)
+ - [Explicit additionalProperties: true](#explicit-additionalproperties-true)
+ - [additionalProperties as integers](#additionalproperties-as-integers)
+ - [additionalProperties with an object](#additionalproperties-with-an-object)
+- [Globally skipping the "optional pointer"](#globally-skipping-the-optional-pointer)
+- [Changing the names of generated types](#changing-the-names-of-generated-types)
+- [Examples](#examples)
+ - [Blog posts](#blog-posts)
+- [Frequently Asked Questions (FAQs)](#frequently-asked-questions-faqs)
+ - [Does oapi-codegen support OpenAPI 3.1?](#does-oapi-codegen-support-openapi-31)
+ - [How does oapi-codegen handle anyOf, allOf and oneOf?](#how-does-oapi-codegen-handle-anyof-allof-and-oneof)
+ - [How can I ignore parts of the spec I don't care about?](#how-can-i-ignore-parts-of-the-spec-i-dont-care-about)
+ - [Should I commit the generated code?](#should-i-commit-the-generated-code)
+ - [Should I lint the generated code?](#should-i-lint-the-generated-code)
+ - [I've just updated my version of kin-openapi, and now I can't build my code 😠](#ive-just-updated-my-version-of-kin-openapi-and-now-i-cant-build-my-code-)
+- [Contributors](#contributors)
+- [Sponsors](#sponsors)
+
+
+## Installation
+
+### Action Required: The repository for this project has changed
As announced in [May 2024](https://github.com/oapi-codegen/oapi-codegen/discussions/1605),
-we have moved the project from the deepmap organization to our own organization, and you will need to update your
+we have moved the project from the Deepmap organization to our own organization, and you will need to update your
import paths to pull updates past this point. You need to do a recursive search/replace from
`github.com/deepmap/oapi-codegen/v2` to `github.com/oapi-codegen/oapi-codegen/v2`.
@@ -40,7 +96,7 @@ If you are using `v2.3.0` or above, please install like so, using the new module
go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest
```
-## Install
+### For Go 1.24+
It is recommended to follow [the `go tool` support available from Go 1.24+](https://www.jvt.me/posts/2025/01/27/go-tools-124/) for managing the dependency of `oapi-codegen` alongside your core application.
@@ -105,9 +161,12 @@ index 44f29a4..436a780 100644
## Usage
-`oapi-codegen` is largely configured using a YAML configuration file, to simplify the number of flags that users need to remember, and to make reading the `go:generate` command less daunting.
+`oapi-codegen` is configured using a YAML configuration file, to simplify the number of flags that users need to remember, and to make reading the `go:generate` command less daunting.
+While some command line options are supported, they should be considered deprecated,
+we just maintain them for backward compatibility, but we're not extending
+them.
-For full details of what is supported, it's worth checking out [the GoDoc for `codegen.Configuration`](https://pkg.go.dev/github.com/oapi-codegen/oapi-codegen/v2/pkg/codegen#Configuration).
+For full details of what is supported, check out the [oapi-codegen configuration documentation](docs/configuration.md).
We also have [a JSON Schema](configuration-schema.json) that can be used by IDEs/editors with the Language Server Protocol (LSP) to perform intelligent suggestions, i.e.:
@@ -366,14 +425,15 @@ We can see that this provides the best means to focus on the implementation of t
- Produce an interface that can be satisfied by your implementation, with reduced boilerplate
- Bulk processing and parsing of OpenAPI document in Go
- Resulting output is using Go's `text/template`s, which are user-overridable
-- Attempts to produce Idiomatic Go
-- Single-file output
-- Support multiple OpenAPI files by having a package-per-OpenAPI file
+- Attempts to produce idiomatic Go
+- Support multiple OpenAPI files by having a package per OpenAPI file
- Support of OpenAPI 3.0
- OpenAPI 3.1 support is [awaiting upstream support](https://github.com/oapi-codegen/oapi-codegen/issues/373)
However, we do have an experimental version using a different OpenAPI parser which does support 3.1 and 3.2, which
you can play around with in our [experimental repo](https://github.com/oapi-codegen/oapi-codegen-exp/tree/main/experimental)
- - Note that this does not include OpenAPI 2.0 (aka Swagger)
+ - Note that this does not include OpenAPI 2.0 (aka Swagger). If you have an old Swagger
+ specification, you can use a [converter](https://converter.swagger.io/) before
+ using oapi-codegen.
- Extract parameters from requests, to reduce work required by your implementation
- Implicit `additionalProperties` are ignored by default ([more details](#additional-properties-additionalproperties))
- Prune unused types by default
@@ -382,2423 +442,467 @@ We can see that this provides the best means to focus on the implementation of t
`oapi-codegen` shines by making it fairly straightforward (note that this is a purposeful choice of wording here - we want to avoid words like "easy") to generate the server-side boilerplate for a backend API.
-Below you can find the supported servers, and more information about how to implement a server using them.
+You can find the supported HTTP server backends below, and more information about how to implement a server on top of each router.
To provide you a fully Test Driven Development style test harness to confirm you are following the specification, you could use a tool such as [openapi.tanna.dev/go/validator](https://openapi.tanna.dev/go/validator/), or craft your own.
### Supported Servers
-Right now, we support the following servers, and are supportive of adding new servers, too!
+Right now, we support the following servers, and are supportive of adding new servers, too! Each
+server lists a minimum require Go version to compile the generated code, which may
+be different from that of oapi-codegen itself. While the code may compile on an
+older version of Go, we don't promise that it'll work.
+
+| Server | `generate` flag | Go Version | Documentation |
+| --- | --- |------------| --- |
+| [Chi](https://github.com/go-chi/chi) | `chi-server` | 1.24+ | [Chi documentation](docs/chi-server.md) |
+| [Echo](https://github.com/labstack/echo) | `echo-server` | 1.24+ | [Echo documentation](docs/echo-server.md) |
+| [Echo v5](https://github.com/labstack/echo) | `echo5-server` | 1.24+ | [Echo v5 documentation](docs/echo5-server.md) |
+| [Fiber](https://github.com/gofiber/fiber) | `fiber-server` | 1.24+ | [Fiber documentation](docs/fiber-server.md) |
+| [Gin](https://github.com/gin-gonic/gin) | `gin-server` | 1.24+ | [Gin documentation](docs/gin-server.md) |
+| [gorilla/mux](https://github.com/gorilla/mux) | `gorilla-server` | 1.24+ | [gorilla/mux documentation](docs/gorilla-server.md) |
+| [Iris](https://github.com/kataras/iris) | `iris-server` | 1.24+ | [Iris documentation](docs/iris-server.md) |
+| [1.22+ `net/http`](https://pkg.go.dev/net/http) | `std-http-server` | 1.24+ | [`net/http` documentation](docs/stdhttp-server.md) |
-
-
-
-|
-Server
- |
-
-generate flag to enable code generation
- |
-
-Required Go Version
- |
-
-Example usage
- |
-
-
-
-|
-
-[Chi](https://github.com/go-chi/chi)
-
- |
-
-chi-server
- |
-
-1.22+
- |
-
+### Strict server
+`oapi-codegen` also supports generating a server that is much more strict with the contract that the implementer requires, and takes inspiration from server-side code generation for RPC servers.
-For a Chi server, you will want a configuration file such as:
+This takes the boilerplate reduction from the non-strict servers and adds additional boilerplate reduction, allowing you to make the following changes to your function signatures:
-```yaml
-# yaml-language-server: ...
-package: api
-generate:
- chi-server: true
- models: true
-output: gen.go
+```diff
+-FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams)
++FindPets(ctx context.Context, request FindPetsRequestObject) (FindPetsResponseObject, error)
```
-To implement this, check out [the Chi docs](#impl-chi).
-
- |
-
+This is the highest level of strictness that `oapi-codegen` supports right now, and it's a good idea to start with this if you want the most guardrails to simplify developing your APIs.
-
-|
+The strict server has support for:
-[Echo](https://github.com/labstack/echo)
+- multiple request/response media types and status codes on a given operation
+- first-class support for `multipart/form-data` and `application/x-www-form-urlencoded` requests
+- returning an [HTTP 500 Internal Server Error](https://http.cat/500), when an `error` is returned from a function
+- automagic (un)marshalling of request/responses, and setting `content-type` and HTTP status codes on responses
+- binding request values to a struct, a `multipart.Reader` or providing a `io.Reader`
- |
-
-echo-server
- |
-
-1.22+
- |
-
+You can see a little more detail of the generated code in the ["What does it look like"](#what-does-it-look-like-strict) section.
-For an Echo server, you will want a configuration file such as:
+> [!NOTE]
+> To configure the strict server generation, you must specify another server to be generated. For instance:
```yaml
-# yaml-language-server: ...
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
package: api
generate:
- echo-server: true
- models: true
-output: gen.go
+ # NOTE another server must be added!
+ chi-server: true
+ strict-server: true
+output: server.gen.go
```
-To implement this, check out [the Echo docs](#impl-echo).
+> [!NOTE]
+> This doesn't include [validation of incoming requests](#requestresponse-validation-middleware).
- |
-
+## Generating API clients
-
-|
+As well as generating the server-side boilerplate, `oapi-codegen` can also generate API clients.
-[Fiber](https://github.com/gofiber/fiber)
+This aims to be an API client that can be used to interact with the methods of the API, and is perfectly suited for production usage.
- |
-
-fiber-server
- |
-
-1.24+
- |
-
+However, if you were looking for a slightly more SDK-style approach, or a mix of generated tests and/or documentation, this API client may not be for you, and you may want to look at alternate tooling.
-For a Fiber server, you will want a configuration file such as:
+For instance, given an `api.yaml`:
```yaml
-# yaml-language-server: ...
-package: api
-generate:
- fiber-server: true
- models: true
-output: gen.go
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Generate models
+paths:
+ /client:
+ get:
+ operationId: getClient
+ responses:
+ 200:
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ClientType"
+ put:
+ operationId: updateClient
+ responses:
+ 400:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ code:
+ type: string
+ required:
+ - code
+components:
+ schemas:
+ ClientType:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ # NOTE that this is not generated by default because it's not referenced. If you want it, you need to use the following YAML configuration:
+ #
+ # output-options:
+ # skip-prune: true
+ Unreferenced:
+ type: object
+ required:
+ - id
+ properties:
+ id:
+ type: integer
```
-To implement this, check out [the Fiber docs](#impl-fiber).
-
- |
-
-
-
-
-|
-
-[Gin](https://github.com/gin-gonic/gin)
-
- |
-
-gin-server
- |
-
-1.22+
- |
-
-
-For a Gin server, you will want a configuration file such as:
+And a `cfg.yaml`:
```yaml
-# yaml-language-server: ...
-package: api
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: client
+output: client.gen.go
generate:
- gin-server: true
models: true
-output: gen.go
+ client: true
```
-To implement this, check out [the Gin docs](#impl-gin).
-
- |
-
-
-
-
-|
-
-[gorilla/mux](https://github.com/gorilla/mux)
-
- |
-
-gorilla-server
- |
-
-1.22+
- |
-
+And a `generate.go`:
-For a gorilla/mux server, you will want a configuration file such as:
+```go
+package client
-```yaml
-# yaml-language-server: ...
-package: api
-generate:
- gorilla-server: true
- models: true
-output: gen.go
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
```
-To implement this, check out [the gorilla/mux docs](#impl-gorillamux).
-
- |
-
-
-
-|
-
-[Iris](https://github.com/kataras/iris)
+This would then generate:
- |
-
-iris-server
- |
-
-1.22+
- |
-
+```go
+package client
-For a Iris server, you will want a configuration file such as:
+// ...
-```yaml
-# yaml-language-server: ...
-package: api
-generate:
- iris-server: true
- models: true
-output: gen.go
-```
+// ClientType defines model for ClientType.
+type ClientType struct {
+ Name string `json:"name"`
+}
-To implement this, check out [the Iris docs](#impl-iris).
+// ...
- |
-
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
-
-|
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
-[1.22+ `net/http`](https://pkg.go.dev/net/http)
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
- |
-
-std-http-server
- |
-
-1.22+
- |
-
+// ...
-To use purely `net/http` (for Go 1.22+), you will want a configuration file such as:
+// The interface specification for the client above.
+type ClientInterface interface {
+ // GetClient request
+ GetClient(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
-```yaml
-# yaml-language-server: ...
-package: api
-generate:
- std-http-server: true
- models: true
-output: gen.go
-```
+ // UpdateClient request
+ UpdateClient(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
-To implement this, check out [the Go 1.22+ `net/http` docs](#impl-stdhttp).
+// ...
- |
-
-
-
-
-### Go 1.22+ `net/http`
-
-
-As of Go 1.22, enhancements have been made to the routing of the `net/http` package in the standard library, which makes it a great starting point for implementing a server with, before needing to reach for another router or a full framework.
-
-For instance, let's take this straightforward specification:
-
-```yaml
-openapi: "3.0.0"
-info:
- version: 1.0.0
- title: Minimal ping API server
-paths:
- /ping:
- get:
- responses:
- '200':
- description: pet response
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Pong'
-components:
- schemas:
- # base types
- Pong:
- type: object
- required:
- - ping
- properties:
- ping:
- type: string
- example: pong
-```
-
-This then generates code such as:
-
-```go
-// Pong defines model for Pong.
-type Pong struct {
- Ping string `json:"ping"`
-}
-
-// ServerInterface represents all server handlers.
-type ServerInterface interface {
-
- // (GET /ping)
- GetPing(w http.ResponseWriter, r *http.Request)
-}
-
-func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler {
- return HandlerWithOptions(si, StdHTTPServerOptions{
- BaseRouter: m,
- })
-}
-
-// HandlerWithOptions creates http.Handler with additional options
-func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler {
- m := options.BaseRouter
-
- // ... omitted for brevity
-
- m.HandleFunc("GET "+options.BaseURL+"/ping", wrapper.GetPing)
-
- return m
-}
-```
-
-To implement this HTTP server, we need to write the following code in our [`api/impl.go`](examples/minimal-server/stdhttp/api/impl.go):
-
-```go
-import (
- "encoding/json"
- "net/http"
-)
-
-// optional code omitted
-
-type Server struct{}
-
-func NewServer() Server {
- return Server{}
-}
-
-// (GET /ping)
-func (Server) GetPing(w http.ResponseWriter, r *http.Request) {
- resp := Pong{
- Ping: "pong",
- }
-
- w.WriteHeader(http.StatusOK)
- _ = json.NewEncoder(w).Encode(resp)
-}
-```
-
-Now we've got our implementation, we can then write the following code to wire it up and get a running server:
-
-```go
-import (
- "log"
- "net/http"
-
- "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/stdhttp/api"
-)
-
-func main() {
- // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
- server := api.NewServer()
-
- r := http.NewServeMux()
-
- // get an `http.Handler` that we can use
- h := api.HandlerFromMux(server, r)
-
- s := &http.Server{
- Handler: h,
- Addr: "0.0.0.0:8080",
- }
-
- // And we serve HTTP until the world ends.
- log.Fatal(s.ListenAndServe())
-}
-```
-
-> [!NOTE]
-> This doesn't include [validation of incoming requests](#requestresponse-validation-middleware).
-
-> [!NOTE]
-> If you feel like you've done everything right, but are still receiving `404 page not found` errors, make sure that you've got the `go` directive in your `go.mod` updated to:
-
-```go.mod
-go 1.22
-```
-
-
-
-### Chi
-
-
-For instance, let's take this straightforward specification:
-
-```yaml
-openapi: "3.0.0"
-info:
- version: 1.0.0
- title: Minimal ping API server
-paths:
- /ping:
- get:
- responses:
- '200':
- description: pet response
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Pong'
-components:
- schemas:
- # base types
- Pong:
- type: object
- required:
- - ping
- properties:
- ping:
- type: string
- example: pong
-```
-
-This then generates code such as:
-
-```go
-// Pong defines model for Pong.
-type Pong struct {
- Ping string `json:"ping"`
-}
-
-// ServerInterface represents all server handlers.
-type ServerInterface interface {
-
- // (GET /ping)
- GetPing(w http.ResponseWriter, r *http.Request)
-}
-
-// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
-func HandlerFromMux(si ServerInterface, r *mux.Router) http.Handler {
- return HandlerWithOptions(si, ChiServerOptions{
- BaseRouter: r,
- })
-}
-
-// HandlerWithOptions creates http.Handler with additional options
-func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handler {
- r := options.BaseRouter
-
- // ...
-
- r.Group(func(r chi.Router) {
- r.Get(options.BaseURL+"/ping", wrapper.GetPing)
- })
-
- return r
-}
-```
-
-To implement this HTTP server, we need to write the following code in our [`api/impl.go`](examples/minimal-server/chi/api/impl.go):
-
-```go
-import (
- "encoding/json"
- "net/http"
-)
-
-// optional code omitted
-
-type Server struct{}
-
-func NewServer() Server {
- return Server{}
-}
-
-// (GET /ping)
-func (Server) GetPing(w http.ResponseWriter, r *http.Request) {
- resp := Pong{
- Ping: "pong",
- }
-
- w.WriteHeader(http.StatusOK)
- _ = json.NewEncoder(w).Encode(resp)
-}
-```
-
-Now we've got our implementation, we can then write the following code to wire it up and get a running server:
-
-```go
-import (
- "log"
- "net/http"
-
- "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/chi/api"
- "github.com/go-chi/chi/v5"
-)
-
-func main() {
- // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
- server := api.NewServer()
-
- r := chi.NewMux()
-
- // get an `http.Handler` that we can use
- h := api.HandlerFromMux(server, r)
-
- s := &http.Server{
- Handler: h,
- Addr: "0.0.0.0:8080",
- }
-
- // And we serve HTTP until the world ends.
- log.Fatal(s.ListenAndServe())
-}
-```
-
-> [!NOTE]
-> This doesn't include [validation of incoming requests](#requestresponse-validation-middleware).
-
-### gorilla/mux
-
-
-For instance, let's take this straightforward specification:
-
-```yaml
-openapi: "3.0.0"
-info:
- version: 1.0.0
- title: Minimal ping API server
-paths:
- /ping:
- get:
- responses:
- '200':
- description: pet response
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Pong'
-components:
- schemas:
- # base types
- Pong:
- type: object
- required:
- - ping
- properties:
- ping:
- type: string
- example: pong
-```
-
-This then generates code such as:
-
-```go
-// Pong defines model for Pong.
-type Pong struct {
- Ping string `json:"ping"`
-}
-
-// ServerInterface represents all server handlers.
-type ServerInterface interface {
-
- // (GET /ping)
- GetPing(w http.ResponseWriter, r *http.Request)
-}
-
-// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
-func HandlerFromMux(si ServerInterface, r *mux.Router) http.Handler {
- return HandlerWithOptions(si, GorillaServerOptions{
- BaseRouter: r,
- })
-}
-
-// HandlerWithOptions creates http.Handler with additional options
-func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.Handler {
- r := options.BaseRouter
-
- // ...
-
- r.HandleFunc(options.BaseURL+"/ping", wrapper.GetPing).Methods("GET")
-
- return r
-}
-```
-
-To implement this HTTP server, we need to write the following code in our [`api/impl.go`](examples/minimal-server/gorillamux/api/impl.go):
-
-```go
-import (
- "encoding/json"
- "net/http"
-)
-
-// optional code omitted
-
-type Server struct{}
-
-func NewServer() Server {
- return Server{}
-}
-
-// (GET /ping)
-func (Server) GetPing(w http.ResponseWriter, r *http.Request) {
- resp := Pong{
- Ping: "pong",
- }
-
- w.WriteHeader(http.StatusOK)
- _ = json.NewEncoder(w).Encode(resp)
-}
-```
-
-Now we've got our implementation, we can then write the following code to wire it up and get a running server:
-
-```go
-import (
- "log"
- "net/http"
-
- "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/gorillamux/api"
- "github.com/gorilla/mux"
-)
-
-func main() {
- // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
- server := api.NewServer()
-
- r := mux.NewRouter()
-
- // get an `http.Handler` that we can use
- h := api.HandlerFromMux(server, r)
-
- s := &http.Server{
- Handler: h,
- Addr: "0.0.0.0:8080",
- }
-
- // And we serve HTTP until the world ends.
- log.Fatal(s.ListenAndServe())
-}
-```
-
-> [!NOTE]
-> This doesn't include [validation of incoming requests](#requestresponse-validation-middleware).
-
-### Echo server
-
-
-For instance, let's take this straightforward specification:
-
-```yaml
-openapi: "3.0.0"
-info:
- version: 1.0.0
- title: Minimal ping API server
-paths:
- /ping:
- get:
- responses:
- '200':
- description: pet response
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Pong'
-components:
- schemas:
- # base types
- Pong:
- type: object
- required:
- - ping
- properties:
- ping:
- type: string
- example: pong
-```
-
-This then generates code such as:
-
-```go
-// Pong defines model for Pong.
-type Pong struct {
- Ping string `json:"ping"`
-}
-
-// ServerInterface represents all server handlers.
-type ServerInterface interface {
-
- // (GET /ping)
- GetPing(ctx echo.Context) error
-}
-
-// 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
-type EchoRouter interface {
- // ...
- GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
- // ...
-}
-
-// RegisterHandlers adds each server route to the EchoRouter.
-func RegisterHandlers(router EchoRouter, si ServerInterface) {
- RegisterHandlersWithBaseURL(router, si, "")
-}
-
-// Registers handlers, and prepends BaseURL to the paths, so that the paths
-// can be served under a prefix.
-func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
- // ...
-
- router.GET(baseURL+"/ping", wrapper.GetPing)
-
-}
-```
-
-To implement this HTTP server, we need to write the following code in our [`api/impl.go`](examples/minimal-server/echo/api/impl.go):
-
-```go
-import (
- "net/http"
-
- "github.com/labstack/echo/v4"
-)
-
-// optional code omitted
-
-type Server struct{}
-
-func NewServer() Server {
- return Server{}
-}
-
-// (GET /ping)
-func (Server) GetPing(ctx echo.Context) error {
- resp := Pong{
- Ping: "pong",
- }
-
- return ctx.JSON(http.StatusOK, resp)
-}
-```
-
-Now we've got our implementation, we can then write the following code to wire it up and get a running server:
-
-```go
-import (
- "log"
-
- "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/echo/api"
- "github.com/labstack/echo/v4"
-)
-
-func main() {
- // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
- server := api.NewServer()
-
- e := echo.New()
-
- api.RegisterHandlers(e, server)
-
- // And we serve HTTP until the world ends.
- log.Fatal(e.Start("0.0.0.0:8080"))
-}
-```
-
-> [!NOTE]
-> This doesn't include [validation of incoming requests](#requestresponse-validation-middleware).
-
-### Fiber server
-
-
-For instance, let's take this straightforward specification:
-
-```yaml
-openapi: "3.0.0"
-info:
- version: 1.0.0
- title: Minimal ping API server
-paths:
- /ping:
- get:
- responses:
- '200':
- description: pet response
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Pong'
-components:
- schemas:
- # base types
- Pong:
- type: object
- required:
- - ping
- properties:
- ping:
- type: string
- example: pong
-```
-
-This then generates code such as:
-
-```go
-// Pong defines model for Pong.
-type Pong struct {
- Ping string `json:"ping"`
-}
-
-// ServerInterface represents all server handlers.
-type ServerInterface interface {
-
- // (GET /ping)
- GetPing(c *fiber.Ctx) error
-}
-
-// 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) {
- // ...
-
- router.Get(options.BaseURL+"/ping", wrapper.GetPing)
-}
-```
-
-To implement this HTTP server, we need to write the following code in our [`api/impl.go`](examples/minimal-server/fiber/api/impl.go):
-
-```go
-import (
- "net/http"
-
- "github.com/gofiber/fiber/v2"
-)
-
-// ensure that we've conformed to the `ServerInterface` with a compile-time check
-var _ ServerInterface = (*Server)(nil)
-
-type Server struct{}
-
-func NewServer() Server {
- return Server{}
-}
-
-// (GET /ping)
-func (Server) GetPing(ctx *fiber.Ctx) error {
- resp := Pong{
- Ping: "pong",
- }
-
- return ctx.
- Status(http.StatusOK).
- JSON(resp)
-}
-```
-
-Now we've got our implementation, we can then write the following code to wire it up and get a running server:
-
-```go
-import (
- "log"
-
- "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/fiber/api"
- "github.com/gofiber/fiber/v2"
-)
-
-func main() {
- // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
- server := api.NewServer()
-
- app := fiber.New()
-
- api.RegisterHandlers(app, server)
-
- // And we serve HTTP until the world ends.
- log.Fatal(app.Listen("0.0.0.0:8080"))
-}
-```
-
-> [!NOTE]
-> This doesn't include [validation of incoming requests](#requestresponse-validation-middleware).
-
-### Gin server
-
-
-For instance, let's take this straightforward specification:
-
-```yaml
-openapi: "3.0.0"
-info:
- version: 1.0.0
- title: Minimal ping API server
-paths:
- /ping:
- get:
- responses:
- '200':
- description: pet response
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Pong'
-components:
- schemas:
- # base types
- Pong:
- type: object
- required:
- - ping
- properties:
- ping:
- type: string
- example: pong
-```
-
-This then generates code such as:
-
-```go
-// Pong defines model for Pong.
-type Pong struct {
- Ping string `json:"ping"`
-}
-
-// ServerInterface represents all server handlers.
-type ServerInterface interface {
-
- // (GET /ping)
- GetPing(c *gin.Context)
-}
-
-// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
-func RegisterHandlers(router gin.IRouter, si ServerInterface) {
- RegisterHandlersWithOptions(router, si, GinServerOptions{})
-}
-
-// RegisterHandlersWithOptions creates http.Handler with additional options
-func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options GinServerOptions) {
- // ...
-
- router.GET(options.BaseURL+"/ping", wrapper.GetPing)
-}
-```
-
-To implement this HTTP server, we need to write the following code in our [`api/impl.go`](examples/minimal-server/gorillamux/api/impl.go):
-
-```go
-import (
- "net/http"
-
- "github.com/gin-gonic/gin"
-)
-
-// optional code omitted
-
-type Server struct{}
-
-func NewServer() Server {
- return Server{}
-}
-
-// (GET /ping)
-func (Server) GetPing(ctx *gin.Context) {
- resp := Pong{
- Ping: "pong",
- }
-
- ctx.JSON(http.StatusOK, resp)
-}
-```
-
-Now we've got our implementation, we can then write the following code to wire it up and get a running server:
-
-```go
-import (
- "log"
- "net/http"
-
- "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/gin/api"
- "github.com/gin-gonic/gin"
-)
-
-func main() {
- // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
- server := api.NewServer()
-
- r := gin.Default()
-
- api.RegisterHandlers(r, server)
-
- // And we serve HTTP until the world ends.
-
- s := &http.Server{
- Handler: r,
- Addr: "0.0.0.0:8080",
- }
-
- // And we serve HTTP until the world ends.
- log.Fatal(s.ListenAndServe())
-}
-```
-
-> [!NOTE]
-> This doesn't include [validation of incoming requests](#requestresponse-validation-middleware).
-
-### Iris server
-
-
-For instance, let's take this straightforward specification:
-
-```yaml
-openapi: "3.0.0"
-info:
- version: 1.0.0
- title: Minimal ping API server
-paths:
- /ping:
- get:
- responses:
- '200':
- description: pet response
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Pong'
-components:
- schemas:
- # base types
- Pong:
- type: object
- required:
- - ping
- properties:
- ping:
- type: string
- example: pong
-```
-
-This then generates code such as:
-
-```go
-// Pong defines model for Pong.
-type Pong struct {
- Ping string `json:"ping"`
-}
-
-// ServerInterface represents all server handlers.
-type ServerInterface interface {
-
- // (GET /ping)
- GetPing(ctx iris.Context)
-}
-
-// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
-func RegisterHandlers(router *iris.Application, si ServerInterface) {
- RegisterHandlersWithOptions(router, si, IrisServerOptions{})
-}
-
-// RegisterHandlersWithOptions creates http.Handler with additional options
-func RegisterHandlersWithOptions(router *iris.Application, si ServerInterface, options IrisServerOptions) {
- // ...
-
- router.Get(options.BaseURL+"/ping", wrapper.GetPing)
-
- router.Build()
-}
-```
-
-To implement this HTTP server, we need to write the following code in our [`api/impl.go`](examples/minimal-server/gorillamux/api/impl.go):
-
-```go
-import (
- "net/http"
-
- "github.com/kataras/iris/v12"
-)
-
-// optional code omitted
-
-type Server struct{}
-
-func NewServer() Server {
- return Server{}
-}
-
-// (GET /ping)
-func (Server) GetPing(ctx iris.Context) {
- resp := Pong{
- Ping: "pong",
- }
-
- ctx.StatusCode(http.StatusOK)
- _ = ctx.JSON(resp)
-}
-```
-
-Now we've got our implementation, we can then write the following code to wire it up and get a running server:
-
-```go
-import (
- "log"
-
- "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/iris/api"
- "github.com/kataras/iris/v12"
-)
-
-func main() {
- // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
- server := api.NewServer()
-
- i := iris.Default()
-
- api.RegisterHandlers(i, server)
-
- // And we serve HTTP until the world ends.
- log.Fatal(i.Listen("0.0.0.0:8080"))
-}
-```
-
-> [!NOTE]
-> This doesn't include [validation of incoming requests](#requestresponse-validation-middleware).
-
-### Strict server
-
-`oapi-codegen` also supports generating a server that is much more strict with the contract that the implementer requires, and takes inspiration from server-side code generation for RPC servers.
-
-This takes the boilerplate reduction from the non-strict servers and adds additional boilerplate reduction, allowing you to make the following changes to your function signatures:
-
-```diff
--FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams)
-+FindPets(ctx context.Context, request FindPetsRequestObject) (FindPetsResponseObject, error)
-```
-
-This is the highest level of strictness that `oapi-codegen` supports right now, and it's a good idea to start with this if you want the most guardrails to simplify developing your APIs.
-
-The strict server has support for:
-
-- multiple request/response media types and status codes on a given operation
-- first-class support for `multipart/form-data` and `application/x-www-form-urlencoded` requests
-- returning an [HTTP 500 Internal Server Error](https://http.cat/500), when an `error` is returned from a function
-- automagic (un)marshalling of request/responses, and setting `content-type` and HTTP status codes on responses
-- binding request values to a struct, a `multipart.Reader` or providing a `io.Reader`
-
-You can see a little more detail of the generated code in the ["What does it look like"](#what-does-it-look-like-strict) section.
-
-> [!NOTE]
-> To configure the strict server generation, you must specify another server to be generated. For instance:
-
-```yaml
-# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
-package: api
-generate:
- # NOTE another server must be added!
- chi-server: true
- strict-server: true
-output: server.gen.go
-```
-
-> [!NOTE]
-> This doesn't include [validation of incoming requests](#requestresponse-validation-middleware).
-
-## Generating API clients
-
-As well as generating the server-side boilerplate, `oapi-codegen` can also generate API clients.
-
-This aims to be an API client that can be used to interact with the methods of the API, and is perfectly suited for production usage.
-
-However, if you were looking for a slightly more SDK-style approach, or a mix of generated tests and/or documentation, this API client may not be for you, and you may want to look at alternate tooling.
-
-For instance, given an `api.yaml`:
-
-```yaml
-openapi: "3.0.0"
-info:
- version: 1.0.0
- title: Generate models
-paths:
- /client:
- get:
- operationId: getClient
- responses:
- 200:
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ClientType"
- put:
- operationId: updateClient
- responses:
- 400:
- content:
- application/json:
- schema:
- type: object
- properties:
- code:
- type: string
- required:
- - code
-components:
- schemas:
- ClientType:
- type: object
- required:
- - name
- properties:
- name:
- type: string
- # NOTE that this is not generated by default because it's not referenced. If you want it, you need to use the following YAML configuration:
- #
- # output-options:
- # skip-prune: true
- Unreferenced:
- type: object
- required:
- - id
- properties:
- id:
- type: integer
-```
-
-And a `cfg.yaml`:
-
-```yaml
-# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
-package: client
-output: client.gen.go
-generate:
- models: true
- client: true
-```
-
-And a `generate.go`:
-
-```go
-package client
-
-//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
-```
-
-This would then generate:
-
-```go
-package client
-
-// ...
-
-// ClientType defines model for ClientType.
-type ClientType struct {
- Name string `json:"name"`
-}
-
-// ...
-
-// Client which conforms to the OpenAPI3 specification for this service.
-type Client struct {
- // The endpoint of the server conforming to this interface, with scheme,
- // https://api.deepmap.com for example. This can contain a path relative
- // to the server, such as https://api.deepmap.com/dev-test, and all the
- // paths in the swagger spec will be appended to the server.
- Server string
-
- // Doer for performing requests, typically a *http.Client with any
- // customized settings, such as certificate chains.
- Client HttpRequestDoer
-
- // A list of callbacks for modifying requests which are generated before sending over
- // the network.
- RequestEditors []RequestEditorFn
-}
-
-// ...
-
-// The interface specification for the client above.
-type ClientInterface interface {
- // GetClient request
- GetClient(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
-
- // UpdateClient request
- UpdateClient(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
-}
-
-// ...
-
-// ClientWithResponsesInterface is the interface specification for the client with responses above.
-type ClientWithResponsesInterface interface {
- // GetClientWithResponse request
- GetClientWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetClientResponse, error)
-
- // UpdateClientWithResponse request
- UpdateClientWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*UpdateClientResponse, error)
-}
-
-type GetClientResponse struct {
- Body []byte
- HTTPResponse *http.Response
- JSON200 *ClientType
-}
-
-// ...
-```
-
-With this generated client, it is then possible to construct and utilise the client, for instance:
-
-```go
-package client_test
-
-import (
- "context"
- "fmt"
- "log"
- "net/http"
-
- "github.com/oapi-codegen/oapi-codegen/v2/examples/client"
-)
-
-func TestClient_canCall() {
- // custom HTTP client
- hc := http.Client{}
-
- // with a raw http.Response
- {
- c, err := client.NewClient("http://localhost:1234", client.WithHTTPClient(&hc))
- if err != nil {
- log.Fatal(err)
- }
-
- resp, err := c.GetClient(context.TODO())
- if err != nil {
- log.Fatal(err)
- }
- if resp.StatusCode != http.StatusOK {
- log.Fatalf("Expected HTTP 200 but received %d", resp.StatusCode)
- }
- }
-
- // or to get a struct with the parsed response body
- {
- c, err := client.NewClientWithResponses("http://localhost:1234", client.WithHTTPClient(&hc))
- if err != nil {
- log.Fatal(err)
- }
-
- resp, err := c.GetClientWithResponse(context.TODO())
- if err != nil {
- log.Fatal(err)
- }
- if resp.StatusCode() != http.StatusOK {
- log.Fatalf("Expected HTTP 200 but received %d", resp.StatusCode())
- }
-
- fmt.Printf("resp.JSON200: %v\n", resp.JSON200)
- }
-
-}
-```
-
-### With Server URLs
-
-An OpenAPI specification makes it possible to denote Servers that a client can interact with, such as:
-
-```yaml
-servers:
-- url: https://development.gigantic-server.com/v1
- description: Development server
-- url: https://{username}.gigantic-server.com:{port}/{basePath}
- description: The production API server
- variables:
- username:
- # note! no enum here means it is an open value
- default: demo
- description: this value is assigned by the service provider, in this example `gigantic-server.com`
- port:
- enum:
- - '8443'
- - '443'
- default: '8443'
- basePath:
- # open meaning there is the opportunity to use special base paths as assigned by the provider, default is `v2`
- default: v2
-```
-
-It is possible to opt-in to the generation of these Server URLs with the following configuration:
-
-```yaml
-# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
-package: serverurls
-output: gen.go
-generate:
- # NOTE that this uses default settings - if you want to use initialisms to generate i.e. `ServerURLDevelopmentServer`, you should look up the `output-options.name-normalizer` configuration
- server-urls: true
-```
-
-This will then generate the following boilerplate:
-
-```go
-// (the below does not include comments that are generated)
-
-const ServerUrlDevelopmentServer = "https://development.gigantic-server.com/v1"
-
-type ServerUrlTheProductionAPIServerBasePathVariable string
-const ServerUrlTheProductionAPIServerBasePathVariableDefault = "v2"
-
-type ServerUrlTheProductionAPIServerPortVariable string
-const ServerUrlTheProductionAPIServerPortVariable8443 ServerUrlTheProductionAPIServerPortVariable = "8443"
-const ServerUrlTheProductionAPIServerPortVariable443 ServerUrlTheProductionAPIServerPortVariable = "443"
-const ServerUrlTheProductionAPIServerPortVariableDefault ServerUrlTheProductionAPIServerPortVariable = ServerUrlTheProductionAPIServerPortVariable8443
-
-type ServerUrlTheProductionAPIServerUsernameVariable string
-const ServerUrlTheProductionAPIServerUsernameVariableDefault = "demo"
-
-func ServerUrlTheProductionAPIServer(basePath ServerUrlTheProductionAPIServerBasePathVariable, port ServerUrlTheProductionAPIServerPortVariable, username ServerUrlTheProductionAPIServerUsernameVariable) (string, error) {
- // ...
-}
-```
-
-Notice that for URLs that are not templated, a simple `const` definition is created.
-
-However, for more complex URLs that defined `variables` in them, we generate the types (and any `enum` values or `default` values), and instead use a function to create the URL.
-
-For a complete example see [`examples/generate/serverurls`](examples/generate/serverurls).
-
-### Duplicate types generated for clients's response object types
-
-When generating the types for interacting with the generated client, `oapi-codegen` will use the `operationId` and add on a `Request` or `Response` suffix.
-
-However, this can clash if you have named your component schemas in a similar way.
-
-For instance:
-
-```yaml
-openapi: "3.0.0"
-info:
- version: 1.0.0
- title: "Show that generated client boilerplate can clash if schemas are well named i.e. `*Request` and `*Response`"
-paths:
- /client:
- put:
- operationId: updateClient
- requestBodies:
- application/json:
- schema:
- $ref: '#/components/schemas/UpdateClientRequest'
- responses:
- 400:
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/UpdateClientResponse'
-components:
- schemas:
- UpdateClientRequest:
- type: object
- properties:
- code:
- type: string
- required:
- - code
- UpdateClientResponse:
- type: object
- required:
- - name
- properties:
- name:
- type: string
-```
-
-If you were to generate with this configuration:
-
-```yaml
-# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
-package: client
-output: client.gen.go
-generate:
- models: true
- client: true
-```
-
-This would then result in `go build` failures:
-
-```
-# github.com/oapi-codegen/oapi-codegen/v2/examples/clienttypenameclash
-./client.gen.go:184:6: UpdateClientResponse redeclared in this block
- ./client.gen.go:17:6: other declaration of UpdateClientResponse
-./client.gen.go:192:7: r.HTTPResponse undefined (type UpdateClientResponse has no field or method HTTPResponse)
-./client.gen.go:193:12: r.HTTPResponse undefined (type UpdateClientResponse has no field or method HTTPResponse)
-./client.gen.go:200:7: r.HTTPResponse undefined (type UpdateClientResponse has no field or method HTTPResponse)
-./client.gen.go:201:12: r.HTTPResponse undefined (type UpdateClientResponse has no field or method HTTPResponse)
-./client.gen.go:224:3: unknown field Body in struct literal of type UpdateClientResponse
-./client.gen.go:225:3: unknown field HTTPResponse in struct literal of type UpdateClientResponse
-./client.gen.go:234:12: response.JSON400 undefined (type *UpdateClientResponse has no field or method JSON400)
-```
-
-To fix this, use the `response-type-suffix` Output Option:
-
-```diff
- # yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
- package: client
- output: client.gen.go
- generate:
- models: true
- client: true
-+output-options:
-+ response-type-suffix: Resp
-```
-
-This will then rename the generated types from the default to use the new suffix:
-
-```diff
--type UpdateClientResponse struct {
-+type UpdateClientResp struct {
- Body []byte
- HTTPResponse *http.Response
- JSON400 *UpdateClientResponse
- }
-```
-
-There is no currently planned work to change this behaviour.
-
-## Generating API models
-
-If you're looking to only generate the models for interacting with a remote service, for instance if you need to hand-roll the API client for whatever reason, you can do this as-is.
-
-> [!TIP]
-> Try to define as much as possible within the `#/components/schemas` object, as `oapi-codegen` will generate all the types here.
->
-> Although we can generate some types based on inline definitions in i.e. a path's response type, it isn't always possible to do this, or if it is generated, can be a little awkward to work with as it may be defined as an anonymous struct.
-
-For instance, given an `api.yaml`:
-
-```yaml
-openapi: "3.0.0"
-info:
- version: 1.0.0
- title: Generate models
-paths:
- /client:
- get:
- operationId: getClient
- responses:
- 200:
- content:
- application/json:
- schema:
- # NOTE that Client is generated here, because it's within #/components/schemas
- $ref: "#/components/schemas/Client"
- put:
- operationId: updateClient
- responses:
- 400:
- content:
- application/json:
- # NOTE that this anonymous object is /not/ generated because it's an anonymous, but would be generated if using `generate: client`
- # See https://github.com/oapi-codegen/oapi-codegen/issues/1512
- schema:
- type: object
- properties:
- code:
- type: string
- required:
- - code
-components:
- schemas:
- Client:
- type: object
- required:
- - name
- properties:
- name:
- type: string
- # NOTE that this is not generated by default because it's not referenced. If you want it, you need to use the following YAML configuration:
- #
- # output-options:
- # skip-prune: true
- Unreferenced:
- type: object
- required:
- - id
- properties:
- id:
- type: integer
-```
-
-And a `cfg.yaml`:
-
-```yaml
-# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
-package: onlymodels
-output: only-models.gen.go
-generate:
- models: true
-```
-
-And a `generate.go`:
-
-```go
-package onlymodels
-
-//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
-```
-
-This would then generate:
-
-```go
-package onlymodels
-
-// Client defines model for Client.
-type Client struct {
- Name string `json:"name"`
-}
-```
-
-If you wish to also generate the `Unreferenced` type, you would need the following `cfg.yaml`:
-
-```yaml
-# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
-package: onlymodels
-output: only-models.gen.go
-generate:
- models: true
-output-options:
- # NOTE that this is only required for the `Unreferenced` type
- skip-prune: true
-```
-
-For a complete example see [`examples/only-models`](examples/only-models).
-
-## Splitting large OpenAPI specs across multiple packages (aka "Import Mapping" or "external references")
-
-
-When you've got a large OpenAPI specification, you may find it useful to split the contents of the spec across multiple files, using external references, such as:
-
-```yaml
- responses:
- 200:
- description: Success
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/User'
-```
-
-This is supported by `oapi-codegen`, through the ability to perform "Import Mapping".
-
-For instance, let's say that we have a large API, which has a user-facing API and an admin API, both of which use a common set of API models.
-
-In this case, we may have an Admin API that looks like:
-
-```yaml
-# admin/api.yaml
-openapi: "3.0.0"
-info:
- version: 1.0.0
- title: Admin API
- description: The admin-only portion of the API, which has its own separate OpenAPI spec
-tags:
- - name: admin
- description: Admin API endpoints
- - name: user
- description: API endpoint that pertains to user data
-paths:
- /admin/user/{id}:
- get:
- tags:
- - admin
- - user
- summary: Get a user's details
- operationId: getUserById
- parameters:
- - name: id
- in: path
- required: true
- schema:
- type: string
- format: uuid
- responses:
- 200:
- description: Success
- content:
- application/json:
- schema:
- $ref: '../common/api.yaml#/components/schemas/User'
-```
-
-This references the common spec:
-
-```yaml
-# common/api.yaml
-components:
- schemas:
- User:
- type: object
- additionalProperties: false
- properties:
- name:
- type: string
- required:
- - name
-```
-
-So how do we get `oapi-codegen` to generate our code?
-
-### Using a single package with multiple OpenAPI specs
-
-
-
-> [!TIP]
-> Since `oapi-codegen` v2.4.0, it is now possible to split large OpenAPI specifications into the same Go package, using the "self" mapping (denoted by a `-`) when using Import Mapping.
->
-> This is an improvement on the previous model, which would require splitting files across multiple packages.
-
-> [!NOTE]
-> You still need to have multiple `go generate`s, and any other configuration files.
-
-To get `oapi-codegen`'s single-package support working, we need multiple calls to `oapi-codegen`, one call per OpenAPI spec file:
-
-```sh
-$ go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg-api.yaml ../admin/api.yaml
-$ go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg-user.yaml ../common/api.yaml
-```
-
-This therefore means that we need multiple configuration files, such as `cfg-api.yaml`:
-
-```yaml
-# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
-package: samepackage
-output: server.gen.go
-generate:
- models: true
- chi-server: true
- strict-server: true
-output-options:
- # to make sure that all types are generated
- skip-prune: true
-import-mapping:
- user.yaml: "-"
-```
-
-And then our `cfg-user.yaml`:
-
-```yaml
-# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
-package: samepackage
-output: user.gen.go
-generate:
- models: true
-output-options:
- # to make sure that all types are generated
- skip-prune: true
-```
-
-From here, `oapi-codegen` will generate multiple Go files, all within the same package, which can be used to break down your large OpenAPI specifications, and generate only the subsets of code needed for each part of the spec.
-
-Check out [the import-mapping/samepackage example](examples/import-mapping/samepackage) for the full code.
-
-### Using multiple packages, with one OpenAPI spec per package
-
-To get `oapi-codegen`'s multi-package support working, we need to set up our directory structure:
-
-```
-├── admin
-│ ├── cfg.yaml
-│ └── generate.go
-└── common
- ├── cfg.yaml
- └── generate.go
-```
-
-We could start with our configuration file for our admin API spec:
-
-```yaml
-# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
-# admin/cfg.yaml
-package: admin
-output: server.gen.go
-generate:
- models: true
- chi-server: true
-output-options:
- # to make sure that all types are generated
- skip-prune: true
-# NOTE that this won't work, as it's missing `import-mapping`
-```
-
-If we were to run `oapi-codegen`, this will fail with the following error
-
-```
-error generating code: error creating operation definitions: error generating response definitions: error generating request body definition: error turning reference (../common/api.yaml#/components/schemas/User) into a Go type: unrecognized external reference '../common/api.yaml'; please provide the known import for this reference using option --import-mapping
-```
-
-This is because `oapi-codegen` requires the `import-mapping`:
-
-```yaml
-# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
-package: admin
-output: server.gen.go
-generate:
- models: true
- chi-server: true
-output-options:
- # to make sure that all types are generated
- skip-prune: true
-import-mapping:
- # for a given file/URL that is $ref'd, point `oapi-codegen` to the Go package that this spec is generated into, to perform Go package imports
- ../common/api.yaml: github.com/oapi-codegen/oapi-codegen/v2/examples/import-mapping/common
-```
-
-This will then generate the following code:
-
-```go
-package admin
-
-import (
- // ...
- externalRef0 "github.com/oapi-codegen/oapi-codegen/v2/examples/import-mapping/common"
-)
-
-// User defines model for User.
-type User = externalRef0.User
-```
-
-If you don't want to do this, an alternate option is to [use a single package, with multiple OpenAPI spec files for that given package](#import-mapping-self) or to [bundle your multiple OpenAPI files](https://www.jvt.me/posts/2022/02/10/bundle-openapi/) into a single spec.
-
-Check out [the import-mapping/multiplepackages example](examples/import-mapping/multiplepackages/) for the full code.
-
-## Modifying the input OpenAPI Specification (with OpenAPI Overlay)
-
-Prior to `oapi-codegen` v2.4.0, users wishing to override specific configuration, for instance taking advantage of extensions such as `x-go-type` would need to modify the OpenAPI specification they are using.
-
-In a lot of cases, this OpenAPI specification would be produced by a different team to the consumers (or even a different company) and so asking them to make changes like this were unreasonable.
-
-This would lead to the API consumers needing to vendor the specification from the producer (which is [our recommendation anyway](#https-paths)) and then make any number of local changes to the specification to make it generate code that looks reasonable.
-
-However, in the case that a consumer would update their specification, they would likely end up with a number of merge conflicts.
-
-Now, as of `oapi-codegen` v2.4.0, it is now possible to make changes to the input OpenAPI specification _without needing to modify it directly_.
-
-This takes advantage of the [OpenAPI Overlay specification](https://github.com/OAI/Overlay-Specification), which is a stable specification.
-
-> [!CAUTION]
-> Beware! Here (may) be dragons.
->
-> The Overlay specification requires the use of JSON Path, which some users may find difficult to write and/or maintain.
->
-> We still heavily recommend using Overlay functionality, but would like users to be aware of this.
->
-> There is a [proposed modification to the specification](https://github.com/OAI/Overlay-Specification/pull/32) which would relax the need for JSON Path as the targeting mechanism.
-
-For instance, let's say that we have the following OpenAPI specification, which provides insight into an internal endpoint that we should not be generating any code for (denoted by `x-internal`):
-
-```yaml
-openapi: "3.0.0"
-info:
- version: 1.0.0
- title: "Example to indicate how to use the OpenAPI Overlay specification (https://github.com/OAI/Overlay-Specification)"
-paths:
- /ping:
- get:
- responses:
- '200':
- description: pet response
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Pong'
- delete:
- x-internal: true
- responses:
- '202':
- content: {}
-```
-
-If we were to run `oapi-codegen` with out-of-the-box functionality, this would then lead to the DELETE endpoint being generated, which we don't want.
-
-Instead, we can define the following `overlay.yaml`:
-
-
-```yaml
-overlay: 1.0.0
-info:
- title: Overlay
- version: 0.0.0
-actions:
-- target: "$"
- description: Perform a structural overlay, which can be more readable, as it's clear what the shape of the document is
- update:
- info:
- x-overlay-applied: structured-overlay
- paths:
- /ping:
- get:
- responses:
- '200':
- description: Perform a ping request
-- target: $.paths.*[?(@.x-internal)]
- description: Remove internal endpoints (noted by x-internal)
- remove: true
-- target: $.paths.*.*[?(@.x-internal)]
- description: Remove internal endpoints (noted by x-internal)
- remove: true
-```
-
-And our configuration file for `oapi-codegen`:
-
-```yaml
-# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
-package: api
-output: ping.gen.go
-generate:
- models: true
- gorilla-server: true
- embedded-spec: true
-output-options:
- overlay:
- path: overlay.yaml
-```
-
-This then completely removes the DELETE endpoint _before_ we even start to parse the specification in `oapi-codegen`, so it's as if your specification was provided without that endpoint.
-
-Additionally, we can override other pieces of metadata, such as the description for operations.
-
-Check out [the overlay example](examples/overlay/) for the full code, and some more complex examples.
-
-## Generating Nullable types
-
-It's possible that you want to be able to determine whether a field isn't sent, is sent as `null` or has a value.
-
-For instance, if you had the following OpenAPI property:
-
-```yaml
-S:
- type: object
- properties:
- Field:
- type: string
- nullable: true
- required: []
-```
-
-The default behaviour in `oapi-codegen` is to generate:
-
-```go
-type S struct {
- Field *string `json:"field,omitempty"`
-}
-```
-
-However, you lose the ability to understand the three cases, as there's no way to distinguish two of the types from each other:
-
-- is this field not sent? (Can be checked with `S.Field == nil`)
-- is this field `null`? (Can be checked with `S.Field == nil`)
-- does this field have a value? (`S.Field != nil && *S.Field == "123"`)
-
-As of `oapi-codegen` [v2.1.0](https://github.com/oapi-codegen/oapi-codegen/releases/tag/v2.1.0) it is now possible to represent this with the `nullable.Nullable` type from [our new library, oapi-codegen/nullable](https://github.com/oapi-codegen/nullable).
-
-If you configure your generator's Output Options to opt-in to this behaviour, as so:
-
-```yaml
-output-options:
- nullable-type: true
-```
-
-You will now receive the following output:
-
-```go
-type S struct {
- // note that there's no pointer here, just `omitempty`
- Field nullable.Nullable[string] `json:"field,omitempty"`
-}
-```
-
-## OpenAPI extensions
-
-As well as the core OpenAPI support, we also support the following OpenAPI extensions, as denoted by the [OpenAPI Specification Extensions](https://spec.openapis.org/oas/v3.0.3#specification-extensions).
-
-The following extensions are supported:
-
-
-
-
-|
-Extension
- |
-
-Description
- |
-
-
-
-
-
-`x-go-type`
-`x-go-type-import`
-
- |
-
-Override the generated type definition (and optionally, add an import from another package)
- |
-
-
-
-|
-
-`x-go-type-skip-optional-pointer`
-
- |
-
-Do not add a pointer type for optional fields in structs
- |
-
-
-
-|
-
-`x-go-name`
-
- |
-
-Override the generated name of a field or a type
- |
-
-
-
-|
-
-`x-go-type-name`
-
- |
-
-Override the generated name of a type
- |
-
-
-
-|
-
-`x-omitempty`
-
- |
-
-Force the presence of the JSON tag `omitempty` on a field
- |
-
-
-
-|
-
-`x-omitzero`
-
- |
-
-Force the presence of the JSON tag `omitzero` on a field
- |
-
-
-
-|
-
-`x-go-json-ignore`
-
- |
-
-When (un)marshaling JSON, ignore field(s)
- |
-
-
-
-|
-
-`x-oapi-codegen-extra-tags`
-
- |
-
-Generate arbitrary struct tags to fields
- |
-
-
-
-|
-
-`x-enum-varnames` / `x-enumNames`
-
- |
-
-Override generated variable names for enum constants
- |
-
-
-
-|
-
-`x-deprecated-reason`
-
- |
-
-Add a GoDoc deprecation warning to a type
- |
-
-
-
-|
-
-`x-order`
-
- |
-
-Explicitly order struct fields
- |
-
-
-
-|
-
-`x-oapi-codegen-only-honour-go-name`
-
- |
-
-Only honour the `x-go-name` when generating field names
- |
-
-
-
-
-
-### `x-go-type` / `x-go-type-import` - override the generated type definition (and optionally, add an import from another package)
-
-Using the `x-go-type` (and optionally, `x-go-type-import` when you need to import another package) allows overriding the type that `oapi-codegen` determined the generated type should be.
-
-We can see this at play with the following schemas:
-
-```yaml
-components:
- schemas:
- Client:
- type: object
- required:
- - name
- properties:
- name:
- type: string
- id:
- type: number
- ClientWithExtension:
- type: object
- required:
- - name
- properties:
- name:
- type: string
- # this is a bit of a contrived example, as you could instead use
- # `format: uuid` but it explains how you'd do this when there may be
- # a clash, for instance if you already had a `uuid` package that was
- # being imported, or ...
- x-go-type: googleuuid.UUID
- x-go-type-import:
- path: github.com/google/uuid
- name: googleuuid
- id:
- type: number
- # ... this is also a bit of a contrived example, as you could use
- # `type: integer` but in the case that you know better than what
- # oapi-codegen is generating, like so:
- x-go-type: int64
-```
-
-From here, we now get two different models:
-
-```go
-// Client defines model for Client.
-type Client struct {
- Id *float32 `json:"id,omitempty"`
- Name string `json:"name"`
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // GetClientWithResponse request
+ GetClientWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetClientResponse, error)
+
+ // UpdateClientWithResponse request
+ UpdateClientWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*UpdateClientResponse, error)
}
-// ClientWithExtension defines model for ClientWithExtension.
-type ClientWithExtension struct {
- Id *int64 `json:"id,omitempty"`
- Name googleuuid.UUID `json:"name"`
+type GetClientResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *ClientType
}
+
+// ...
```
-You can see this in more detail in [the example code](examples/extensions/xgotype/).
+With this generated client, it is then possible to construct and utilise the client, for instance:
-### `x-go-type-skip-optional-pointer` - do not add a pointer type for optional fields in structs
+```go
+package client_test
-
+import (
+ "context"
+ "fmt"
+ "log"
+ "net/http"
-> [!TIP]
-> If you prefer this behaviour, and prefer to not have to annotate your whole OpenAPI spec for this behaviour, you can use `output-options.prefer-skip-optional-pointer=true` to default this behaviour for all fields.
->
-> It is then possible to override this on a per-type/per-field basis where necessary.
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/client"
+)
-By default, `oapi-codegen` will generate a pointer for optional fields.
+func TestClient_canCall() {
+ // custom HTTP client
+ hc := http.Client{}
-Using the `x-go-type-skip-optional-pointer` extension allows omitting that pointer.
+ // with a raw http.Response
+ {
+ c, err := client.NewClient("http://localhost:1234", client.WithHTTPClient(&hc))
+ if err != nil {
+ log.Fatal(err)
+ }
-We can see this at play with the following schemas:
+ resp, err := c.GetClient(context.TODO())
+ if err != nil {
+ log.Fatal(err)
+ }
+ if resp.StatusCode != http.StatusOK {
+ log.Fatalf("Expected HTTP 200 but received %d", resp.StatusCode)
+ }
+ }
-```yaml
-components:
- schemas:
- Client:
- type: object
- required:
- - name
- properties:
- name:
- type: string
- id:
- type: number
- ClientWithExtension:
- type: object
- required:
- - name
- properties:
- name:
- type: string
- id:
- type: number
- x-go-type-skip-optional-pointer: true
-```
+ // or to get a struct with the parsed response body
+ {
+ c, err := client.NewClientWithResponses("http://localhost:1234", client.WithHTTPClient(&hc))
+ if err != nil {
+ log.Fatal(err)
+ }
-From here, we now get two different models:
+ resp, err := c.GetClientWithResponse(context.TODO())
+ if err != nil {
+ log.Fatal(err)
+ }
+ if resp.StatusCode() != http.StatusOK {
+ log.Fatalf("Expected HTTP 200 but received %d", resp.StatusCode())
+ }
-```go
-// Client defines model for Client.
-type Client struct {
- Id *float32 `json:"id,omitempty"`
- Name string `json:"name"`
-}
+ fmt.Printf("resp.JSON200: %v\n", resp.JSON200)
+ }
-// ClientWithExtension defines model for ClientWithExtension.
-type ClientWithExtension struct {
- Id float32 `json:"id,omitempty"`
- Name string `json:"name"`
}
```
-You can see this in more detail in [the example code](examples/extensions/xgotypeskipoptionalpointer/).
-
-### `x-go-name` - override the generated name of a field or a type
+### With Server URLs
-By default, `oapi-codegen` will attempt to generate the name of fields and types in as best a way it can.
+An OpenAPI specification makes it possible to denote Servers that a client can interact with, such as:
-However, sometimes, the name doesn't quite fit what your codebase standards are, or the intent of the field, so you can override it with `x-go-name`.
+```yaml
+servers:
+- url: https://development.gigantic-server.com/v1
+ description: Development server
+- url: https://{username}.gigantic-server.com:{port}/{basePath}
+ description: The production API server
+ variables:
+ username:
+ # note! no enum here means it is an open value
+ default: demo
+ description: this value is assigned by the service provider, in this example `gigantic-server.com`
+ port:
+ enum:
+ - '8443'
+ - '443'
+ default: '8443'
+ basePath:
+ # open meaning there is the opportunity to use special base paths as assigned by the provider, default is `v2`
+ default: v2
+```
-We can see this at play with the following schemas:
+It is possible to opt-in to the generation of these Server URLs with the following configuration:
```yaml
-openapi: "3.0.0"
-info:
- version: 1.0.0
- title: x-go-name
-components:
- schemas:
- Client:
- type: object
- required:
- - name
- properties:
- name:
- type: string
- id:
- type: number
- ClientWithExtension:
- type: object
- # can be used on a type
- x-go-name: ClientRenamedByExtension
- required:
- - name
- properties:
- name:
- type: string
- id:
- type: number
- # or on a field
- x-go-name: AccountIdentifier
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: serverurls
+output: gen.go
+generate:
+ # NOTE that this uses default settings - if you want to use initialisms to generate i.e. `ServerURLDevelopmentServer`, you should look up the `output-options.name-normalizer` configuration
+ server-urls: true
```
-From here, we now get two different models:
+This will then generate the following boilerplate:
```go
-// Client defines model for Client.
-type Client struct {
- Id *float32 `json:"id,omitempty"`
- Name string `json:"name"`
-}
+// (the below does not include comments that are generated)
+
+const ServerUrlDevelopmentServer = "https://development.gigantic-server.com/v1"
-// ClientRenamedByExtension defines model for ClientWithExtension.
-type ClientRenamedByExtension struct {
- AccountIdentifier *float32 `json:"id,omitempty"`
- Name string `json:"name"`
+type ServerUrlTheProductionAPIServerBasePathVariable string
+const ServerUrlTheProductionAPIServerBasePathVariableDefault = "v2"
+
+type ServerUrlTheProductionAPIServerPortVariable string
+const ServerUrlTheProductionAPIServerPortVariable8443 ServerUrlTheProductionAPIServerPortVariable = "8443"
+const ServerUrlTheProductionAPIServerPortVariable443 ServerUrlTheProductionAPIServerPortVariable = "443"
+const ServerUrlTheProductionAPIServerPortVariableDefault ServerUrlTheProductionAPIServerPortVariable = ServerUrlTheProductionAPIServerPortVariable8443
+
+type ServerUrlTheProductionAPIServerUsernameVariable string
+const ServerUrlTheProductionAPIServerUsernameVariableDefault = "demo"
+
+func ServerUrlTheProductionAPIServer(basePath ServerUrlTheProductionAPIServerBasePathVariable, port ServerUrlTheProductionAPIServerPortVariable, username ServerUrlTheProductionAPIServerUsernameVariable) (string, error) {
+ // ...
}
```
-You can see this in more detail in [the example code](examples/extensions/xgoname/).
+Notice that for URLs that are not templated, a simple `const` definition is created.
-### `x-go-type-name` - Override the generated name of a type
+However, for more complex URLs that defined `variables` in them, we generate the types (and any `enum` values or `default` values), and instead use a function to create the URL.
-> [!NOTE]
-> Notice that this is subtly different to the `x-go-name`, which also applies to _fields_ within `struct`s.
+For a complete example see [`examples/generate/serverurls`](examples/generate/serverurls).
+
+### Duplicate types generated for clients's response object types
-By default, `oapi-codegen` will attempt to generate the name of types in as best a way it can.
+When generating the types for interacting with the generated client, `oapi-codegen` will use the `operationId` and add on a `Request` or `Response` suffix.
-However, sometimes, the name doesn't quite fit what your codebase standards are, or the intent of the field, so you can override it with `x-go-name`.
+However, this can clash if you have named your component schemas in a similar way.
-We can see this at play with the following schemas:
+For instance:
```yaml
openapi: "3.0.0"
info:
version: 1.0.0
- title: x-go-type-name
+ title: "Show that generated client boilerplate can clash if schemas are well named i.e. `*Request` and `*Response`"
+paths:
+ /client:
+ put:
+ operationId: updateClient
+ requestBodies:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UpdateClientRequest'
+ responses:
+ 400:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UpdateClientResponse'
components:
schemas:
- Client:
+ UpdateClientRequest:
type: object
- required:
- - name
properties:
- name:
+ code:
type: string
- id:
- type: number
- ClientWithExtension:
+ required:
+ - code
+ UpdateClientResponse:
type: object
- x-go-type-name: ClientRenamedByExtension
required:
- name
properties:
name:
type: string
- id:
- type: number
- # NOTE attempting a `x-go-type-name` here is a no-op, as we're not producing a _type_ only a _field_
- x-go-type-name: ThisWillNotBeUsed
```
-From here, we now get two different models and a type alias:
-
-```go
-// Client defines model for Client.
-type Client struct {
- Id *float32 `json:"id,omitempty"`
- Name string `json:"name"`
-}
-
-// ClientWithExtension defines model for ClientWithExtension.
-type ClientWithExtension = ClientRenamedByExtension
+If you were to generate with this configuration:
-// ClientRenamedByExtension defines model for .
-type ClientRenamedByExtension struct {
- Id *float32 `json:"id,omitempty"`
- Name string `json:"name"`
-}
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: client
+output: client.gen.go
+generate:
+ models: true
+ client: true
```
-You can see this in more detail in [the example code](examples/extensions/xgotypename/).
-
-### `x-omitempty` - force the presence of the JSON tag `omitempty` on a field
+This would then result in `go build` failures:
-In a case that you may want to add the JSON struct tag `omitempty` to types that don't have one generated by default - for instance a required field - you can use the `x-omitempty` extension.
+```
+# github.com/oapi-codegen/oapi-codegen/v2/examples/clienttypenameclash
+./client.gen.go:184:6: UpdateClientResponse redeclared in this block
+ ./client.gen.go:17:6: other declaration of UpdateClientResponse
+./client.gen.go:192:7: r.HTTPResponse undefined (type UpdateClientResponse has no field or method HTTPResponse)
+./client.gen.go:193:12: r.HTTPResponse undefined (type UpdateClientResponse has no field or method HTTPResponse)
+./client.gen.go:200:7: r.HTTPResponse undefined (type UpdateClientResponse has no field or method HTTPResponse)
+./client.gen.go:201:12: r.HTTPResponse undefined (type UpdateClientResponse has no field or method HTTPResponse)
+./client.gen.go:224:3: unknown field Body in struct literal of type UpdateClientResponse
+./client.gen.go:225:3: unknown field HTTPResponse in struct literal of type UpdateClientResponse
+./client.gen.go:234:12: response.JSON400 undefined (type *UpdateClientResponse has no field or method JSON400)
+```
-We can see this at play with the following schemas:
+To fix this, use the `response-type-suffix` Output Option:
-```yaml
-openapi: "3.0.0"
-info:
- version: 1.0.0
- title: x-omitempty
-components:
- schemas:
- Client:
- type: object
- required:
- - name
- properties:
- name:
- type: string
- id:
- type: number
- ClientWithExtension:
- type: object
- required:
- - name
- properties:
- name:
- type: string
- # for some reason, you may want this behaviour, even though it's a required field
- x-omitempty: true
- id:
- type: number
+```diff
+ # yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+ package: client
+ output: client.gen.go
+ generate:
+ models: true
+ client: true
++output-options:
++ response-type-suffix: Resp
```
-From here, we now get two different models:
-
-```go
-// Client defines model for Client.
-type Client struct {
- Id *float32 `json:"id,omitempty"`
- Name string `json:"name"`
-}
+This will then rename the generated types from the default to use the new suffix:
-// ClientWithExtension defines model for ClientWithExtension.
-type ClientWithExtension struct {
- Id *float32 `json:"id,omitempty"`
- Name string `json:"name,omitempty"`
-}
+```diff
+-type UpdateClientResponse struct {
++type UpdateClientResp struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON400 *UpdateClientResponse
+ }
```
-You can see this in more detail in [the example code](examples/extensions/xomitempty/).
+There is no currently planned work to change this behaviour.
-### `x-omitzero` - force the presence of the JSON tag `omitzero` on a field
+## Generating API models
-> [!NOTE]
-> `omitzero` was added in Go 1.24. If you're not using Go 1.24 in your project, this won't work.
+If you're looking to only generate the models for interacting with a remote service, for instance if you need to hand-roll the API client for whatever reason, you can do this as-is.
-In a case that you may want to add the JSON struct tag `omitzero` to types, you can use the `x-omitempty` extension.
+> [!TIP]
+> Try to define as much as possible within the `#/components/schemas` object, as `oapi-codegen` will generate all the types here.
+>
+> Although we can generate some types based on inline definitions in i.e. a path's response type, it isn't always possible to do this, or if it is generated, can be a little awkward to work with as it may be defined as an anonymous struct.
-We can see this at play with the following schemas:
+For instance, given an `api.yaml`:
```yaml
openapi: "3.0.0"
info:
version: 1.0.0
- title: x-omitempty
+ title: Generate models
+paths:
+ /client:
+ get:
+ operationId: getClient
+ responses:
+ 200:
+ content:
+ application/json:
+ schema:
+ # NOTE that Client is generated here, because it's within #/components/schemas
+ $ref: "#/components/schemas/Client"
+ put:
+ operationId: updateClient
+ responses:
+ 400:
+ content:
+ application/json:
+ # NOTE that this anonymous object is /not/ generated because it's an anonymous, but would be generated if using `generate: client`
+ # See https://github.com/oapi-codegen/oapi-codegen/issues/1512
+ schema:
+ type: object
+ properties:
+ code:
+ type: string
+ required:
+ - code
components:
schemas:
Client:
@@ -2808,395 +912,427 @@ components:
properties:
name:
type: string
- id:
- type: number
- ClientWithExtension:
+ # NOTE that this is not generated by default because it's not referenced. If you want it, you need to use the following YAML configuration:
+ #
+ # output-options:
+ # skip-prune: true
+ Unreferenced:
type: object
required:
- - name
+ - id
properties:
- name:
- type: string
id:
- type: number
- x-omitzero: true
+ type: integer
+```
+
+And a `cfg.yaml`:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: onlymodels
+output: only-models.gen.go
+generate:
+ models: true
+```
+
+And a `generate.go`:
+
+```go
+package onlymodels
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
```
-From here, we now get two different models:
+This would then generate:
```go
+package onlymodels
+
// Client defines model for Client.
type Client struct {
- Id *float32 `json:"id,omitempty"`
- Name string `json:"name"`
+ Name string `json:"name"`
}
+```
-// ClientWithExtension defines model for ClientWithExtension.
-type ClientWithExtension struct {
- Id *float32 `json:"id,omitempty,omitzero"`
- Name string `json:"name"`
-}
+If you wish to also generate the `Unreferenced` type, you would need the following `cfg.yaml`:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: onlymodels
+output: only-models.gen.go
+generate:
+ models: true
+output-options:
+ # NOTE that this is only required for the `Unreferenced` type
+ skip-prune: true
```
-You can see this in more detail in [the example code](examples/extensions/xomitzero/).
+For a complete example see [`examples/only-models`](examples/only-models).
+
+## Splitting large OpenAPI specs across multiple packages (aka "Import Mapping" or "external references")
+
+
+When you've got a large OpenAPI specification, you may find it useful to split the contents of the spec across multiple files, using external references, such as:
-### `x-go-json-ignore` - when (un)marshaling JSON, ignore field(s)
+```yaml
+ responses:
+ 200:
+ description: Success
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+```
-By default, `oapi-codegen` will generate `json:"..."` struct tags for all fields in a struct, so JSON (un)marshaling works.
+This is supported by `oapi-codegen`, through the ability to perform "Import Mapping".
-However, sometimes, you want to omit fields, which can be done with the `x-go-json-ignore` extension.
+For instance, let's say that we have a large API, which has a user-facing API and an admin API, both of which use a common set of API models.
-We can see this at play with the following schemas:
+In this case, we may have an Admin API that looks like:
```yaml
+# admin/api.yaml
openapi: "3.0.0"
info:
version: 1.0.0
- title: x-go-json-ignore
+ title: Admin API
+ description: The admin-only portion of the API, which has its own separate OpenAPI spec
+tags:
+ - name: admin
+ description: Admin API endpoints
+ - name: user
+ description: API endpoint that pertains to user data
+paths:
+ /admin/user/{id}:
+ get:
+ tags:
+ - admin
+ - user
+ summary: Get a user's details
+ operationId: getUserById
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ 200:
+ description: Success
+ content:
+ application/json:
+ schema:
+ $ref: '../common/api.yaml#/components/schemas/User'
+```
+
+This references the common spec:
+
+```yaml
+# common/api.yaml
components:
schemas:
- Client:
+ User:
type: object
- required:
- - name
+ additionalProperties: false
properties:
name:
type: string
- complexField:
- type: object
- properties:
- name:
- type: string
- accountName:
- type: string
- # ...
- ClientWithExtension:
- type: object
required:
- name
- properties:
- name:
- type: string
- complexField:
- type: object
- properties:
- name:
- type: string
- accountName:
- type: string
- # ...
- x-go-json-ignore: true
```
-From here, we now get two different models:
+So how do we get `oapi-codegen` to generate our code?
-```go
-// Client defines model for Client.
-type Client struct {
- ComplexField *struct {
- AccountName *string `json:"accountName,omitempty"`
- Name *string `json:"name,omitempty"`
- } `json:"complexField,omitempty"`
- Name string `json:"name"`
-}
+### Using a single package with multiple OpenAPI specs
-// ClientWithExtension defines model for ClientWithExtension.
-type ClientWithExtension struct {
- ComplexField *struct {
- AccountName *string `json:"accountName,omitempty"`
- Name *string `json:"name,omitempty"`
- } `json:"-"`
- Name string `json:"name"`
-}
-```
+
+
+> [!TIP]
+> Since `oapi-codegen` v2.4.0, it is now possible to split large OpenAPI specifications into the same Go package, using the "self" mapping (denoted by a `-`) when using Import Mapping.
+>
+> This is an improvement on the previous model, which would require splitting files across multiple packages.
+
+> [!NOTE]
+> You still need to have multiple `go generate`s, and any other configuration files.
-Notice that the `ComplexField` is still generated in full, but the type will then be ignored with JSON marshalling.
+To get `oapi-codegen`'s single-package support working, we need multiple calls to `oapi-codegen`, one call per OpenAPI spec file:
-You can see this in more detail in [the example code](examples/extensions/xgojsonignore/).
+```sh
+$ go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg-api.yaml ../admin/api.yaml
+$ go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg-user.yaml ../common/api.yaml
+```
-### `x-oapi-codegen-extra-tags` - generate arbitrary struct tags to fields
+This therefore means that we need multiple configuration files, such as `cfg-api.yaml`:
-If you're making use of a field's struct tags to i.e. apply validation, decide whether something should be logged, etc, you can use `x-oapi-codegen-extra-tags` to set additional tags for your generated types.
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: samepackage
+output: server.gen.go
+generate:
+ models: true
+ chi-server: true
+ strict-server: true
+output-options:
+ # to make sure that all types are generated
+ skip-prune: true
+import-mapping:
+ user.yaml: "-"
+```
-We can see this at play with the following schemas:
+And then our `cfg-user.yaml`:
```yaml
-openapi: "3.0.0"
-info:
- version: 1.0.0
- title: x-oapi-codegen-extra-tags
-components:
- schemas:
- Client:
- type: object
- required:
- - name
- - id
- properties:
- name:
- type: string
- id:
- type: number
- ClientWithExtension:
- type: object
- required:
- - name
- - id
- properties:
- name:
- type: string
- id:
- type: number
- x-oapi-codegen-extra-tags:
- validate: "required,min=1,max=256"
- safe-to-log: "true"
- gorm: primarykey
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: samepackage
+output: user.gen.go
+generate:
+ models: true
+output-options:
+ # to make sure that all types are generated
+ skip-prune: true
```
-From here, we now get two different models:
+From here, `oapi-codegen` will generate multiple Go files, all within the same package, which can be used to break down your large OpenAPI specifications, and generate only the subsets of code needed for each part of the spec.
+
+Check out [the import-mapping/samepackage example](examples/import-mapping/samepackage) for the full code.
+
+### Using multiple packages, with one OpenAPI spec per package
-```go
-// Client defines model for Client.
-type Client struct {
- Id float32 `json:"id"`
- Name string `json:"name"`
-}
+To get `oapi-codegen`'s multi-package support working, we need to set up our directory structure:
-// ClientWithExtension defines model for ClientWithExtension.
-type ClientWithExtension struct {
- Id float32 `gorm:"primarykey" json:"id" safe-to-log:"true" validate:"required,min=1,max=256"`
- Name string `json:"name"`
-}
+```
+├── admin
+│ ├── cfg.yaml
+│ └── generate.go
+└── common
+ ├── cfg.yaml
+ └── generate.go
```
-You can see this in more detail in [the example code](examples/extensions/xoapicodegenextratags/).
+We could start with our configuration file for our admin API spec:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+# admin/cfg.yaml
+package: admin
+output: server.gen.go
+generate:
+ models: true
+ chi-server: true
+output-options:
+ # to make sure that all types are generated
+ skip-prune: true
+# NOTE that this won't work, as it's missing `import-mapping`
+```
-### `x-enum-varnames` / `x-enumNames` - override generated variable names for enum constants
+If we were to run `oapi-codegen`, this will fail with the following error
-When consuming an enum value from an external system, the name may not produce a nice variable name. Using the `x-enum-varnames` extension allows overriding the name of the generated variable names.
+```
+error generating code: error creating operation definitions: error generating response definitions: error generating request body definition: error turning reference (../common/api.yaml#/components/schemas/User) into a Go type: unrecognized external reference '../common/api.yaml'; please provide the known import for this reference using option --import-mapping
+```
-We can see this at play with the following schemas:
+This is because `oapi-codegen` requires the `import-mapping`:
```yaml
-openapi: "3.0.0"
-info:
- version: 1.0.0
- title: x-enumNames and x-enum-varnames
-components:
- schemas:
- ClientType:
- type: string
- enum:
- - ACT
- - EXP
- ClientTypeWithNamesExtension:
- type: string
- enum:
- - ACT
- - EXP
- x-enumNames:
- - Active
- - Expired
- ClientTypeWithVarNamesExtension:
- type: string
- enum:
- - ACT
- - EXP
- x-enum-varnames:
- - Active
- - Expired
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: admin
+output: server.gen.go
+generate:
+ models: true
+ chi-server: true
+output-options:
+ # to make sure that all types are generated
+ skip-prune: true
+import-mapping:
+ # for a given file/URL that is $ref'd, point `oapi-codegen` to the Go package that this spec is generated into, to perform Go package imports
+ ../common/api.yaml: github.com/oapi-codegen/oapi-codegen/v2/examples/import-mapping/common
```
-From here, we now get two different forms of the same enum definition.
+This will then generate the following code:
```go
-// Defines values for ClientType.
-const (
- ACT ClientType = "ACT"
- EXP ClientType = "EXP"
-)
+package admin
-// Defines values for ClientTypeWithNamesExtension.
-const (
- ClientTypeWithNamesExtensionActive ClientTypeWithNamesExtension = "ACT"
- ClientTypeWithNamesExtensionExpired ClientTypeWithNamesExtension = "EXP"
+import (
+ // ...
+ externalRef0 "github.com/oapi-codegen/oapi-codegen/v2/examples/import-mapping/common"
)
-// Defines values for ClientTypeWithVarNamesExtension.
-const (
- ClientTypeWithVarNamesExtensionActive ClientTypeWithVarNamesExtension = "ACT"
- ClientTypeWithVarNamesExtensionExpired ClientTypeWithVarNamesExtension = "EXP"
-)
+// User defines model for User.
+type User = externalRef0.User
+```
-// ClientType defines model for ClientType.
-type ClientType string
+If you don't want to do this, an alternate option is to [use a single package, with multiple OpenAPI spec files for that given package](#import-mapping-self) or to [bundle your multiple OpenAPI files](https://www.jvt.me/posts/2022/02/10/bundle-openapi/) into a single spec.
-// ClientTypeWithNamesExtension defines model for ClientTypeWithNamesExtension.
-type ClientTypeWithNamesExtension string
+Check out [the import-mapping/multiplepackages example](examples/import-mapping/multiplepackages/) for the full code.
-// ClientTypeWithVarNamesExtension defines model for ClientTypeWithVarNamesExtension.
-type ClientTypeWithVarNamesExtension string
-```
+## Modifying the input OpenAPI Specification (with OpenAPI Overlay)
+
+Prior to `oapi-codegen` v2.4.0, users wishing to override specific configuration, for instance taking advantage of extensions such as `x-go-type` would need to modify the OpenAPI specification they are using.
+
+In a lot of cases, this OpenAPI specification would be produced by a different team to the consumers (or even a different company) and so asking them to make changes like this were unreasonable.
+
+This would lead to the API consumers needing to vendor the specification from the producer (which is [our recommendation anyway](#https-paths)) and then make any number of local changes to the specification to make it generate code that looks reasonable.
+
+However, in the case that a consumer would update their specification, they would likely end up with a number of merge conflicts.
-You can see this in more detail in [the example code](examples/extensions/xenumnames/).
+Now, as of `oapi-codegen` v2.4.0, it is now possible to make changes to the input OpenAPI specification _without needing to modify it directly_.
-### `x-deprecated-reason` - add a GoDoc deprecation warning to a type
+This takes advantage of the [OpenAPI Overlay specification](https://github.com/OAI/Overlay-Specification), which is a stable specification.
-When an OpenAPI type is deprecated, a deprecation warning can be added in the GoDoc using `x-deprecated-reason`.
+> [!CAUTION]
+> Beware! Here (may) be dragons.
+>
+> The Overlay specification requires the use of JSON Path, which some users may find difficult to write and/or maintain.
+>
+> We still heavily recommend using Overlay functionality, but would like users to be aware of this.
+>
+> There is a [proposed modification to the specification](https://github.com/OAI/Overlay-Specification/pull/32) which would relax the need for JSON Path as the targeting mechanism.
-We can see this at play with the following schemas:
+For instance, let's say that we have the following OpenAPI specification, which provides insight into an internal endpoint that we should not be generating any code for (denoted by `x-internal`):
```yaml
openapi: "3.0.0"
info:
version: 1.0.0
- title: x-deprecated-reason
-components:
- schemas:
- Client:
- type: object
- required:
- - name
- properties:
- name:
- type: string
- id:
- type: number
- ClientWithExtension:
- type: object
- required:
- - name
- properties:
- name:
- type: string
- deprecated: true
- x-deprecated-reason: Don't use because reasons
- id:
- type: number
- # NOTE that this doesn't generate, as no `deprecated: true` is set
- x-deprecated-reason: NOTE you shouldn't see this, as you've not deprecated this field
+ title: "Example to indicate how to use the OpenAPI Overlay specification (https://github.com/OAI/Overlay-Specification)"
+paths:
+ /ping:
+ get:
+ responses:
+ '200':
+ description: pet response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pong'
+ delete:
+ x-internal: true
+ responses:
+ '202':
+ content: {}
```
-From here, we now get two different forms of the same enum definition.
+If we were to run `oapi-codegen` with out-of-the-box functionality, this would then lead to the DELETE endpoint being generated, which we don't want.
-```go
-// Client defines model for Client.
-type Client struct {
- Id *float32 `json:"id,omitempty"`
- Name string `json:"name"`
-}
+Instead, we can define the following `overlay.yaml`:
-// ClientWithExtension defines model for ClientWithExtension.
-type ClientWithExtension struct {
- Id *float32 `json:"id,omitempty"`
- // Deprecated: Don't use because reasons
- Name string `json:"name"`
-}
+
+```yaml
+overlay: 1.0.0
+info:
+ title: Overlay
+ version: 0.0.0
+actions:
+- target: "$"
+ description: Perform a structural overlay, which can be more readable, as it's clear what the shape of the document is
+ update:
+ info:
+ x-overlay-applied: structured-overlay
+ paths:
+ /ping:
+ get:
+ responses:
+ '200':
+ description: Perform a ping request
+- target: $.paths.*[?(@.x-internal)]
+ description: Remove internal endpoints (noted by x-internal)
+ remove: true
+- target: $.paths.*.*[?(@.x-internal)]
+ description: Remove internal endpoints (noted by x-internal)
+ remove: true
+```
+
+And our configuration file for `oapi-codegen`:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: api
+output: ping.gen.go
+generate:
+ models: true
+ gorilla-server: true
+ embedded-spec: true
+output-options:
+ overlay:
+ path: overlay.yaml
```
-Notice that because we've not set `deprecated: true` to the `name` field, it doesn't generate a deprecation warning.
+This then completely removes the DELETE endpoint _before_ we even start to parse the specification in `oapi-codegen`, so it's as if your specification was provided without that endpoint.
-You can see this in more detail in [the example code](examples/extensions/xdeprecatedreason/).
+Additionally, we can override other pieces of metadata, such as the description for operations.
-### `x-order` - explicitly order struct fields
+Check out [the overlay example](examples/overlay/) for the full code, and some more complex examples.
-Whether you like certain fields being ordered before others, or you want to perform more efficient packing of your structs, the `x-order` extension is here for you.
+## Generating Nullable types
-Note that `x-order` is 1-indexed - `x-order: 0` is not a valid value.
+It's possible that you want to be able to determine whether a field isn't sent, is sent as `null` or has a value.
-We can see this at play with the following schemas:
+For instance, if you had the following OpenAPI property:
```yaml
-openapi: "3.0.0"
-info:
- version: 1.0.0
- title: x-order
-components:
- schemas:
- Client:
- type: object
- required:
- - name
- properties:
- a_name:
- type: string
- id:
- type: number
- ClientWithExtension:
- type: object
- required:
- - name
- properties:
- a_name:
- type: string
- x-order: 2
- id:
- type: number
- x-order: 1
+S:
+ type: object
+ properties:
+ Field:
+ type: string
+ nullable: true
+ required: []
```
-From here, we now get two different forms of the same type definition.
+The default behaviour in `oapi-codegen` is to generate:
```go
-// Client defines model for Client.
-type Client struct {
- AName *string `json:"a_name,omitempty"`
- Id *float32 `json:"id,omitempty"`
-}
-
-// ClientWithExtension defines model for ClientWithExtension.
-type ClientWithExtension struct {
- Id *float32 `json:"id,omitempty"`
- AName *string `json:"a_name,omitempty"`
+type S struct {
+ Field *string `json:"field,omitempty"`
}
```
-You can see this in more detail in [the example code](examples/extensions/xorder/).
-
-### `x-oapi-codegen-only-honour-go-name` - only honour the `x-go-name` when generating field names
-
-
-> [!WARNING]
-> Using this option may lead to cases where `oapi-codegen`'s rewriting of field names to prevent clashes with other types, or to prevent including characters that may not be valid Go field names.
+However, you lose the ability to understand the three cases, as there's no way to distinguish two of the types from each other:
-In some cases, you may not want use the inbuilt options for converting an OpenAPI field name to a Go field name, such as the `name-normalizer: "ToCamelCaseWithInitialisms"`, and instead trust the name that you've defined for the type better.
+- is this field not sent? (Can be checked with `S.Field == nil`)
+- is this field `null`? (Can be checked with `S.Field == nil`)
+- does this field have a value? (`S.Field != nil && *S.Field == "123"`)
-In this case, you can use `x-oapi-codegen-only-honour-go-name` to enforce this, alongside specifying the `allow-unexported-struct-field-names` compatibility option.
+As of `oapi-codegen` [v2.1.0](https://github.com/oapi-codegen/oapi-codegen/releases/tag/v2.1.0) it is now possible to represent this with the `nullable.Nullable` type from [our new library, oapi-codegen/nullable](https://github.com/oapi-codegen/nullable).
-This allows you to take a spec such as:
+If you configure your generator's Output Options to opt-in to this behaviour, as so:
```yaml
-openapi: "3.0.0"
-info:
- version: 1.0.0
- title: x-oapi-codegen-only-honour-go-name
-components:
- schemas:
- TypeWithUnexportedField:
- description: A struct will be output where one of the fields is not exported
- properties:
- name:
- type: string
- id:
- type: string
- # NOTE that there is an explicit usage of a lowercase character
- x-go-name: accountIdentifier
- x-oapi-codegen-extra-tags:
- json: "-"
- x-oapi-codegen-only-honour-go-name: true
+output-options:
+ nullable-type: true
```
-And we'll generate:
+You will now receive the following output:
```go
-// TypeWithUnexportedField A struct will be output where one of the fields is not exported
-type TypeWithUnexportedField struct {
- accountIdentifier *string `json:"-"`
- Name *string `json:"name,omitempty"`
+type S struct {
+ // note that there's no pointer here, just `omitempty`
+ Field nullable.Nullable[string] `json:"field,omitempty"`
}
```
-You can see this in more detail in [the example code](examples/extensions/xoapicodegenonlyhonourgoname).
+## OpenAPI extensions
+
+As well as the core OpenAPI support, we also support the following OpenAPI extensions, as denoted by the [OpenAPI Specification Extensions](https://spec.openapis.org/oas/v3.0.3#specification-extensions).
+
+The following extensions are supported:
+
+| Extension | Description | Docs |
+| --- | --- |-----------------------------------------------------------------------|
+| `x-go-type` / `x-go-type-import` | Override the generated type definition (and optionally, add an import from another package) | [(docs)](docs/extensions.md#x-go-type--x-go-type-import) |
+| `x-go-type-skip-optional-pointer` | Do not add a pointer type for optional fields in structs | [(docs)](docs/extensions.md#x-go-type-skip-optional-pointer) |
+| `x-go-name` | Override the generated name of a field or a type | [(docs)](docs/extensions.md#x-go-name) |
+| `x-go-type-name` | Override the generated name of a type | [(docs)](docs/extensions.md#x-go-type-name) |
+| `x-omitempty` | Force the presence of the JSON tag `omitempty` on a field | [(docs)](docs/extensions.md#x-omitempty) |
+| `x-omitzero` | Force the presence of the JSON tag `omitzero` on a field | [(docs)](docs/extensions.md#x-omitzero) |
+| `x-go-json-ignore` | When (un)marshaling JSON, ignore field(s) | [(docs)](docs/extensions.md#x-go-json-ignore) |
+| `x-oapi-codegen-extra-tags` | Generate arbitrary struct tags to fields | [(docs)](docs/extensions.md#x-oapi-codegen-extra-tags) |
+| `x-enum-varnames` / `x-enumNames` | Override generated variable names for enum constants | [(docs)](docs/extensions.md#x-enum-varnames--x-enumnames) |
+| `x-deprecated-reason` | Add a GoDoc deprecation warning to a type | [(docs)](docs/extensions.md#x-deprecated-reason) |
+| `x-order` | Explicitly order struct fields | [(docs)](docs/extensions.md#x-order) |
+| `x-oapi-codegen-only-honour-go-name` | Only honour the `x-go-name` when generating field names | [(docs)](docs/extensions.md#x-oapi-codegen-only-honour-go-name) |
## Request/response validation middleware
@@ -3332,9 +1468,6 @@ Any other server (which conforms to `net/http`)
> [!NOTE]
> It is [not currently possible](https://github.com/oapi-codegen/oapi-codegen/issues/1038) to validate the HTTP response with a middleware.
-> [!NOTE]
-> We're also [exploring](https://github.com/oapi-codegen/exp/issues/1) the use of [libopenapi-validator](https://github.com/pb33f/libopenapi-validator/) for request/response validation middleware
-
## Implementing security
If you're using a specification with [Security Schemes](https://spec.openapis.org/oas/v3.0.3#security-scheme-object) and [Security Requirements](https://spec.openapis.org/oas/v3.0.3#security-requirement-object), you'll want to authenticate and authorize requests.
diff --git a/docs/chi-server.md b/docs/chi-server.md
new file mode 100644
index 0000000000..255eabc3c1
--- /dev/null
+++ b/docs/chi-server.md
@@ -0,0 +1,140 @@
+# Chi Server
+
+For a Chi server, you will want a configuration file such as:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: api
+generate:
+ chi-server: true
+ models: true
+output: gen.go
+```
+
+## Generated code
+
+For instance, let's take this straightforward specification:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Minimal ping API server
+paths:
+ /ping:
+ get:
+ responses:
+ '200':
+ description: pet response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pong'
+components:
+ schemas:
+ # base types
+ Pong:
+ type: object
+ required:
+ - ping
+ properties:
+ ping:
+ type: string
+ example: pong
+```
+
+This then generates code such as:
+
+```go
+// Pong defines model for Pong.
+type Pong struct {
+ Ping string `json:"ping"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /ping)
+ GetPing(w http.ResponseWriter, r *http.Request)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r *mux.Router) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ // ...
+
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/ping", wrapper.GetPing)
+ })
+
+ return r
+}
+```
+
+To implement this HTTP server, we need to write the following code in our [`api/impl.go`](../examples/minimal-server/chi/api/impl.go):
+
+```go
+import (
+ "encoding/json"
+ "net/http"
+)
+
+// optional code omitted
+
+type Server struct{}
+
+func NewServer() Server {
+ return Server{}
+}
+
+// (GET /ping)
+func (Server) GetPing(w http.ResponseWriter, r *http.Request) {
+ resp := Pong{
+ Ping: "pong",
+ }
+
+ w.WriteHeader(http.StatusOK)
+ _ = json.NewEncoder(w).Encode(resp)
+}
+```
+
+Now we've got our implementation, we can then write the following code to wire it up and get a running server:
+
+```go
+import (
+ "log"
+ "net/http"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/chi/api"
+ "github.com/go-chi/chi/v5"
+)
+
+func main() {
+ // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
+ server := api.NewServer()
+
+ r := chi.NewMux()
+
+ // get an `http.Handler` that we can use
+ h := api.HandlerFromMux(server, r)
+
+ s := &http.Server{
+ Handler: h,
+ Addr: "0.0.0.0:8080",
+ }
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(s.ListenAndServe())
+}
+```
+
+> [!NOTE]
+> This doesn't include [validation of incoming requests](../README.md#requestresponse-validation-middleware).
diff --git a/docs/configuration.md b/docs/configuration.md
new file mode 100644
index 0000000000..392091b1df
--- /dev/null
+++ b/docs/configuration.md
@@ -0,0 +1,421 @@
+# Configuration Reference
+
+`oapi-codegen` is configured using a YAML configuration file. This document describes every available setting.
+
+You can also use [the JSON Schema](../configuration-schema.json) for IDE autocompletion:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: api
+# ...
+```
+
+# Example configuration with all settings
+
+Every setting is shown below with its default value. Click any setting name to jump to its documentation.
+
+
+# Required: Go package name
+package: api
+
+# What to generate (only one server type at a time)
+generate:
+ chi-server: false
+ echo-server: false
+ fiber-server: false
+ gin-server: false
+ gorilla-server: false
+ iris-server: false
+ std-http-server: false
+ strict-server: false
+ client: false
+ models: false
+ embedded-spec: false
+ server-urls: false
+
+# Backward compatibility settings
+compatibility:
+ old-merge-schemas: false
+ old-enum-conflicts: false
+ old-aliasing: false
+ disable-flatten-additional-properties: false
+ disable-required-readonly-as-pointer: false
+ always-prefix-enum-values: false
+ apply-chi-middleware-first-to-last: false
+ apply-gorilla-middleware-first-to-last: false
+ circular-reference-limit: 0
+ allow-unexported-struct-field-names: false
+ preserve-original-operation-id-casing-in-embedded-spec: false
+
+# Output modification options
+output-options:
+ include-tags: []
+ exclude-tags: []
+ include-operation-ids: []
+ exclude-operation-ids: []
+ exclude-schemas: []
+ skip-fmt: false
+ skip-prune: false
+ name-normalizer: ""
+ initialism-overrides: false
+ additional-initialisms: []
+ response-type-suffix: ""
+ client-type-name: ""
+ nullable-type: false
+ disable-type-aliases-for-type: []
+ resolve-type-name-collisions: false
+ prefer-skip-optional-pointer: false
+ prefer-skip-optional-pointer-with-omitzero: false
+ prefer-skip-optional-pointer-on-container-types: false
+ type-mapping:
+ integer:
+ default:
+ type: int
+ formats:
+ int: { type: int }
+ int8: { type: int8 }
+ int16: { type: int16 }
+ int32: { type: int32 }
+ int64: { type: int64 }
+ uint: { type: uint }
+ uint8: { type: uint8 }
+ uint16: { type: uint16 }
+ uint32: { type: uint32 }
+ uint64: { type: uint64 }
+ number:
+ default:
+ type: float32
+ formats:
+ float: { type: float32 }
+ double: { type: float64 }
+ boolean:
+ default:
+ type: bool
+ string:
+ default:
+ type: string
+ formats:
+ byte: { type: "[]byte" }
+ email: { type: openapi_types.Email }
+ date: { type: openapi_types.Date }
+ date-time: { type: time.Time, import: time }
+ json: { type: json.RawMessage, import: encoding/json }
+ uuid: { type: openapi_types.UUID }
+ binary: { type: openapi_types.File }
+ yaml-tags: false
+ client-response-bytes-function: false
+ user-templates: {}
+ overlay:
+ path: ""
+ strict: true
+
+# External reference to Go package mapping
+import-mapping: {}
+
+# Additional Go imports
+additional-imports: []
+
+
+# `package`
+
+The Go package name for the generated code. This is the only required setting.
+
+```yaml
+package: api
+```
+
+# `import-mapping`
+
+Maps external OpenAPI `$ref` paths to Go package import paths. Used when splitting specs across multiple packages.
+
+```yaml
+import-mapping:
+ common.yaml: github.com/myorg/myproject/api/common
+ auth.yaml: github.com/myorg/myproject/api/auth
+```
+
+# `additional-imports`
+
+Defines additional Go imports to add to the generated code.
+
+```yaml
+additional-imports:
+ - alias: mylib
+ package: github.com/myorg/mylib
+```
+
+Each entry has:
+- `package` (required): the Go import path
+- `alias` (optional): an import alias
+
+# Generate options
+
+These are specified under the `generate` key. Only one server type may be enabled at a time.
+
+If the `generate` block is omitted entirely, it defaults to generating an Echo server with models and an embedded spec.
+
+## Server types
+
+| Setting | Description |
+| --- | --- |
+| `chi-server` | Generate [Chi](https://github.com/go-chi/chi) server boilerplate |
+| `echo-server` | Generate [Echo](https://github.com/labstack/echo) server boilerplate |
+| `fiber-server` | Generate [Fiber](https://github.com/gofiber/fiber) server boilerplate |
+| `gin-server` | Generate [Gin](https://github.com/gin-gonic/gin) server boilerplate |
+| `gorilla-server` | Generate [gorilla/mux](https://github.com/gorilla/mux) server boilerplate |
+| `iris-server` | Generate [Iris](https://github.com/kataras/iris) server boilerplate |
+| `std-http-server` | Generate Go 1.22+ `net/http` server boilerplate |
+
+## Other generate flags
+
+| Setting | Description |
+| --- | --- |
+| `strict-server` | Generate a strict server wrapper. Must be used alongside one of the server types above. |
+| `client` | Generate API client boilerplate |
+| `models` | Generate Go type definitions from OpenAPI schemas |
+| `embedded-spec` | Embed the OpenAPI spec in the generated code |
+| `server-urls` | Generate types for the `servers` definitions' URLs |
+
+# Compatibility options
+
+These are specified under the `compatibility` key. They exist to preserve backward-compatible behavior when a bug fix or improvement changes generated output.
+
+## `old-merge-schemas`
+
+Reverts to the old behavior for `allOf` schema merging, which inlined each schema within the schema list rather than merging at the schema definition level. See [#531](https://github.com/oapi-codegen/oapi-codegen/issues/531).
+
+## `old-enum-conflicts`
+
+Reverts to old behavior for enum type naming that could produce conflicting typenames. See [#549](https://github.com/oapi-codegen/oapi-codegen/issues/549).
+
+## `old-aliasing`
+
+Reverts to generating a full Go type definition for every `$ref` instead of using type aliases where possible. See [#549](https://github.com/oapi-codegen/oapi-codegen/issues/549).
+
+## `disable-flatten-additional-properties`
+
+When an object contains no members and only an `additionalProperties` specification, it is normally flattened to a map. Set this to `true` to disable that behavior.
+
+## `disable-required-readonly-as-pointer`
+
+When an object property is both `required` and `readOnly`, the generated Go model uses a pointer by default. Set this to `true` to generate non-pointer types instead. See [#604](https://github.com/oapi-codegen/oapi-codegen/issues/604).
+
+## `always-prefix-enum-values`
+
+When set to `true`, always prefix enum constant variable names with their type name, even when there are no naming conflicts.
+
+## `apply-chi-middleware-first-to-last`
+
+Fixes the ordering of Chi middleware so they are chained in the order they are invoked, rather than the historically inverted order. See [#786](https://github.com/oapi-codegen/oapi-codegen/issues/786).
+
+## `apply-gorilla-middleware-first-to-last`
+
+Fixes the ordering of gorilla/mux middleware so they are chained in the order they are invoked, rather than the historically inverted order. See [#841](https://github.com/oapi-codegen/oapi-codegen/issues/841).
+
+## `circular-reference-limit`
+
+> **Deprecated**: In kin-openapi v0.126.0, the Circular Reference Counter functionality was removed, resolving all references with backtracking instead.
+
+Allows controlling the limit for circular reference checking in older versions.
+
+## `allow-unexported-struct-field-names`
+
+Makes it possible to output structs that have unexported (lowercase) fields. Expected to be used in conjunction with `x-go-name`, `x-oapi-codegen-only-honour-go-name`, and `x-oapi-codegen-extra-tags`.
+
+Example use case:
+
+```yaml
+# In your OpenAPI spec:
+id:
+ type: string
+ x-go-name: accountIdentifier
+ x-oapi-codegen-extra-tags:
+ json: "-"
+ x-oapi-codegen-only-honour-go-name: true
+```
+
+> [!NOTE]
+> This can be confusing to users of your OpenAPI specification, who may see a field present and expect to use it in the request/response.
+
+## `preserve-original-operation-id-casing-in-embedded-spec`
+
+Ensures that the `operationId` from the source spec is kept intact in the embedded spec output, rather than having the `name-normalizer` applied to it. This keeps the embedded OpenAPI specification in sync with the input specification.
+
+> [!NOTE]
+> This does not impact generated code. If you're using `include-operation-ids` or `exclude-operation-ids`, ensure the `operationId`s used are correct.
+
+# Output options
+
+These are specified under the `output-options` key.
+
+## Filtering
+
+| Setting | Type | Description |
+| --- | --- | --- |
+| `include-tags` | `[]string` | Only include operations that have one of these tags. Ignored when empty. |
+| `exclude-tags` | `[]string` | Exclude operations that have one of these tags. Ignored when empty. |
+| `include-operation-ids` | `[]string` | Only include operations that have one of these operation IDs. Ignored when empty. |
+| `exclude-operation-ids` | `[]string` | Exclude operations that have one of these operation IDs. Ignored when empty. |
+| `exclude-schemas` | `[]string` | Exclude schemas with the given names from generation. Ignored when empty. |
+
+## Formatting and pruning
+
+| Setting | Type | Description |
+| --- | --- | --- |
+| `skip-fmt` | `bool` | Skip running `goimports` on the generated code |
+| `skip-prune` | `bool` | Skip pruning unused components from the generated code |
+
+## Naming
+
+| Setting | Type | Description |
+| --- | --- | --- |
+| `name-normalizer` | `string` | Method used to normalize Go names and types. See [name normalizer values](#name-normalizer-values) below. |
+| `initialism-overrides` | `bool` | Whether to use initialism overrides (e.g., `HTTP`, `API`) |
+| `additional-initialisms` | `[]string` | Additional initialisms to recognize. Only has effect when `name-normalizer` is set to `ToCamelCaseWithInitialisms`. |
+| `response-type-suffix` | `string` | Suffix used for response types |
+| `client-type-name` | `string` | Override the default generated client type name |
+
+### Name normalizer values
+
+| Value | Example: `getHttpPet` | Example: `OneOf2things` |
+| --- | --- | --- |
+| (unset / `ToCamelCase`) | `GetHttpPet` | `OneOf2things` |
+| `ToCamelCaseWithDigits` | `GetHttpPet` | `OneOf2Things` |
+| `ToCamelCaseWithInitialisms` | `GetHTTPPet` | `OneOf2things` |
+
+## Type generation
+
+| Setting | Type | Description |
+| --- | --- | --- |
+| `nullable-type` | `bool` | Generate nullable types for nullable fields |
+| `disable-type-aliases-for-type` | `[]string` | OpenAPI types that will not use type aliases. Currently supports: `"array"`. |
+| `resolve-type-name-collisions` | `bool` | Automatically rename types that collide across different OpenAPI component sections by appending a suffix (e.g., `Parameter`, `Response`). Without this, codegen errors on duplicate type names. |
+| `prefer-skip-optional-pointer` | `bool` | Globally omit the pointer for optional fields/types. Same as adding `x-go-type-skip-optional-pointer` to every field. |
+| `prefer-skip-optional-pointer-with-omitzero` | `bool` | Generate the `omitzero` JSON tag for types that would have had an optional pointer. Must be used alongside `prefer-skip-optional-pointer`. A field can set `x-omitzero: false` to opt out. |
+| `prefer-skip-optional-pointer-on-container-types` | `bool` | Disable the "optional pointer" for optional container types (slices, maps), avoiding unnecessary `!= nil` checks. |
+
+## Type mapping
+
+The `type-mapping` setting allows customizing how OpenAPI type/format combinations map to Go types. User-specified mappings are merged on top of the defaults.
+
+```yaml
+output-options:
+ type-mapping:
+ string:
+ formats:
+ date-time:
+ type: mycustomtime.Time
+ import: github.com/myorg/mycustomtime
+ integer:
+ default:
+ type: int64
+```
+
+The structure is:
+
+```yaml
+type-mapping:
+ : # integer, number, boolean, string
+ default:
+ type:
+ import: # optional
+ formats:
+ :
+ type:
+ import: # optional
+```
+
+The default mappings are:
+
+```yaml
+type-mapping:
+ integer:
+ default:
+ type: int
+ formats:
+ int:
+ type: int
+ int8:
+ type: int8
+ int16:
+ type: int16
+ int32:
+ type: int32
+ int64:
+ type: int64
+ uint:
+ type: uint
+ uint8:
+ type: uint8
+ uint16:
+ type: uint16
+ uint32:
+ type: uint32
+ uint64:
+ type: uint64
+ number:
+ default:
+ type: float32
+ formats:
+ float:
+ type: float32
+ double:
+ type: float64
+ boolean:
+ default:
+ type: bool
+ string:
+ default:
+ type: string
+ formats:
+ byte:
+ type: "[]byte"
+ email:
+ type: openapi_types.Email
+ date:
+ type: openapi_types.Date
+ date-time:
+ type: time.Time
+ import: time
+ json:
+ type: json.RawMessage
+ import: encoding/json
+ uuid:
+ type: openapi_types.UUID
+ binary:
+ type: openapi_types.File
+```
+
+## Tags
+
+| Setting | Type | Description |
+| --- | --- | --- |
+| `yaml-tags` | `bool` | Add YAML struct tags to generated types, in addition to the default JSON tags |
+
+## Client options
+
+| Setting | Type | Description |
+| --- | --- | --- |
+| `client-response-bytes-function` | `bool` | Generate a `Bytes()` method on response objects for `ClientWithResponses` |
+
+## Templates
+
+| Setting | Type | Description |
+| --- | --- | --- |
+| `user-templates` | `map[string]string` | Override built-in templates with user-provided files. Keys are template names, values are file paths. |
+
+## Overlay
+
+The `overlay` setting configures an [OpenAPI Overlay](https://github.com/OAI/Overlay-Specification) to modify the spec before generation.
+
+```yaml
+output-options:
+ overlay:
+ path: overlay.yaml
+ strict: true
+```
+
+| Setting | Type | Description |
+| --- | --- | --- |
+| `overlay.path` | `string` | Path to the overlay file |
+| `overlay.strict` | `bool` | When `true` (the default), highlights any overlay actions that have no effect. Set to `false` to suppress these warnings. |
diff --git a/docs/echo-server.md b/docs/echo-server.md
new file mode 100644
index 0000000000..72de394b43
--- /dev/null
+++ b/docs/echo-server.md
@@ -0,0 +1,136 @@
+# Echo Server
+
+For an Echo server, you will want a configuration file such as:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: api
+generate:
+ echo-server: true
+ models: true
+output: gen.go
+```
+
+## Generated code
+
+For instance, let's take this straightforward specification:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Minimal ping API server
+paths:
+ /ping:
+ get:
+ responses:
+ '200':
+ description: pet response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pong'
+components:
+ schemas:
+ # base types
+ Pong:
+ type: object
+ required:
+ - ping
+ properties:
+ ping:
+ type: string
+ example: pong
+```
+
+This then generates code such as:
+
+```go
+// Pong defines model for Pong.
+type Pong struct {
+ Ping string `json:"ping"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /ping)
+ GetPing(ctx echo.Context) error
+}
+
+// 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
+type EchoRouter interface {
+ // ...
+ GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ // ...
+}
+
+// RegisterHandlers adds each server route to the EchoRouter.
+func RegisterHandlers(router EchoRouter, si ServerInterface) {
+ RegisterHandlersWithBaseURL(router, si, "")
+}
+
+// Registers handlers, and prepends BaseURL to the paths, so that the paths
+// can be served under a prefix.
+func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ // ...
+
+ router.GET(baseURL+"/ping", wrapper.GetPing)
+
+}
+```
+
+To implement this HTTP server, we need to write the following code in our [`api/impl.go`](../examples/minimal-server/echo/api/impl.go):
+
+```go
+import (
+ "net/http"
+
+ "github.com/labstack/echo/v4"
+)
+
+// optional code omitted
+
+type Server struct{}
+
+func NewServer() Server {
+ return Server{}
+}
+
+// (GET /ping)
+func (Server) GetPing(ctx echo.Context) error {
+ resp := Pong{
+ Ping: "pong",
+ }
+
+ return ctx.JSON(http.StatusOK, resp)
+}
+```
+
+Now we've got our implementation, we can then write the following code to wire it up and get a running server:
+
+```go
+import (
+ "log"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/echo/api"
+ "github.com/labstack/echo/v4"
+)
+
+func main() {
+ // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
+ server := api.NewServer()
+
+ e := echo.New()
+
+ api.RegisterHandlers(e, server)
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(e.Start("0.0.0.0:8080"))
+}
+```
+
+> [!NOTE]
+> This doesn't include [validation of incoming requests](../README.md#requestresponse-validation-middleware).
diff --git a/docs/echo5-server.md b/docs/echo5-server.md
new file mode 100644
index 0000000000..6185f77d58
--- /dev/null
+++ b/docs/echo5-server.md
@@ -0,0 +1,139 @@
+# Echo v5 Server
+
+For an Echo v5 server, you will want a configuration file such as:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: api
+generate:
+ echo5-server: true
+ models: true
+output: gen.go
+```
+
+## Generated code
+
+For instance, let's take this straightforward specification:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Minimal ping API server
+paths:
+ /ping:
+ get:
+ responses:
+ '200':
+ description: pet response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pong'
+components:
+ schemas:
+ # base types
+ Pong:
+ type: object
+ required:
+ - ping
+ properties:
+ ping:
+ type: string
+ example: pong
+```
+
+This then generates code such as:
+
+```go
+// Pong defines model for Pong.
+type Pong struct {
+ Ping string `json:"ping"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /ping)
+ GetPing(ctx *echo.Context) error
+}
+
+// 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
+type EchoRouter interface {
+ // ...
+ GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+ // ...
+}
+
+// RegisterHandlers adds each server route to the EchoRouter.
+func RegisterHandlers(router EchoRouter, si ServerInterface) {
+ RegisterHandlersWithBaseURL(router, si, "")
+}
+
+// Registers handlers, and prepends BaseURL to the paths, so that the paths
+// can be served under a prefix.
+func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ // ...
+
+ router.GET(baseURL+"/ping", wrapper.GetPing)
+
+}
+```
+
+To implement this HTTP server, we need to write the following code in our `api/impl.go`:
+
+```go
+import (
+ "net/http"
+
+ "github.com/labstack/echo/v5"
+)
+
+// optional code omitted
+
+type Server struct{}
+
+func NewServer() Server {
+ return Server{}
+}
+
+// (GET /ping)
+func (Server) GetPing(ctx *echo.Context) error {
+ resp := Pong{
+ Ping: "pong",
+ }
+
+ return ctx.JSON(http.StatusOK, resp)
+}
+```
+
+Now we've got our implementation, we can then write the following code to wire it up and get a running server:
+
+```go
+import (
+ "log"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/echo-v5/api"
+ "github.com/labstack/echo/v5"
+)
+
+func main() {
+ // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
+ server := api.NewServer()
+
+ e := echo.New()
+
+ api.RegisterHandlers(e, server)
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(e.Start("0.0.0.0:8080"))
+}
+```
+
+> [!NOTE]
+> Echo v5 changes `echo.Context` from an interface to a concrete struct, so handler signatures use `*echo.Context` (pointer) instead of `echo.Context`.
+
+> [!NOTE]
+> This doesn't include [validation of incoming requests](../README.md#requestresponse-validation-middleware).
diff --git a/docs/extensions.md b/docs/extensions.md
new file mode 100644
index 0000000000..6c509b9188
--- /dev/null
+++ b/docs/extensions.md
@@ -0,0 +1,725 @@
+# OpenAPI Extensions
+
+As well as the core OpenAPI support, `oapi-codegen` also supports the following OpenAPI extensions, as denoted by the [OpenAPI Specification Extensions](https://spec.openapis.org/oas/v3.0.3#specification-extensions).
+
+## `x-go-type` / `x-go-type-import`
+
+Override the generated type definition (and optionally, add an import from another package).
+
+Using the `x-go-type` (and optionally, `x-go-type-import` when you need to import another package) allows overriding the type that `oapi-codegen` determined the generated type should be.
+
+We can see this at play with the following schemas:
+
+```yaml
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ # this is a bit of a contrived example, as you could instead use
+ # `format: uuid` but it explains how you'd do this when there may be
+ # a clash, for instance if you already had a `uuid` package that was
+ # being imported, or ...
+ x-go-type: googleuuid.UUID
+ x-go-type-import:
+ path: github.com/google/uuid
+ name: googleuuid
+ id:
+ type: number
+ # ... this is also a bit of a contrived example, as you could use
+ # `type: integer` but in the case that you know better than what
+ # oapi-codegen is generating, like so:
+ x-go-type: int64
+```
+
+From here, we now get two different models:
+
+```go
+// Client defines model for Client.
+type Client struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ Id *int64 `json:"id,omitempty"`
+ Name googleuuid.UUID `json:"name"`
+}
+```
+
+You can see this in more detail in [the example code](../examples/extensions/xgotype/).
+
+## `x-go-type-skip-optional-pointer`
+
+Do not add a pointer type for optional fields in structs.
+
+> [!TIP]
+> If you prefer this behaviour, and prefer to not have to annotate your whole OpenAPI spec for this behaviour, you can use `output-options.prefer-skip-optional-pointer=true` to default this behaviour for all fields.
+>
+> It is then possible to override this on a per-type/per-field basis where necessary.
+
+By default, `oapi-codegen` will generate a pointer for optional fields.
+
+Using the `x-go-type-skip-optional-pointer` extension allows omitting that pointer.
+
+We can see this at play with the following schemas:
+
+```yaml
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ x-go-type-skip-optional-pointer: true
+```
+
+From here, we now get two different models:
+
+```go
+// Client defines model for Client.
+type Client struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ Id float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+```
+
+You can see this in more detail in [the example code](../examples/extensions/xgotypeskipoptionalpointer/).
+
+## `x-go-name`
+
+Override the generated name of a field or a type.
+
+By default, `oapi-codegen` will attempt to generate the name of fields and types in as best a way it can.
+
+However, sometimes, the name doesn't quite fit what your codebase standards are, or the intent of the field, so you can override it with `x-go-name`.
+
+We can see this at play with the following schemas:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-go-name
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ # can be used on a type
+ x-go-name: ClientRenamedByExtension
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ # or on a field
+ x-go-name: AccountIdentifier
+```
+
+From here, we now get two different models:
+
+```go
+// Client defines model for Client.
+type Client struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+
+// ClientRenamedByExtension defines model for ClientWithExtension.
+type ClientRenamedByExtension struct {
+ AccountIdentifier *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+```
+
+You can see this in more detail in [the example code](../examples/extensions/xgoname/).
+
+## `x-go-type-name`
+
+Override the generated name of a type.
+
+> [!NOTE]
+> Notice that this is subtly different to the `x-go-name`, which also applies to _fields_ within `struct`s.
+
+By default, `oapi-codegen` will attempt to generate the name of types in as best a way it can.
+
+However, sometimes, the name doesn't quite fit what your codebase standards are, or the intent of the field, so you can override it with `x-go-name`.
+
+We can see this at play with the following schemas:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-go-type-name
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ x-go-type-name: ClientRenamedByExtension
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ # NOTE attempting a `x-go-type-name` here is a no-op, as we're not producing a _type_ only a _field_
+ x-go-type-name: ThisWillNotBeUsed
+```
+
+From here, we now get two different models and a type alias:
+
+```go
+// Client defines model for Client.
+type Client struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension = ClientRenamedByExtension
+
+// ClientRenamedByExtension defines model for .
+type ClientRenamedByExtension struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+```
+
+You can see this in more detail in [the example code](../examples/extensions/xgotypename/).
+
+## `x-omitempty`
+
+Force the presence of the JSON tag `omitempty` on a field.
+
+In a case that you may want to add the JSON struct tag `omitempty` to types that don't have one generated by default - for instance a required field - you can use the `x-omitempty` extension.
+
+We can see this at play with the following schemas:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-omitempty
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ # for some reason, you may want this behaviour, even though it's a required field
+ x-omitempty: true
+ id:
+ type: number
+```
+
+From here, we now get two different models:
+
+```go
+// Client defines model for Client.
+type Client struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name,omitempty"`
+}
+```
+
+You can see this in more detail in [the example code](../examples/extensions/xomitempty/).
+
+## `x-omitzero`
+
+Force the presence of the JSON tag `omitzero` on a field.
+
+> [!NOTE]
+> `omitzero` was added in Go 1.24. If you're not using Go 1.24 in your project, this won't work.
+
+In a case that you may want to add the JSON struct tag `omitzero` to types, you can use the `x-omitempty` extension.
+
+We can see this at play with the following schemas:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-omitempty
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ x-omitzero: true
+```
+
+From here, we now get two different models:
+
+```go
+// Client defines model for Client.
+type Client struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ Id *float32 `json:"id,omitempty,omitzero"`
+ Name string `json:"name"`
+}
+```
+
+You can see this in more detail in [the example code](../examples/extensions/xomitzero/).
+
+## `x-go-json-ignore`
+
+When (un)marshaling JSON, ignore field(s).
+
+By default, `oapi-codegen` will generate `json:"..."` struct tags for all fields in a struct, so JSON (un)marshaling works.
+
+However, sometimes, you want to omit fields, which can be done with the `x-go-json-ignore` extension.
+
+We can see this at play with the following schemas:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-go-json-ignore
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ complexField:
+ type: object
+ properties:
+ name:
+ type: string
+ accountName:
+ type: string
+ # ...
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ complexField:
+ type: object
+ properties:
+ name:
+ type: string
+ accountName:
+ type: string
+ # ...
+ x-go-json-ignore: true
+```
+
+From here, we now get two different models:
+
+```go
+// Client defines model for Client.
+type Client struct {
+ ComplexField *struct {
+ AccountName *string `json:"accountName,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"complexField,omitempty"`
+ Name string `json:"name"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ ComplexField *struct {
+ AccountName *string `json:"accountName,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"-"`
+ Name string `json:"name"`
+}
+```
+
+Notice that the `ComplexField` is still generated in full, but the type will then be ignored with JSON marshalling.
+
+You can see this in more detail in [the example code](../examples/extensions/xgojsonignore/).
+
+## `x-oapi-codegen-extra-tags`
+
+Generate arbitrary struct tags to fields.
+
+If you're making use of a field's struct tags to i.e. apply validation, decide whether something should be logged, etc, you can use `x-oapi-codegen-extra-tags` to set additional tags for your generated types.
+
+We can see this at play with the following schemas:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-oapi-codegen-extra-tags
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ - id
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ - id
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ x-oapi-codegen-extra-tags:
+ validate: "required,min=1,max=256"
+ safe-to-log: "true"
+ gorm: primarykey
+```
+
+From here, we now get two different models:
+
+```go
+// Client defines model for Client.
+type Client struct {
+ Id float32 `json:"id"`
+ Name string `json:"name"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ Id float32 `gorm:"primarykey" json:"id" safe-to-log:"true" validate:"required,min=1,max=256"`
+ Name string `json:"name"`
+}
+```
+
+You can see this in more detail in [the example code](../examples/extensions/xoapicodegenextratags/).
+
+## `x-enum-varnames` / `x-enumNames`
+
+Override generated variable names for enum constants.
+
+When consuming an enum value from an external system, the name may not produce a nice variable name. Using the `x-enum-varnames` extension allows overriding the name of the generated variable names.
+
+We can see this at play with the following schemas:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-enumNames and x-enum-varnames
+components:
+ schemas:
+ ClientType:
+ type: string
+ enum:
+ - ACT
+ - EXP
+ ClientTypeWithNamesExtension:
+ type: string
+ enum:
+ - ACT
+ - EXP
+ x-enumNames:
+ - Active
+ - Expired
+ ClientTypeWithVarNamesExtension:
+ type: string
+ enum:
+ - ACT
+ - EXP
+ x-enum-varnames:
+ - Active
+ - Expired
+```
+
+From here, we now get two different forms of the same enum definition.
+
+```go
+// Defines values for ClientType.
+const (
+ ACT ClientType = "ACT"
+ EXP ClientType = "EXP"
+)
+
+// Defines values for ClientTypeWithNamesExtension.
+const (
+ ClientTypeWithNamesExtensionActive ClientTypeWithNamesExtension = "ACT"
+ ClientTypeWithNamesExtensionExpired ClientTypeWithNamesExtension = "EXP"
+)
+
+// Defines values for ClientTypeWithVarNamesExtension.
+const (
+ ClientTypeWithVarNamesExtensionActive ClientTypeWithVarNamesExtension = "ACT"
+ ClientTypeWithVarNamesExtensionExpired ClientTypeWithVarNamesExtension = "EXP"
+)
+
+// ClientType defines model for ClientType.
+type ClientType string
+
+// ClientTypeWithNamesExtension defines model for ClientTypeWithNamesExtension.
+type ClientTypeWithNamesExtension string
+
+// ClientTypeWithVarNamesExtension defines model for ClientTypeWithVarNamesExtension.
+type ClientTypeWithVarNamesExtension string
+```
+
+You can see this in more detail in [the example code](../examples/extensions/xenumnames/).
+
+## `x-deprecated-reason`
+
+Add a GoDoc deprecation warning to a type.
+
+When an OpenAPI type is deprecated, a deprecation warning can be added in the GoDoc using `x-deprecated-reason`.
+
+We can see this at play with the following schemas:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-deprecated-reason
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ deprecated: true
+ x-deprecated-reason: Don't use because reasons
+ id:
+ type: number
+ # NOTE that this doesn't generate, as no `deprecated: true` is set
+ x-deprecated-reason: NOTE you shouldn't see this, as you've not deprecated this field
+```
+
+From here, we now get two different forms of the same enum definition.
+
+```go
+// Client defines model for Client.
+type Client struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ Id *float32 `json:"id,omitempty"`
+ // Deprecated: Don't use because reasons
+ Name string `json:"name"`
+}
+```
+
+Notice that because we've not set `deprecated: true` to the `name` field, it doesn't generate a deprecation warning.
+
+You can see this in more detail in [the example code](../examples/extensions/xdeprecatedreason/).
+
+## `x-order`
+
+Explicitly order struct fields.
+
+Whether you like certain fields being ordered before others, or you want to perform more efficient packing of your structs, the `x-order` extension is here for you.
+
+Note that `x-order` is 1-indexed - `x-order: 0` is not a valid value.
+
+We can see this at play with the following schemas:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-order
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ a_name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ properties:
+ a_name:
+ type: string
+ x-order: 2
+ id:
+ type: number
+ x-order: 1
+```
+
+From here, we now get two different forms of the same type definition.
+
+```go
+// Client defines model for Client.
+type Client struct {
+ AName *string `json:"a_name,omitempty"`
+ Id *float32 `json:"id,omitempty"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ Id *float32 `json:"id,omitempty"`
+ AName *string `json:"a_name,omitempty"`
+}
+```
+
+You can see this in more detail in [the example code](../examples/extensions/xorder/).
+
+## `x-oapi-codegen-only-honour-go-name`
+
+Only honour the `x-go-name` when generating field names.
+
+> [!WARNING]
+> Using this option may lead to cases where `oapi-codegen`'s rewriting of field names to prevent clashes with other types, or to prevent including characters that may not be valid Go field names.
+
+In some cases, you may not want use the inbuilt options for converting an OpenAPI field name to a Go field name, such as the `name-normalizer: "ToCamelCaseWithInitialisms"`, and instead trust the name that you've defined for the type better.
+
+In this case, you can use `x-oapi-codegen-only-honour-go-name` to enforce this, alongside specifying the `allow-unexported-struct-field-names` compatibility option.
+
+This allows you to take a spec such as:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-oapi-codegen-only-honour-go-name
+components:
+ schemas:
+ TypeWithUnexportedField:
+ description: A struct will be output where one of the fields is not exported
+ properties:
+ name:
+ type: string
+ id:
+ type: string
+ # NOTE that there is an explicit usage of a lowercase character
+ x-go-name: accountIdentifier
+ x-oapi-codegen-extra-tags:
+ json: "-"
+ x-oapi-codegen-only-honour-go-name: true
+```
+
+And we'll generate:
+
+```go
+// TypeWithUnexportedField A struct will be output where one of the fields is not exported
+type TypeWithUnexportedField struct {
+ accountIdentifier *string `json:"-"`
+ Name *string `json:"name,omitempty"`
+}
+```
+
+You can see this in more detail in [the example code](../examples/extensions/xoapicodegenonlyhonourgoname).
diff --git a/docs/fiber-server.md b/docs/fiber-server.md
new file mode 100644
index 0000000000..0658c81279
--- /dev/null
+++ b/docs/fiber-server.md
@@ -0,0 +1,128 @@
+# Fiber Server
+
+For a Fiber server, you will want a configuration file such as:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: api
+generate:
+ fiber-server: true
+ models: true
+output: gen.go
+```
+
+## Generated code
+
+For instance, let's take this straightforward specification:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Minimal ping API server
+paths:
+ /ping:
+ get:
+ responses:
+ '200':
+ description: pet response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pong'
+components:
+ schemas:
+ # base types
+ Pong:
+ type: object
+ required:
+ - ping
+ properties:
+ ping:
+ type: string
+ example: pong
+```
+
+This then generates code such as:
+
+```go
+// Pong defines model for Pong.
+type Pong struct {
+ Ping string `json:"ping"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /ping)
+ GetPing(c *fiber.Ctx) error
+}
+
+// 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) {
+ // ...
+
+ router.Get(options.BaseURL+"/ping", wrapper.GetPing)
+}
+```
+
+To implement this HTTP server, we need to write the following code in our [`api/impl.go`](../examples/minimal-server/fiber/api/impl.go):
+
+```go
+import (
+ "net/http"
+
+ "github.com/gofiber/fiber/v2"
+)
+
+// ensure that we've conformed to the `ServerInterface` with a compile-time check
+var _ ServerInterface = (*Server)(nil)
+
+type Server struct{}
+
+func NewServer() Server {
+ return Server{}
+}
+
+// (GET /ping)
+func (Server) GetPing(ctx *fiber.Ctx) error {
+ resp := Pong{
+ Ping: "pong",
+ }
+
+ return ctx.
+ Status(http.StatusOK).
+ JSON(resp)
+}
+```
+
+Now we've got our implementation, we can then write the following code to wire it up and get a running server:
+
+```go
+import (
+ "log"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/fiber/api"
+ "github.com/gofiber/fiber/v2"
+)
+
+func main() {
+ // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
+ server := api.NewServer()
+
+ app := fiber.New()
+
+ api.RegisterHandlers(app, server)
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(app.Listen("0.0.0.0:8080"))
+}
+```
+
+> [!NOTE]
+> This doesn't include [validation of incoming requests](../README.md#requestresponse-validation-middleware).
diff --git a/docs/gin-server.md b/docs/gin-server.md
new file mode 100644
index 0000000000..e4737227f2
--- /dev/null
+++ b/docs/gin-server.md
@@ -0,0 +1,133 @@
+# Gin Server
+
+For a Gin server, you will want a configuration file such as:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: api
+generate:
+ gin-server: true
+ models: true
+output: gen.go
+```
+
+## Generated code
+
+For instance, let's take this straightforward specification:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Minimal ping API server
+paths:
+ /ping:
+ get:
+ responses:
+ '200':
+ description: pet response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pong'
+components:
+ schemas:
+ # base types
+ Pong:
+ type: object
+ required:
+ - ping
+ properties:
+ ping:
+ type: string
+ example: pong
+```
+
+This then generates code such as:
+
+```go
+// Pong defines model for Pong.
+type Pong struct {
+ Ping string `json:"ping"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /ping)
+ GetPing(c *gin.Context)
+}
+
+// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
+func RegisterHandlers(router gin.IRouter, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, GinServerOptions{})
+}
+
+// RegisterHandlersWithOptions creates http.Handler with additional options
+func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options GinServerOptions) {
+ // ...
+
+ router.GET(options.BaseURL+"/ping", wrapper.GetPing)
+}
+```
+
+To implement this HTTP server, we need to write the following code in our [`api/impl.go`](../examples/minimal-server/gin/api/impl.go):
+
+```go
+import (
+ "net/http"
+
+ "github.com/gin-gonic/gin"
+)
+
+// optional code omitted
+
+type Server struct{}
+
+func NewServer() Server {
+ return Server{}
+}
+
+// (GET /ping)
+func (Server) GetPing(ctx *gin.Context) {
+ resp := Pong{
+ Ping: "pong",
+ }
+
+ ctx.JSON(http.StatusOK, resp)
+}
+```
+
+Now we've got our implementation, we can then write the following code to wire it up and get a running server:
+
+```go
+import (
+ "log"
+ "net/http"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/gin/api"
+ "github.com/gin-gonic/gin"
+)
+
+func main() {
+ // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
+ server := api.NewServer()
+
+ r := gin.Default()
+
+ api.RegisterHandlers(r, server)
+
+ // And we serve HTTP until the world ends.
+
+ s := &http.Server{
+ Handler: r,
+ Addr: "0.0.0.0:8080",
+ }
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(s.ListenAndServe())
+}
+```
+
+> [!NOTE]
+> This doesn't include [validation of incoming requests](../README.md#requestresponse-validation-middleware).
diff --git a/docs/gorilla-server.md b/docs/gorilla-server.md
new file mode 100644
index 0000000000..f06e7b0384
--- /dev/null
+++ b/docs/gorilla-server.md
@@ -0,0 +1,138 @@
+# gorilla/mux Server
+
+For a gorilla/mux server, you will want a configuration file such as:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: api
+generate:
+ gorilla-server: true
+ models: true
+output: gen.go
+```
+
+## Generated code
+
+For instance, let's take this straightforward specification:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Minimal ping API server
+paths:
+ /ping:
+ get:
+ responses:
+ '200':
+ description: pet response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pong'
+components:
+ schemas:
+ # base types
+ Pong:
+ type: object
+ required:
+ - ping
+ properties:
+ ping:
+ type: string
+ example: pong
+```
+
+This then generates code such as:
+
+```go
+// Pong defines model for Pong.
+type Pong struct {
+ Ping string `json:"ping"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /ping)
+ GetPing(w http.ResponseWriter, r *http.Request)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r *mux.Router) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ // ...
+
+ r.HandleFunc(options.BaseURL+"/ping", wrapper.GetPing).Methods("GET")
+
+ return r
+}
+```
+
+To implement this HTTP server, we need to write the following code in our [`api/impl.go`](../examples/minimal-server/gorillamux/api/impl.go):
+
+```go
+import (
+ "encoding/json"
+ "net/http"
+)
+
+// optional code omitted
+
+type Server struct{}
+
+func NewServer() Server {
+ return Server{}
+}
+
+// (GET /ping)
+func (Server) GetPing(w http.ResponseWriter, r *http.Request) {
+ resp := Pong{
+ Ping: "pong",
+ }
+
+ w.WriteHeader(http.StatusOK)
+ _ = json.NewEncoder(w).Encode(resp)
+}
+```
+
+Now we've got our implementation, we can then write the following code to wire it up and get a running server:
+
+```go
+import (
+ "log"
+ "net/http"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/gorillamux/api"
+ "github.com/gorilla/mux"
+)
+
+func main() {
+ // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
+ server := api.NewServer()
+
+ r := mux.NewRouter()
+
+ // get an `http.Handler` that we can use
+ h := api.HandlerFromMux(server, r)
+
+ s := &http.Server{
+ Handler: h,
+ Addr: "0.0.0.0:8080",
+ }
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(s.ListenAndServe())
+}
+```
+
+> [!NOTE]
+> This doesn't include [validation of incoming requests](../README.md#requestresponse-validation-middleware).
diff --git a/docs/iris-server.md b/docs/iris-server.md
new file mode 100644
index 0000000000..351db32d6f
--- /dev/null
+++ b/docs/iris-server.md
@@ -0,0 +1,128 @@
+# Iris Server
+
+For an Iris server, you will want a configuration file such as:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: api
+generate:
+ iris-server: true
+ models: true
+output: gen.go
+```
+
+## Generated code
+
+For instance, let's take this straightforward specification:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Minimal ping API server
+paths:
+ /ping:
+ get:
+ responses:
+ '200':
+ description: pet response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pong'
+components:
+ schemas:
+ # base types
+ Pong:
+ type: object
+ required:
+ - ping
+ properties:
+ ping:
+ type: string
+ example: pong
+```
+
+This then generates code such as:
+
+```go
+// Pong defines model for Pong.
+type Pong struct {
+ Ping string `json:"ping"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /ping)
+ GetPing(ctx iris.Context)
+}
+
+// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
+func RegisterHandlers(router *iris.Application, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, IrisServerOptions{})
+}
+
+// RegisterHandlersWithOptions creates http.Handler with additional options
+func RegisterHandlersWithOptions(router *iris.Application, si ServerInterface, options IrisServerOptions) {
+ // ...
+
+ router.Get(options.BaseURL+"/ping", wrapper.GetPing)
+
+ router.Build()
+}
+```
+
+To implement this HTTP server, we need to write the following code in our [`api/impl.go`](../examples/minimal-server/iris/api/impl.go):
+
+```go
+import (
+ "net/http"
+
+ "github.com/kataras/iris/v12"
+)
+
+// optional code omitted
+
+type Server struct{}
+
+func NewServer() Server {
+ return Server{}
+}
+
+// (GET /ping)
+func (Server) GetPing(ctx iris.Context) {
+ resp := Pong{
+ Ping: "pong",
+ }
+
+ ctx.StatusCode(http.StatusOK)
+ _ = ctx.JSON(resp)
+}
+```
+
+Now we've got our implementation, we can then write the following code to wire it up and get a running server:
+
+```go
+import (
+ "log"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/iris/api"
+ "github.com/kataras/iris/v12"
+)
+
+func main() {
+ // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
+ server := api.NewServer()
+
+ i := iris.Default()
+
+ api.RegisterHandlers(i, server)
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(i.Listen("0.0.0.0:8080"))
+}
+```
+
+> [!NOTE]
+> This doesn't include [validation of incoming requests](../README.md#requestresponse-validation-middleware).
diff --git a/docs/stdhttp-server.md b/docs/stdhttp-server.md
new file mode 100644
index 0000000000..6e6f0daca1
--- /dev/null
+++ b/docs/stdhttp-server.md
@@ -0,0 +1,145 @@
+# Go 1.22+ `net/http` Server
+
+To use purely `net/http` (for Go 1.22+), you will want a configuration file such as:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: api
+generate:
+ std-http-server: true
+ models: true
+output: gen.go
+```
+
+## Generated code
+
+As of Go 1.22, enhancements have been made to the routing of the `net/http` package in the standard library, which makes it a great starting point for implementing a server with, before needing to reach for another router or a full framework.
+
+For instance, let's take this straightforward specification:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Minimal ping API server
+paths:
+ /ping:
+ get:
+ responses:
+ '200':
+ description: pet response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pong'
+components:
+ schemas:
+ # base types
+ Pong:
+ type: object
+ required:
+ - ping
+ properties:
+ ping:
+ type: string
+ example: pong
+```
+
+This then generates code such as:
+
+```go
+// Pong defines model for Pong.
+type Pong struct {
+ Ping string `json:"ping"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /ping)
+ GetPing(w http.ResponseWriter, r *http.Request)
+}
+
+func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseRouter: m,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler {
+ m := options.BaseRouter
+
+ // ... omitted for brevity
+
+ m.HandleFunc("GET "+options.BaseURL+"/ping", wrapper.GetPing)
+
+ return m
+}
+```
+
+To implement this HTTP server, we need to write the following code in our [`api/impl.go`](../examples/minimal-server/stdhttp/api/impl.go):
+
+```go
+import (
+ "encoding/json"
+ "net/http"
+)
+
+// optional code omitted
+
+type Server struct{}
+
+func NewServer() Server {
+ return Server{}
+}
+
+// (GET /ping)
+func (Server) GetPing(w http.ResponseWriter, r *http.Request) {
+ resp := Pong{
+ Ping: "pong",
+ }
+
+ w.WriteHeader(http.StatusOK)
+ _ = json.NewEncoder(w).Encode(resp)
+}
+```
+
+Now we've got our implementation, we can then write the following code to wire it up and get a running server:
+
+```go
+import (
+ "log"
+ "net/http"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/stdhttp/api"
+)
+
+func main() {
+ // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
+ server := api.NewServer()
+
+ r := http.NewServeMux()
+
+ // get an `http.Handler` that we can use
+ h := api.HandlerFromMux(server, r)
+
+ s := &http.Server{
+ Handler: h,
+ Addr: "0.0.0.0:8080",
+ }
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(s.ListenAndServe())
+}
+```
+
+> [!NOTE]
+> This doesn't include [validation of incoming requests](../README.md#requestresponse-validation-middleware).
+
+> [!NOTE]
+> If you feel like you've done everything right, but are still receiving `404 page not found` errors, make sure that you've got the `go` directive in your `go.mod` updated to:
+
+```go.mod
+go 1.22
+```