experimental

module
v0.0.0-...-da2a1ef Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 15, 2026 License: Apache-2.0

README

oapi-codegen V3

This is an experimental prototype of a V3 version of oapi-codegen. The generated code and command line options are not yet stable. Use at your own risk.

What is new in Version 3

This directory contains an experimental version of oapi-codegen's future V3 version, which is based on libopenapi, instead of the prior kin-openapi. This change necessitated a nearly complete rewrite, but we strive to be as compatible as possible.

What is working:

  • All model, client and server generation as in earlier versions.
  • We have added Webhook and Callback support, please see ./examples, which contains the ubiquitous OpenAPI pet shop implemented in all supported servers and examples of webhooks and callbacks implemented on top of the http.ServeMux server, with no additional imports.
  • Model generation of allOf, anyOf, oneOf is much more robust, since these were a source of many problems in earlier versions.
  • Echo V5 support has been added (Go 1.25 required)

What is missing:

  • We have not yet created any runtime code like request validation middleware.

Differences in V3

V3 is a brand new implementation, and may (will) contain new bugs, but also strives to fix many current, existing bugs. We've run quite a few conformance tests against specifications in old Issues, and we're looking pretty good! Please try this out, and if it failes in some way, please file Issues.

Aggregate Schemas

V3 implements oneOf, anyOf, allOf differently. Our prior versions had pretty good handling for allOf, where we merge all the constituent schemas into a schema object that contains all the fields of the originals. It makes sense, since this is composition.

oneOf and anyOf were handled by deferred parsing, where the JSON was captured into json.RawMessage and helper functions were created on each type to parse the JSON as any constituent type with the user's help.

Given the following schemas:

components:
  schemas:
    Cat:
      type: object
      properties:
        name:
          type: string
        color:
          type: string
    Dog:
      type: object
      properties:
        name:
          type: string
        color:
          type: string
    Fish:
      type: object
      properties:
        species:
          type: string
        isSaltwater:
          type: boolean
    NamedPet:
      anyOf:
        - $ref: '#/components/schemas/Cat'
        - $ref: '#/components/schemas/Dog'
    SpecificPet:
      oneOf:
        - $ref: '#/components/schemas/Cat'
        - $ref: '#/components/schemas/Dog'
        - $ref: '#/components/schemas/Fish'
V2 output

V2 generates both NamedPet (anyOf) and SpecificPet (oneOf) identically as opaque wrappers around json.RawMessage:

type NamedPet struct {
	union json.RawMessage
}

type SpecificPet struct {
	union json.RawMessage
}

The actual variant types are invisible at the struct level. To access the underlying data, the user must call generated helper methods:

// NamedPet (anyOf) helpers
func (t NamedPet) AsCat() (Cat, error)
func (t *NamedPet) FromCat(v Cat) error
// <snip>

// SpecificPet (oneOf) helpers

func (t SpecificPet) AsFish() (Fish, error)
func (t *SpecificPet) FromFish(v Fish) error
func (t *SpecificPet) MergeFish(v Fish) error
// <snip>

Note that anyOf and oneOf produce identical types and method signatures; there is no semantic difference in the generated code.

V3 output

V3 generates structs with exported pointer fields for each variant, making the union members visible at the type level. Crucially, anyOf and oneOf now have different marshal/unmarshal semantics.

anyOf (NamedPet)MarshalJSON merges all non-nil variants into a single JSON object. UnmarshalJSON tries every variant and keeps whichever succeed:

type NamedPet struct {
	Cat *Cat
	Dog *Dog
}

oneOf (SpecificPet)MarshalJSON returns an error unless exactly one field is non-nil. UnmarshalJSON returns an error unless the JSON matches exactly one variant:

type SpecificPet struct {
	Cat  *Cat
	Dog  *Dog
	Fish *Fish
}
OpenAPI V3.1 Feature Support

