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