Awesome Go

oapi-codegen

CategoryGenerators
SubcategoryGenerators
Stars8,619

This package contains a set of utilities for generating Go boilerplate code for services based on OpenAPI 3.0 API definitions

About oapi-codegen

This large README is shown as a plain-text preview. Read the full README at the source

# `oapi-codegen`

[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/9450/badge)](https://www.bestpractices.dev/projects/9450)

`oapi-codegen` is a command-line tool and library to convert OpenAPI specifications to Go code, be it [server-side implementations](#generating-server-side-boilerplate), [API clients](#generating-api-clients), or simply [HTTP models](#generating-api-models).

Using `oapi-codegen` allows you to reduce the boilerplate required to create or integrate with services based on [OpenAPI 3.0](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md) and [OpenAPI 3.1](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md), and instead focus on writing your business logic, and working on the real value-add for your organisation.

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 verbose code over complex modular code
- supporting as much of OpenAPI 3.0 and 3.1 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.

## Table of Contents

<!-- toc -->
- [Installation](#installation)
  - [Action Required: The repository for this project has changed](#action-required-the-repository-for-this-project-has-changed)
  - [Installing](#installing)
  - [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 &quot;Import Mapping&quot; or &quot;external references&quot;)](#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)
    - [Deprecated: auth scopes on the request context](#deprecated-auth-scopes-on-the-request-context)
  - [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 (<code>additionalProperties</code>)](#additional-properties-additionalproperties)
  - [Implicit <code>additionalProperties: true</code> / no <code>additionalProperties</code> set](#implicit-additionalproperties-true--no-additionalproperties-set)
  - [Explicit <code>additionalProperties: true</code>](#explicit-additionalproperties-true)
  - [<code>additionalProperties</code> as <code>integer</code>s](#additionalproperties-as-integers)
  - [<code>additionalProperties</code> with an object](#additionalproperties-with-an-object)
- [Globally skipping the &quot;optional pointer&quot;](#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 <code>oapi-codegen</code> support OpenAPI 3.1?](#does-oapi-codegen-support-openapi-31)
  - [How does <code>oapi-codegen</code> handle <code>anyOf</code>, <code>allOf</code> and <code>oneOf</code>?](#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 <code>kin-openapi</code>, 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)
<!-- /toc -->

## 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
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`.

> [!IMPORTANT]
> `oapi-codegen` moved to its new home with the version tag `v2.3.0`.

If you are using `v2.2.0` or below, please install like so:

```sh
# for the binary install
go install github.com/deepmap/oapi-codegen/v2/cmd/[email protected]
```

If you are using `v2.3.0` or above, please install like so, using the new module import path:

```sh
# for the binary install
go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest
```

### Installing

`oapi-codegen` requires Go 1.25+ to build and install. Note that the *generated* code has its own, lower requirements — see [Supported Servers](#supported-servers).

It is recommended to use [`go tool` support](https://www.jvt.me/posts/2025/01/27/go-tools-124/) for managing the dependency of `oapi-codegen` alongside your core application.

To do this, you run `go get -tool`:

```sh
$ go get -tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest
# this will then modify your `go.mod`
```

From there, each invocation of `oapi-codegen` would be used like so:

```go
//go:generate go tool oapi-codegen -config cfg.yaml ../../api.yaml
```

Alternatively, you can install it as a binary with:

```sh
$ go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest
$ oapi-codegen -version
```

Which then means you can invoke it like so:

```go
//go:generate oapi-codegen --config=config.yaml ../../api.yaml
```

### Pinning to commits

While the project does not ([yet](https://github.com/oapi-codegen/oapi-codegen/issues/1519)) have a defined release cadence, there may be cases where you want to pull in yet-unreleased changes to your codebase.

Therefore, you may want to pin your dependency on `oapi-codegen` to a given commit hash, rather than a tag.

This is **officially recommended** for consumers of `oapi-codegen`, who want features/bug fixes that haven't yet been released.

We aim to keep the default branch ready-to-release so you should be able to safely pin.

To do so, you can run:

```sh
# pin to the latest version on the default branch
$ go get github.com/oapi-codegen/oapi-codegen/v2@main
# alternatively, to a commit hash i.e. https://github.com/oapi-codegen/oapi-codegen/commit/71e916c59688a6379b5774dfe5904ec222b9a537
$ go get github.com/oapi-codegen/oapi-codegen/v2@71e916c59688a6379b5774dfe5904ec222b9a537
```

This will then make a change such as:

```diff
diff --git go.mod go.mod
index 44f29a4..436a780 100644
--- go.mod
+++ go.mod
@@ -2,21 +2,20 @@
-require github.com/oapi-codegen/oapi-codegen/v2 v2.1.0
+require github.com/oapi-codegen/oapi-codegen/v2 v2.1.1-0.20240331212514-80f0b978ef16
```

## Usage

`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, 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.:

```yaml
# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/v2.8.0/configuration-schema.json
package: api
# ...
```

Note that it's recommended to pin to a specific version of the configuration schema, so it matches the version of `oapi-codegen` you're using. For instance, if you're using [Renovate](https://docs.renovatebot.com/), you can [have Renovate automagically update this version for you](https://www.jvt.me/posts/2026/03/01/oapi-codegen-config-renovate/).

### Backwards compatibility

Although we strive to retain backwards compatibility - as a project that's using a stable API per SemVer - there are sometimes opportunities we must take to fix a bug that could cause a breaking change for [people relying upon the behaviour](https://xkcd.com/1172/).

In this case, we will expose a [compatibility option](https://pkg.go.dev/github.com/oapi-codegen/oapi-codegen/v2/pkg/codegen#CompatibilityOptions) to restore old behaviour.

That all being said, we operate in a little bit of a grey area, since we are a code generator, we support template overrides, and
our code can be imported. So this is how we will try to maintain compatibility:

  - SemVer mostly applies to generated code. We strive to avoid breaking your code which depends on the generated code. We will
    provide compatibility flags for major breaking changes.
  - A breaking change could happen with either a compilation error (as something has changed in the generated code) or a behaviour change (we generate a slightly different implementation)
  - However, if you're using generated code that is "off the beaten path", on a seldom encountered edge case, we'll sometimes decide to make a breaking change to avoid complicating usage or internals.
  - [Our `pkg/` directory is importable](https://pkg.go.dev/github.com/oapi-codegen/oapi-codegen/v2/pkg). In retrospect, this was a mistake in our original design. Importing anything other than the `Generate` function and its related `Configuration` is considered unstable (and at this point, [hasn't (yet) been documented](https://github.com/oapi-codegen/oapi-codegen/issues/1487)). In the future, we will clean up our import surface.
  - Template overrides are considered unstable, and you use them at your own risk. These are always drifting and so are their input contexts, so we can't guarantee much here.
  - The command-line interface and/or the configuration file format are classed as stable

Also note that - if a security vulnerability is found - we will opt for breaking all users if need be, if it is the most secure response.

Unless explicitly called out above, your usage of `oapi-codegen` may be using unstable features, which may make it harder to upgrade over time.

## Features

At a high level, `oapi-codegen` supports:

- Generating server-side boilerplate for [a number of servers](#supported-servers) ([docs](#generating-server-side-boilerplate))
- Generating client API boilerplate ([docs](#generating-api-clients))
- Generating the types ([docs](#generating-api-models))
- Splitting large OpenAPI specs across multiple packages([docs](#import-mapping))
  - This is also known as "Import Mapping" or "external references" across our documentation / discussion in GitHub issues

## What does it look like?

Below we can see a trimmed down example taken from the OpenAPI Petstore [example](examples/petstore-expanded/stdhttp/api/petstore.gen.go):

```go
// generated code

type ServerInterface interface {
	// ...
	// Returns all pets
	// (GET /pets)
	FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams)
	// ...
}

// FindPets operation middleware
func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Request) {

	var err error

	// Parameter object where we will unmarshal all parameters from the context
	var params FindPetsParams

	// ------------- Optional query parameter "tags" -------------

	err = runtime.BindQueryParameter("form", true, false, "tags", r.URL.Query(), &params.Tags)
	if err != nil {
		siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "tags", Err: err})
		return
	}

	// ------------- Optional query parameter "limit" -------------

	err = runtime.BindQueryParameter("form", true, false, "limit", r.URL.Query(), &params.Limit)
	if err != nil {
		siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err})
		return
	}

	handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		siw.Handler.FindPets(w, r, params)
	}))

	for _, middleware := range siw.HandlerMiddlewares {
		handler = middleware(handler)
	}

	handler.ServeHTTP(w, r)
}

// HandlerWithOptions creates http.Handler with additional options
func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler {
	m := options.BaseRouter

	if m == nil {
		m = http.NewServeMux()
	}
	if options.ErrorHandlerFunc == nil {
		options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
			http.Error(w, err.Error(), http.StatusBadRequest)
		}
	}

	wrapper := ServerInterfaceWrapper{
		Handler:            si,
		HandlerMiddlewares: options.Middlewares,
		ErrorHandlerFunc:   options.ErrorHandlerFunc,
	}

	m.HandleFunc("GET "+options.BaseURL+"/pets", wrapper.FindPets)

	return m
}
```

Then, in your own code, you implement the underlying logic for the `FindPets` implementation:

```go
type PetStore struct {
	Pets   map[int64]Pet
	NextId int64
	Lock   sync.Mutex
}

// Make sure we conform to ServerInterface

var _ ServerInterface = (*PetStore)(nil)

func NewPetStore() *PetStore {
	return &PetStore{
		Pets:   make(map[int64]Pet),
		NextId: 1000,
	}
}

// FindPets implements all the handlers in the ServerInterface
func (p *PetStore) FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams) {
	p.Lock.Lock()
	defer p.Lock.Unlock()

	var result []Pet

	for _, pet := range p.Pets {
		if params.Tags != nil {
			// If we have tags,  filter pets by tag
			for _, t := range *params.Tags {
				if pet.Tag != nil && (*pet.Tag == t) {
					result = append(result, pet)
				}
			}
		} else {
			// Add all pets if we're not filtering
			result = append(result, pet)
		}

		if params.Limit != nil {
			l := int(*params.Limit)
			if len(result) >= l {
				// We're at the limit
				break
			}
		}
	}

	w.WriteHeader(http.StatusOK)
	_ = json.NewEncoder(w).Encode(result)
}
```

As we can see, `oapi-codegen` simplifies some of the boilerplate by taking parameters out of the request and instead allows us to focus on the implementation.

You'll note that there's still a bit more marshaling of request/response data, which is further reduced by using the [Strict server](#strict-server) functionality.

<a name="what-does-it-look-like-strict"></a>
When using the strict server, you'll have the following generated code:

```go
// StrictServerInterface represents all server handlers.
type StrictServerInterface interface {
	// ...
	// Returns all pets
	// (GET /pets)
	FindPets(ctx context.Context, request FindPetsRequestObject) (FindPetsResponseObject, error)
	// ...
}

func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictHTTPServerOptions) ServerInterface {
	return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
}

// FindPets operation middleware
func (sh *strictHandler) FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams) {
	var request FindPetsRequestObject

	request.Params = params

	handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
		return sh.ssi.FindPets(ctx, request.(FindPetsRequestObject))
	}
	for _, middleware := range sh.middlewares {
		handler = middleware(handler, "FindPets")
	}

	response, err := handler(r.Context(), w, r, request)

	if err != nil {
		sh.options.ResponseErrorHandlerFunc(w, r, err)
	} else if validResponse, ok := response.(FindPetsResponseObject); ok {
		if err := validResponse.VisitFindPetsResponse(w); err != nil {
			sh.options.ResponseErrorHandlerFunc(w, r, err)
		}
	} else if response != nil {
		sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
	}
}
```

Then, in your own code, you implement the underlying logic for the `FindPets` implementation:

```go
// Make sure we conform to StrictServerInterface

var _ StrictServerInterface = (*PetStore)(nil)

func NewPetStore() *PetStore {
	return &PetStore{
		Pets:   make(map[int64]Pet),
		NextId: 1000,
	}
}

// FindPets implements all the handlers in the ServerInterface
func (p *PetStore) FindPets(ctx context.Context, request FindPetsRequestObject) (FindPetsResponseObject, error) {
	p.Lock.Lock()
	defer p.Lock.Unlock()

	var result []Pet

	for _, pet := range p.Pets {
		if request.Params.Tags != nil {
			// If we have tags,  filter pets by tag
			for _, t := range *request.Params.Tags {
				if pet.Tag != nil && (*pet.Tag == t) {
					result = append(result, pet)
				}
			}
		} else {
			// Add all pets if we're not filtering
			result = append(result, pet)
		}

		if request.Params.Limit != nil {
			l := int(*request.Params.Limit)
			if len(result) >= l {
				// We're at the limit
				break
			}
		}
	}

	return FindPets200JSONResponse(result), nil
}
```

We can see that this provides the best means to focus on the implementation of the business logic within the endpoint, rather than (un)marshalling types to and from JSON, or wrangling cookies or headers.

## Key design decisions

- 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
- Support multiple OpenAPI files by having a package per OpenAPI file
- Support of OpenAPI 3.0 and 3.1
  - OpenAPI 3.1 support includes [webhooks](https://spec.openapis.org/oas/v3.1.0#oasWebhooks) and version-aware handling of 3.1 idioms such as `type: [T, "null"]` nullability and enums declared via `oneOf` + `const`
  - 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

## Generating server-side boilerplate

`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.

You can find the supported HTTP server backends below, and more information about how to implement a server on top of each router.

Frequently Asked Questions

What is oapi-codegen?

oapi-codegen is a Generators library for the Go programming language. This package contains a set of utilities for generating Go boilerplate code for services based on OpenAPI 3.0 API definitions

How many GitHub stars does oapi-codegen have?

oapi-codegen has 8,619 GitHub stars in the directory's latest synchronization.

How do I install oapi-codegen?

Install oapi-codegen with the Go module system using `go get deepmap/oapi-codegen`. Check the repository for the current installation instructions.

What category does oapi-codegen belong to?

oapi-codegen is listed under Generators, specifically Generators.

← Back to Generators