Thanks to libopenapi, we are able to parse OpenAPI 3.1 and 3.2 specifications. They are functionally similar, you can read the differences between nullable fields yourself, but they add some new functionality, namely webhooks and callbacks. We support all of them in this prototype. callbacks and webhooks are basically the inverse of paths. Webhooks contain no URL element in their definition, so we can't register handlers for you in your http router of choice, you have to do that yourself. Callbacks support complex request URL's which may reference the original request. This is something you need to pull out of the request body, and doing it generically is difficult, so we punt this problem, for now, to our users.

Please see the webhook example. It creates a little server that pretends to be a door badge reader, and it generates an event stream about people coming and going. Any number of clients may subscribe to this event. See the doc.go for usage examples.

The callback example, creates a little server that pretends to plant trees. Each tree planting request contains a callback to be notified when tree planting is complete. We invoke those in a random order via delays, and the client prints out callbacks as they happen. Please see doc.go for usage.

Flexible Configuration

oapi-codegen V3 tries to make no assumptions about which initialisms, struct tags, or name mangling that is correct for you. A very flexible configuration file allows you to override anything.

No runtime dependency

V2 generated code relied on github.com/oapi-codegen/runtime for parameter binding and styling. This was a complaint from lots of people due to various audit requirements. V3 embeds all necessary helper functions and helper types into the spec. There are no longer generic, parameterized functions that handle arbitrary parameters, but rather very specific functions for each kind of parameter, and we call the correct little helper versus a generic runtime helper.

Models now support default values configured in the spec

Every model which we generate supports an ApplyDefaults() function. It recursively applies defaults on any unset optional fields. There's a little caveat here, in that some types are external references, so we call ApplyDefaults() on them via reflection. This might call an ApplyDefaults() which is completely unrelated to what we're doing. Please let me know if this feature is causing trouble.

Installation

Go 1.24 is required, install like so:

go get -tool github.com/oapi-codegen/oapi-codegen-exp/experimental/cmd/oapi-codegen@latest

You can then run the code generator

//go:generate go run github.com/oapi-codegen/oapi-codegen-exp/experimental/cmd/oapi-codegen

Directories

