oapi-codegen-dd

module
v3.63.5 Latest Latest
Warning

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

Go to latest
Published: Jan 12, 2026 License: Apache-2.0

README

oapi-codegen

OpenSSF Best Practices

Using oapi-codegen allows you to reduce the boilerplate required to create or integrate with services based on OpenAPI 3.x, 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 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

Migrate from v2

This project is a fork of oapi-codegen v2.
Due to the lack of OpenAPI 3.1 support in the original repository, we introduced a fully reworked implementation.
While this includes some breaking changes, it also brings more flexible generator and parser APIs for finer control over code generation.
If you're migrating from v2, please refer to the migration guide for important differences.

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.

Features

At a high level, oapi-codegen supports:

  • Generating the types (docs)
  • Splitting large OpenAPI specs across multiple packages(docs)
    • This is also known as "Import Mapping" or "external references" across our documentation / discussion in GitHub issues

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/templates, which are user-overridable
  • Attempts to produce Idiomatic Go
  • Single or multiple file output
  • Support of OpenAPI 3.1
  • Extract parameters from requests, to reduce work required by your implementation
  • Implicit additionalProperties are ignored by default (more details)
  • Prune unused types by default

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.

OpenAPI extensions

As well as the core OpenAPI support, we also support the following OpenAPI extensions, as denoted by the OpenAPI Specification Extensions.

Extension Description Example usage

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:

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:

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

x-go-type-skip-optional-pointer

Do not add a pointer type for optional fields in structs

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:

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:

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

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:

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:

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

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

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:

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:

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

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:

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 behavior, even though it's a required field
          x-omitempty: true
        id:
          type: number

From here, we now get two different models:

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

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:

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:

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

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:

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:

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

x-sensitive-data

Automatically mask sensitive data in JSON output

The x-sensitive-data extension allows you to mark fields as containing sensitive information that should be automatically masked when marshaling to JSON. This is useful for preventing accidental logging or exposure of sensitive data like passwords, API keys, credit card numbers, etc.

The extension supports several masking strategies:

  • full: Replace the entire value with a fixed-length mask ("********") to hide both content and length
  • regex: Mask only parts of the value matching a regex pattern (keeps context visible)
  • hash: Replace the value with a SHA256 hash (one-way, useful for verification)
  • partial: Mask the middle part while keeping prefix/suffix visible (e.g., show last 4 digits of credit card)

Example:

openapi: "3.0.0"
info:
  version: 1.0.0
  title: Sensitive Data Example
components:
  schemas:
    User:
      type: object
      properties:
        email:
          type: string
          x-sensitive-data:
            mask: full
        ssn:
          type: string
          x-sensitive-data:
            mask: regex
            pattern: '\d{3}-\d{2}-\d{4}'
        creditCard:
          type: string
          x-sensitive-data:
            mask: partial
            keepSuffix: 4  # Show last 4 digits
        apiKey:
          type: string
          x-sensitive-data:
            mask: hash
            algorithm: sha256

This generates:

type User struct {
    Email      *string `json:"email,omitempty" sensitive:""`
    Ssn        *string `json:"ssn,omitempty" sensitive:""`
    CreditCard *string `json:"creditCard,omitempty" sensitive:""`
    ApiKey     *string `json:"apiKey,omitempty" sensitive:""`
}

func (u User) MarshalJSON() ([]byte, error) {
    // Custom marshaler that masks sensitive fields
    // ...
}

When marshaling to JSON:

  • email: "user@example.com" becomes email: "********" (fixed length, hides original length)
  • ssn: "123-45-6789" becomes ssn: "***-**-****" (digits masked, structure visible)
  • creditCard: "1234-5678-9012-3456" becomes creditCard: "********3456" (last 4 visible)
  • apiKey: "my-secret-key" becomes apiKey: "325ededd6c3b9988f623c7f964abb9b016b76b0f8b3474df0f7d7c23b941381f" (SHA256 hash)

Partial masking options:

  • keepPrefix: Number of characters to keep at the start
  • keepSuffix: Number of characters to keep at the end

You can see this in more detail in the example code.

x-enum-names

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-names extension allows overriding the name of the generated variable names.

We can see this at play with the following schemas:

openapi: "3.0.0"
info:
  version: 1.0.0
  title: x-enum-names
