DEV Community

Umar Tahir
Umar Tahir

Posted on

`allOf` vs `oneOf` vs `anyOf` in OpenAPI (with examples)

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
Enter fullscreen mode Exit fullscreen mode

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'
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
{
  "type": "inverter",
  "reverseFlow": true
}
Enter fullscreen mode Exit fullscreen mode

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'
Enter fullscreen mode Exit fullscreen mode

This allows requests that:

  • Match one schema
  • Match multiple schemas

PATCH + Overlapping Fields: The Key Insight

Consider this PATCH request:

{
  "reverseFlow": true
}
Enter fullscreen mode Exit fullscreen mode

If:

  • reverseFlow exists 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 recommended
  • allOf is great for base + extensions
  • anyOf is 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)