Path Synopsis
cmd
oapi-codegen command
Package codegen provides the public API for oapi-codegen's experimental code generator.
Package codegen provides the public API for oapi-codegen's experimental code generator.
internal
Package codegen generates Go code from parsed OpenAPI specs.
Package codegen generates Go code from parsed OpenAPI specs.
internal/templates/test/helpers/genhelpers command
genhelpers generates Go files from helper and param templates.
genhelpers generates Go files from helper and param templates.
internal/templates/test/types/gentypes command
gentypes generates Go type files from templates.
gentypes generates Go type files from templates.
internal/test/name_conflict_resolution
Package name_conflict_resolution tests comprehensive type name collision resolution.
Package name_conflict_resolution tests comprehensive type name collision resolution.
internal/test/previous_version/all_of
Package all_of tests allOf schema composition from the V2 test suite.
Package all_of tests allOf schema composition from the V2 test suite.
internal/test/previous_version/any_of/inline
Package inline tests inline anyOf schema composition from the V2 test suite.
Package inline tests inline anyOf schema composition from the V2 test suite.
internal/test/previous_version/any_of/param
Package param tests anyOf/oneOf in parameters from the V2 test suite.
Package param tests anyOf/oneOf in parameters from the V2 test suite.
internal/test/previous_version/components
Package components tests complex component schemas from the V2 test suite.
Package components tests complex component schemas from the V2 test suite.
internal/test/previous_version/extensions/x_order
Package x_order tests x-order field ordering extension from the V2 test suite.
Package x_order tests x-order field ordering extension from the V2 test suite.
internal/test/previous_version/issues/issue_1029
Package issue_1029 tests that oneOf with multiple single-value string enums generates valid code.
Package issue_1029 tests that oneOf with multiple single-value string enums generates valid code.
internal/test/previous_version/issues/issue_1039
Package issue_1039 tests nullable type generation.
Package issue_1039 tests nullable type generation.
internal/test/previous_version/issues/issue_1087
Package issue_1087 tests external dependencies with import resolution.
Package issue_1087 tests external dependencies with import resolution.
internal/test/previous_version/issues/issue_1087/deps
Package deps provides external dependency types for issue 1087.
Package deps provides external dependency types for issue 1087.
internal/test/previous_version/issues/issue_1093
Package issue_1093 tests multi-spec cross-package imports.
Package issue_1093 tests multi-spec cross-package imports.
internal/test/previous_version/issues/issue_1127
Package issue_1127 tests multiple content types.
Package issue_1127 tests multiple content types.
internal/test/previous_version/issues/issue_1168
Package issue_1168 tests additionalProperties: true.
Package issue_1168 tests additionalProperties: true.
internal/test/previous_version/issues/issue_1180
Package issue_1180 tests parameter style handling.
Package issue_1180 tests parameter style handling.
internal/test/previous_version/issues/issue_1182
Package issue_1182 tests external response refs across specs.
Package issue_1182 tests external response refs across specs.
internal/test/previous_version/issues/issue_1189
Package issue_1189 tests anyOf/allOf/oneOf composition.
Package issue_1189 tests anyOf/allOf/oneOf composition.
internal/test/previous_version/issues/issue_1208_1209
Package issue_1208_1209 tests multiple JSON content types.
Package issue_1208_1209 tests multiple JSON content types.
internal/test/previous_version/issues/issue_1212
Package issue_1212 tests multi-package response schemas.
Package issue_1212 tests multi-package response schemas.
internal/test/previous_version/issues/issue_1219
Package issue_1219 tests additionalProperties merge with allOf.
Package issue_1219 tests additionalProperties merge with allOf.
internal/test/previous_version/issues/issue_1298
Package issue_1298 tests custom content-type schemas.
Package issue_1298 tests custom content-type schemas.
internal/test/previous_version/issues/issue_1397
Package issue_1397 tests basic type generation with x-go-type-name.
Package issue_1397 tests basic type generation with x-go-type-name.
internal/test/previous_version/issues/issue_1429
Package issue_1429 tests that enums inside anyOf members are generated.
Package issue_1429 tests that enums inside anyOf members are generated.
internal/test/previous_version/issues/issue_1496
Package issue_1496 tests that inline schemas generate valid Go identifiers.
Package issue_1496 tests that inline schemas generate valid Go identifiers.
internal/test/previous_version/issues/issue_1561
Package issue_1561 tests skip-optional-pointer on containers.
Package issue_1561 tests skip-optional-pointer on containers.
internal/test/previous_version/issues/issue_1710
Package issue_1710 tests that fields are not lost in nested allOf oneOf structures.
Package issue_1710 tests that fields are not lost in nested allOf oneOf structures.
internal/test/previous_version/issues/issue_1767
Package issue_1767 tests underscore field name mapping.
Package issue_1767 tests underscore field name mapping.
internal/test/previous_version/issues/issue_1825
Package issue_1825 tests overlay and external refs.
Package issue_1825 tests overlay and external refs.
internal/test/previous_version/issues/issue_193
Package issue_193 tests allOf with additionalProperties merging.
Package issue_193 tests allOf with additionalProperties merging.
internal/test/previous_version/issues/issue_1957
Package issue_1957 tests x-go-type with skip-optional-pointer.
Package issue_1957 tests x-go-type with skip-optional-pointer.
internal/test/previous_version/issues/issue_2031
Package issue_2031 tests skip-optional-pointer with arrays.
Package issue_2031 tests skip-optional-pointer with arrays.
internal/test/previous_version/issues/issue_2102
Package issue_2102 tests that properties defined at the same level as allOf are included.
Package issue_2102 tests that properties defined at the same level as allOf are included.
internal/test/previous_version/issues/issue_240
Package issue_240 tests models with no type field.
Package issue_240 tests models with no type field.
internal/test/previous_version/issues/issue_312
Package issue_312 tests proper escaping of paths with special characters.
Package issue_312 tests proper escaping of paths with special characters.
internal/test/previous_version/issues/issue_502
Package issue_502 tests that anyOf with only one ref generates the referenced type.
Package issue_502 tests that anyOf with only one ref generates the referenced type.
internal/test/previous_version/issues/issue_52
Package issue_52 tests that recursive types are handled properly.
Package issue_52 tests that recursive types are handled properly.
internal/test/previous_version/issues/issue_579
Package issue_579 tests aliased types with date format.
Package issue_579 tests aliased types with date format.
internal/test/previous_version/issues/issue_609
Package issue_609 tests optional field with no type info.
Package issue_609 tests optional field with no type info.
internal/test/previous_version/issues/issue_697
Package issue_697 tests that properties alongside allOf are included.
Package issue_697 tests that properties alongside allOf are included.
internal/test/previous_version/issues/issue_775
Package issue_775 tests that allOf with format specification works correctly.
Package issue_775 tests that allOf with format specification works correctly.
internal/test/previous_version/issues/issue_832
Package issue_832 tests x-go-type-name override for enum types.
Package issue_832 tests x-go-type-name override for enum types.
internal/test/previous_version/issues/issue_936
Package issue_936 tests recursive/circular schema references.
Package issue_936 tests recursive/circular schema references.
internal/test/previous_version/issues/issue_head_digit_operation_id
Package issue_head_digit_operation_id tests operation IDs starting with digits.
Package issue_head_digit_operation_id tests operation IDs starting with digits.
internal/test/previous_version/issues/issue_illegal_enum_names
Package issue_illegal_enum_names tests enum constant generation with edge cases.
Package issue_illegal_enum_names tests enum constant generation with edge cases.
internal/test/previous_version/issues/issue_removed_external_ref
Package issue_removed_external_ref tests external ref filtering.
Package issue_removed_external_ref tests external ref filtering.
internal/test/previous_version/outputoptions/name_normalizer
Package name_normalizer tests name normalization from the V2 test suite.
Package name_normalizer tests name normalization from the V2 test suite.
internal/test/previous_version/parameters
Package parameters tests parameter type generation from the V2 test suite.
Package parameters tests parameter type generation from the V2 test suite.
internal/test/previous_version/schemas
Package schemas tests comprehensive schema generation from the V2 test suite.
Package schemas tests comprehensive schema generation from the V2 test suite.
examples
callback
Package treefarm provides an example of how to handle OpenAPI callbacks.
Package treefarm provides an example of how to handle OpenAPI callbacks.
callback/client command
callback/server command
petstore-expanded
Package petstore provides generated types for the Petstore API.
Package petstore provides generated types for the Petstore API.
webhook
Package doorbadge provides an example of OpenAPI 3.1 webhooks.
Package doorbadge provides an example of OpenAPI 3.1 webhooks.
webhook/client command
webhook/server command
Package runtime provides shared helper types and functions for code generated by oapi-codegen.
Package runtime provides shared helper types and functions for code generated by oapi-codegen.
helpers
Package helpers provides utility functions for request body encoding, including MarshalForm for form-encoded request bodies.
Package helpers provides utility functions for request body encoding, including MarshalForm for form-encoded request bodies.
params
Package params provides parameter serialization and deserialization functions for OpenAPI-style parameters (simple, form, label, matrix, etc.).
Package params provides parameter serialization and deserialization functions for OpenAPI-style parameters (simple, form, label, matrix, etc.).
types
Package types provides custom Go types for OpenAPI format mappings: Date, Email, UUID, File, and the generic Nullable[T] wrapper.
Package types provides custom Go types for OpenAPI format mappings: Date, Email, UUID, File, and the generic Nullable[T] wrapper.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL