If you’ve worked with OpenAPI schemas, you’ve probably seen oneOf, anyOf, and allOf and wondered:
“They look similar… so when should I actually use each one?”
Let’s break them down with practical, API-design–focused examples.
allOf Composition / Inheritance
Meaning:
👉 The schema must satisfy all listed schemas.
Think of allOf as “AND”.
When to use it
- To compose schemas
- To model base + extension
Example
InverterCreate:
allOf:
- $ref: '#/components/schemas/ApplianceBase'
- type: object
properties:
reverseFlow:
type: boolean
What this means:
✔ The request must match ApplianceBase
✔ AND it must match other specific fields
This is perfect for:
- Base appliance fields (
name,location) - Plus type-specific fields
oneOf Exactly one schema
Meaning:
👉 The schema must match exactly one of the listed schemas.
Think of oneOf as “XOR”.
When to use it
- When schemas are mutually exclusive
- When you want strict validation
- Often combined with a discriminator
Example
oneOf:
- $ref: '#/components/schemas/InverterPatch'
- $ref: '#/components/schemas/EVPatch'
- $ref: '#/components/schemas/EVCSPatch'
Important detail ⚠️
If a request matches more than one schema, validation fails.
That’s why oneOf + PATCH + overlapping fields can be tricky.
With discriminator (recommended)
discriminator:
propertyName: type
{
"type": "inverter",
"reverseFlow": true
}
The discriminator tells OpenAPI which schema to use, removing ambiguity.
anyOf One or more schemas
Meaning:
👉 The schema must match at least one of the listed schemas.
Think of anyOf as “OR”.
When to use it
- When schemas overlap
- When flexibility is more important than strictness
- When multiple schema matches are acceptable
Example
anyOf:
- $ref: '#/components/schemas/InverterSpecificPatch'
- $ref: '#/components/schemas/EVSpecificPatch'
This allows requests that:
- Match one schema
- Match multiple schemas
PATCH + Overlapping Fields: The Key Insight
Consider this PATCH request:
{
"reverseFlow": true
}
If:
-
reverseFlowexists in multiple schemas - You’re using
oneOf
👉 OpenAPI cannot decide which schema applies
👉 Validation fails unless you use a discriminator
That’s why:
oneOf+ PATCH + overlapping fields → discriminator strongly recommendedallOfis great for base + extensionsanyOfis useful when overlap is intentional and acceptable
Quick decision table
| Goal | Use |
|---|---|
| Schema composition / inheritance | allOf |
| Exactly one valid schema | oneOf |
| Flexible matching | anyOf |
| PATCH with overlapping fields |
oneOf + discriminator or single schema |
| Strict API contracts | oneOf |
| Simpler client experience | Single schema / anyOf
|
Final takeaway
-
allOf= build schemas -
oneOf= enforce exclusivity -
anyOf= allow flexibility - Discriminators exist to remove ambiguity, especially for PATCH requests
If your API has polymorphic resources and partial updates, understanding this distinction is crucial to designing clean, predictable OpenAPI specs.
Top comments (0)