Skip to content

Additional Properties

OpenAPI's additionalProperties keyword allows schemas to accept fields that aren't explicitly defined in the schema. This is useful for creating flexible APIs that can handle dynamic or user-defined fields.

Overview

When you use additionalProperties in your OpenAPI spec, oapi-codegen generates Go code that can handle both: - Defined properties: Fields explicitly listed in the schema's properties section - Additional properties: Any extra fields not in the schema definition

Basic Usage

Type Aliases for Maps

When a schema consists only of additionalProperties (no explicit properties), oapi-codegen generates a type alias to a Go map:

    users:
      type: object
      additionalProperties:
        $ref: '#/components/schemas/user'

Generates:

type Users map[string]User

Explicit additionalProperties: true

Using additionalProperties: true creates a map that accepts any value type:

    location:
      type: object
      additionalProperties: true
      nullable: true

Generates:

type Location map[string]any

Typed Additional Properties

You can specify the type of additional property values:

    optional-items:
      additionalProperties:
        type: string
        nullable: true

Generates:

type OptionalItems map[string]*string

Mixed Properties and Additional Properties

When a schema has both explicit properties and additionalProperties, oapi-codegen generates a struct with: - Regular fields for defined properties - An AdditionalProperties field (with json:"-" tag) - Get() and Set() methods for accessing additional properties - Custom MarshalJSON() and UnmarshalJSON() methods

Example schema:

    referenceWithRequiredExtra:
      type: object
      properties:
        index:
          $ref: '#/components/schemas/reference'
      additionalProperties:
        $ref: '#/components/schemas/reference'

Generated code:

type ReferenceWithRequiredExtra struct {
    Index                *Reference           `json:"index,omitempty"`
    AdditionalProperties map[string]Reference `json:"-"`
}

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

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

The custom JSON marshaling ensures that additional properties are serialized alongside defined properties in the JSON output.

Advanced Scenarios

Nested Additional Properties

You can nest additionalProperties to create multi-level maps:

metadata:
  type: object
  additionalProperties:
    additionalProperties:
      additionalProperties:
        $ref: "#/components/schemas/Metadata"

Generates:

Metadata map[string]map[string]map[string]Metadata

View nested example

Self-Referencing Schemas

Schemas can reference themselves via additionalProperties:

AggregatedResult:
  type: object
  properties:
    totalClicks:
      type: integer
    hourlyBreakDown:
      type: object
      additionalProperties:
        $ref: '#/components/schemas/AggregatedResult'

Generates:

type AggregatedResult struct {
    TotalClicks     *int                        `json:"totalClicks,omitempty"`
    HourlyBreakDown map[string]AggregatedResult `json:"hourlyBreakDown,omitempty"`
}

View self-reference example

Validation

For map types, oapi-codegen generates Validate() methods that validate each value in the map:

func (u Users) Validate() error {
    var errors runtime.ValidationErrors
    for k, v := range u {
        if validator, ok := any(v).(runtime.Validator); ok {
            if err := validator.Validate(); err != nil {
                errors = errors.Append(k, err)
            }
        }
    }
    if len(errors) == 0 {
        return nil
    }
    return errors
}

Complete Examples

For comprehensive examples including: - Property count constraints (minProperties, maxProperties) - String length constraints in map values - Required fields in additional property values - oneOf in additional properties - And more...

View complete examples