components:
  schemas:
    ClientType:
      type: string
      enum:
        - ACT
        - EXP
    ClientTypeWithNamesExtension:
      type: string
      enum:
        - ACT
        - EXP
      x-enum-names:
        - Active
        - Expired

From here, we now get two different forms of the same enum definition.

// Defines values for ClientType.
const (
	ACT ClientType = "ACT"
	EXP ClientType = "EXP"
)

// ClientType defines model for ClientType.
type ClientType string

// Defines values for ClientTypeWithExtension.
const (
	Active  ClientTypeWithExtension = "ACT"
	Expired ClientTypeWithExtension = "EXP"
)

// ClientTypeWithExtension defines model for ClientTypeWithExtension.
type ClientTypeWithExtension string

You can see this in more detail in the example code.

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:

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.

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

Custom code generation

It is possible to extend the inbuilt code generation from oapi-codegen using Go's text/templates.

You can specify, through your configuration file, the user-templates setting to override the inbuilt templates and use a user-defined template.

[!NOTE] Filenames given to the user-templates configuration must exactly match the filename that oapi-codegen is looking for

Local paths

Within your configuration file, you can specify relative or absolute paths to a file to reference for the template, such as:

# yaml-language-server: $schema=https://raw.githubusercontent.com/doordash/oapi-codegen/HEAD/configuration-schema.json
# ...
user-templates:
  client.tmpl: ./custom-template.tmpl
  enums.tmpl: /tmp/foo.bar
  types.tmpl: no-prefix.tmpl
Using the Go package

You can get full control of the generator and the parser by using the codegen package directly.

TBD: add documentation

Additional Properties (additionalProperties)

OpenAPI Schemas implicitly accept additionalProperties, meaning that any fields provided, but not explicitly defined via properties on the schema are accepted as input, and propagated. When unspecified, OpenAPI defines that the additionalProperties field is assumed to be true.

For simplicity, and to remove a fair bit of duplication and boilerplate, oapi-codegen decides to ignore the implicit additionalProperties: true, and instead requires you to specify the additionalProperties key to generate the boilerplate.

Below you can see some examples of how additionalProperties affects the generated code.

Implicit additionalProperties: true / no additionalProperties set
components:
  schemas:
    Thing:
      type: object
      required:
        - id
      properties:
        id:
          type: integer
      # implicit additionalProperties: true

Will generate:

// Thing defines model for Thing.
type Thing struct {
	Id int `json:"id"`
}

// with no generated boilerplate nor the `AdditionalProperties` field
Explicit additionalProperties: true
components:
  schemas:
    Thing:
      type: object
      required:
        - id
      properties:
        id:
          type: integer
      # explicit true
      additionalProperties: true

Will generate:

// Thing defines model for Thing.
type Thing struct {
	Id                   int                    `json:"id"`
	AdditionalProperties map[string]interface{} `json:"-"`
}

// with generated boilerplate below
Boilerplate

// Getter for additional properties for Thing. Returns the specified
// element and whether it was found
func (a Thing) Get(fieldName string) (value interface{}, found bool) {
	if a.AdditionalProperties != nil {
		value, found = a.AdditionalProperties[fieldName]
	}
	return
}

// Setter for additional properties for Thing
func (a *Thing) Set(fieldName string, value interface{}) {
	if a.AdditionalProperties == nil {
		a.AdditionalProperties = make(map[string]interface{})
	}
	a.AdditionalProperties[fieldName] = value
}

// Override default JSON handling for Thing to handle AdditionalProperties
func (a *Thing) UnmarshalJSON(b []byte) error {
	object := make(map[string]json.RawMessage)
	err := json.Unmarshal(b, &object)
	if err != nil {
		return err
	}

	if raw, found := object["id"]; found {
		err = json.Unmarshal(raw, &a.Id)
		if err != nil {
			return fmt.Errorf("error reading 'id': %w", err)
		}
		delete(object, "id")
	}

	if len(object) != 0 {
		a.AdditionalProperties = make(map[string]interface{})
		for fieldName, fieldBuf := range object {
			var fieldVal interface{}
			err := json.Unmarshal(fieldBuf, &fieldVal)
			if err != nil {
				return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
			}
			a.AdditionalProperties[fieldName] = fieldVal
		}
	}
	return nil
}

// Override default JSON handling for Thing to handle AdditionalProperties
func (a Thing) MarshalJSON() ([]byte, error) {
	var err error
	object := make(map[string]json.RawMessage)

	object["id"], err = json.Marshal(a.Id)
	if err != nil {
		return nil, fmt.Errorf("error marshaling 'id': %w", err)
	}

	for fieldName, field := range a.AdditionalProperties {
		object[fieldName], err = json.Marshal(field)
		if err != nil {
			return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
		}
	}
	return json.Marshal(object)
}
additionalProperties as integers
components:
  schemas:
    Thing:
      type: object
      required:
        - id
      properties:
        id:
          type: integer
      # simple type
      additionalProperties:
        type: integer

Will generate:

// Thing defines model for Thing.
type Thing struct {
	Id                   int            `json:"id"`
	AdditionalProperties map[string]int `json:"-"`
}

// with generated boilerplate below
Boilerplate
// Getter for additional properties for Thing. Returns the specified
// element and whether it was found
func (a Thing) Get(fieldName string) (value int, found bool) {
	if a.AdditionalProperties != nil {
		value, found = a.AdditionalProperties[fieldName]
	}
	return
}

// Setter for additional properties for Thing
func (a *Thing) Set(fieldName string, value int) {
	if a.AdditionalProperties == nil {
		a.AdditionalProperties = make(map[string]int)
	}
	a.AdditionalProperties[fieldName] = value
}

// Override default JSON handling for Thing to handle AdditionalProperties
func (a *Thing) UnmarshalJSON(b []byte) error {
	object := make(map[string]json.RawMessage)
	err := json.Unmarshal(b, &object)
	if err != nil {
		return err
	}

	if raw, found := object["id"]; found {
		err = json.Unmarshal(raw, &a.Id)
		if err != nil {
			return fmt.Errorf("error reading 'id': %w", err)
		}
		delete(object, "id")
	}

	if len(object) != 0 {
		a.AdditionalProperties = make(map[string]int)
		for fieldName, fieldBuf := range object {
			var fieldVal int
			err := json.Unmarshal(fieldBuf, &fieldVal)
			if err != nil {
				return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
			}
			a.AdditionalProperties[fieldName] = fieldVal
		}
	}
	return nil
}

// Override default JSON handling for Thing to handle AdditionalProperties
func (a Thing) MarshalJSON() ([]byte, error) {
	var err error
	object := make(map[string]json.RawMessage)

	object["id"], err = json.Marshal(a.Id)
	if err != nil {
		return nil, fmt.Errorf("error marshaling 'id': %w", err)
	}

	for fieldName, field := range a.AdditionalProperties {
		object[fieldName], err = json.Marshal(field)
		if err != nil {
			return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
		}
	}
	return json.Marshal(object)
}
additionalProperties with an object
components:
  schemas:
    Thing:
      type: object
      required:
        - id
      properties:
        id:
          type: integer
      # object
      additionalProperties:
        type: object
        properties:
          foo:
            type: string

Will generate:

// Thing defines model for Thing.
type Thing struct {
	Id                   int `json:"id"`
	AdditionalProperties map[string]struct {
		Foo *string `json:"foo,omitempty"`
	} `json:"-"`
}

// with generated boilerplate below
Boilerplate
// Getter for additional properties for Thing. Returns the specified
// element and whether it was found
func (a Thing) Get(fieldName string) (value struct {
	Foo *string `json:"foo,omitempty"`
}, found bool) {
	if a.AdditionalProperties != nil {
		value, found = a.AdditionalProperties[fieldName]
	}
	return
}

// Setter for additional properties for Thing
func (a *Thing) Set(fieldName string, value struct {
	Foo *string `json:"foo,omitempty"`
}) {
	if a.AdditionalProperties == nil {
		a.AdditionalProperties = make(map[string]struct {
			Foo *string `json:"foo,omitempty"`
		})
	}
	a.AdditionalProperties[fieldName] = value
}

// Override default JSON handling for Thing to handle AdditionalProperties
func (a *Thing) UnmarshalJSON(b []byte) error {
	object := make(map[string]json.RawMessage)
	err := json.Unmarshal(b, &object)
	if err != nil {
		return err
	}

	if raw, found := object["id"]; found {
		err = json.Unmarshal(raw, &a.Id)
		if err != nil {
			return fmt.Errorf("error reading 'id': %w", err)
		}
		delete(object, "id")
	}

	if len(object) != 0 {
		a.AdditionalProperties = make(map[string]struct {
			Foo *string `json:"foo,omitempty"`
		})
		for fieldName, fieldBuf := range object {
			var fieldVal struct {
				Foo *string `json:"foo,omitempty"`
			}
			err := json.Unmarshal(fieldBuf, &fieldVal)
			if err != nil {
				return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
			}
			a.AdditionalProperties[fieldName] = fieldVal
		}
	}
	return nil
}

// Override default JSON handling for Thing to handle AdditionalProperties
func (a Thing) MarshalJSON() ([]byte, error) {
	var err error
	object := make(map[string]json.RawMessage)

	object["id"], err = json.Marshal(a.Id)
	if err != nil {
		return nil, fmt.Errorf("error marshaling 'id': %w", err)
	}

	for fieldName, field := range a.AdditionalProperties {
		object[fieldName], err = json.Marshal(field)
		if err != nil {
			return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
		}
	}
	return json.Marshal(object)
}

Examples

The examples directory contains some additional cases which are useful examples for how to use oapi-codegen, including how you'd take the Petstore API and implement it with oapi-codegen.

Frequently Asked Questions (FAQs)

How does oapi-codegen handle anyOf, allOf and oneOf?

oapi-codegen supports anyOf, allOf and oneOf for generated code.

For instance, through the following OpenAPI spec:

openapi: "3.0.0"
info:
  version: 1.0.0
  title: Using complex schemas
  description: An example of `anyOf`, `allOf` and `oneOf`
components:
  schemas:
    # base types
    Client:
      type: object
      required:
        - name
      properties:
        name:
          type: string
    Identity:
      type: object
      required:
        - issuer
      properties:
        issuer:
          type: string

    # allOf performs a union of all types defined
    ClientWithId:
      allOf:
        - $ref: '#/components/schemas/Client'
        - properties:
            id:
              type: integer
          required:
            - id

    # allOf performs a union of all types defined, but if there's a duplicate field defined, it'll be overwritten by the last schema
    # https://github.com/oapi-codegen/oapi-codegen/issues/1569
    IdentityWithDuplicateField:
      allOf:
        # `issuer` will be ignored
        - $ref: '#/components/schemas/Identity'
        # `issuer` will be ignored
        - properties:
            issuer:
              type: integer
        # `issuer` will take precedence
        - properties:
            issuer:
              type: object
              properties:
                name:
                  type: string
              required:
                - name

    # anyOf results in a type that has an `AsClient`/`MergeClient`/`FromClient` and an `AsIdentity`/`MergeIdentity`/`FromIdentity` method so you can choose which of them you want to retrieve
    ClientAndMaybeIdentity:
      anyOf:
        - $ref: '#/components/schemas/Client'
        - $ref: '#/components/schemas/Identity'

    # oneOf results in a type that has an `AsClient`/`MergeClient`/`FromClient` and an `AsIdentity`/`MergeIdentity`/`FromIdentity` method so you can choose which of them you want to retrieve
    ClientOrIdentity:
      oneOf:
        - $ref: '#/components/schemas/Client'
        - $ref: '#/components/schemas/Identity'

This results in the following types:

Base types
// Client defines model for Client.
type Client struct {
	Name string `json:"name"`
}

// Identity defines model for Identity.
type Identity struct {
	Issuer string `json:"issuer"`
}
allOf
// ClientWithId defines model for ClientWithId.
type ClientWithId struct {
	Id   int    `json:"id"`
	Name string `json:"name"`
}

// IdentityWithDuplicateField defines model for IdentityWithDuplicateField.
type IdentityWithDuplicateField struct {
	Issuer struct {
		Name string `json:"name"`
	} `json:"issuer"`
}
anyOf
import (
	"encoding/json"

	"github.com/oapi-codegen/runtime"
)

// ClientAndMaybeIdentity defines model for ClientAndMaybeIdentity.
type ClientAndMaybeIdentity struct {
	union json.RawMessage
}

// AsClient returns the union data inside the ClientAndMaybeIdentity as a Client
func (t ClientAndMaybeIdentity) AsClient() (Client, error) {
	var body Client
	err := json.Unmarshal(t.union, &body)
	return body, err
}

// FromClient overwrites any union data inside the ClientAndMaybeIdentity as the provided Client
func (t *ClientAndMaybeIdentity) FromClient(v Client) error {
	b, err := json.Marshal(v)
	t.union = b
	return err
}

// MergeClient performs a merge with any union data inside the ClientAndMaybeIdentity, using the provided Client
func (t *ClientAndMaybeIdentity) MergeClient(v Client) error {
	b, err := json.Marshal(v)
	if err != nil {
		return err
	}

	merged, err := runtime.JSONMerge(t.union, b)
	t.union = merged
	return err
}

// AsIdentity returns the union data inside the ClientAndMaybeIdentity as a Identity
func (t ClientAndMaybeIdentity) AsIdentity() (Identity, error) {
	var body Identity
	err := json.Unmarshal(t.union, &body)
	return body, err
}

// FromIdentity overwrites any union data inside the ClientAndMaybeIdentity as the provided Identity
func (t *ClientAndMaybeIdentity) FromIdentity(v Identity) error {
	b, err := json.Marshal(v)
	t.union = b
	return err
}

// MergeIdentity performs a merge with any union data inside the ClientAndMaybeIdentity, using the provided Identity
func (t *ClientAndMaybeIdentity) MergeIdentity(v Identity) error {
	b, err := json.Marshal(v)
	if err != nil {
		return err
	}

	merged, err := runtime.JSONMerge(t.union, b)
	t.union = merged
	return err
}

func (t ClientAndMaybeIdentity) MarshalJSON() ([]byte, error) {
	b, err := t.union.MarshalJSON()
	return b, err
}

func (t *ClientAndMaybeIdentity) UnmarshalJSON(b []byte) error {
	err := t.union.UnmarshalJSON(b)
	return err
}


oneOf
// AsClient returns the union data inside the ClientOrIdentity as a Client
func (t ClientOrIdentity) AsClient() (Client, error) {
	var body Client
	err := json.Unmarshal(t.union, &body)
	return body, err
}

// FromClient overwrites any union data inside the ClientOrIdentity as the provided Client
func (t *ClientOrIdentity) FromClient(v Client) error {
	b, err := json.Marshal(v)
	t.union = b
	return err
}

// MergeClient performs a merge with any union data inside the ClientOrIdentity, using the provided Client
func (t *ClientOrIdentity) MergeClient(v Client) error {
	b, err := json.Marshal(v)
	if err != nil {
		return err
	}

	merged, err := runtime.JSONMerge(t.union, b)
	t.union = merged
	return err
}

// AsIdentity returns the union data inside the ClientOrIdentity as a Identity
func (t ClientOrIdentity) AsIdentity() (Identity, error) {
	var body Identity
	err := json.Unmarshal(t.union, &body)
	return body, err
}

// FromIdentity overwrites any union data inside the ClientOrIdentity as the provided Identity
func (t *ClientOrIdentity) FromIdentity(v Identity) error {
	b, err := json.Marshal(v)
	t.union = b
	return err
}

// MergeIdentity performs a merge with any union data inside the ClientOrIdentity, using the provided Identity
func (t *ClientOrIdentity) MergeIdentity(v Identity) error {
	b, err := json.Marshal(v)
	if err != nil {
		return err
	}

	merged, err := runtime.JSONMerge(t.union, b)
	t.union = merged
	return err
}

func (t ClientOrIdentity) MarshalJSON() ([]byte, error) {
	b, err := t.union.MarshalJSON()
	return b, err
}

func (t *ClientOrIdentity) UnmarshalJSON(b []byte) error {
	err := t.union.UnmarshalJSON(b)
	return err
}

For more info, check out the example code.

How can I ignore parts of the spec I don't care about?

By default, oapi-codegen will generate everything from the specification.

If you'd like to reduce what's generated, you can use one of a few options in the configuration file to tune the generation of the resulting output:

# yaml-language-server: $schema=https://raw.githubusercontent.com/doordash/oapi-codegen/HEAD/configuration-schema.json
filter:
  include:
    paths: []
    tags: []
    operation-ids: []
    schema-properties:
    extensions: []
  exclude:
    operation-ids: []

License

This project is licensed under the Apache License 2.0.
See LICENSE.txt for details.

Notices

See NOTICE.txt for third-party components and attributions.

Contributor License Agreement (CLA)

Contributions to this project require agreeing to the DoorDash Contributor License Agreement.
See CONTRIBUTOR_LICENSE_AGREEMENT.txt.

Directories

Path Synopsis
cmd
oapi-codegen command
pkg

Jump to

Keyboard shortcuts

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