Real payloads have variants, and how you model them decides whether SDKs get usable types.
JSON Schema composition keywords:
allOf: must match all subschemas. Used to extend a base schema (allOf: [$ref Pet, {properties: {...}}]).oneOf: must match exactly one subschema. Used for alternatives like payment methods.anyOf: must match at least one. Rarely what you want for typed SDKs.not: must not match.
oneOf is strict: if two alternatives both accept an object (e.g. neither forbids extra properties), the payload matches both and validation fails. Make variants mutually exclusive with required fields, const values or additionalProperties: false.
A discriminator names the property that tells variants apart, e.g. type: card. It is an OpenAPI addition (not JSON Schema) that helps code generators and validators choose the right class quickly. With mapping you connect values to schemas explicitly; otherwise the schema name is used. In 3.2, defaultMapping adds a fallback.
Give each variant a const for its discriminator value, so the document validates correctly even for tools that ignore discriminator.
Generated code quality varies a lot across generators with deep allOf chains, so keep composition shallow and test what your SDK generator produces.
Example
components:
schemas:
Payment:
oneOf:
- $ref: '#/components/schemas/CardPayment'
- $ref: '#/components/schemas/BankPayment'
discriminator:
propertyName: method
mapping:
card: '#/components/schemas/CardPayment'
bank: '#/components/schemas/BankPayment'
PaymentBase:
type: object
required: [method, amountCents]
properties:
amountCents: { type: integer, minimum: 1 }
CardPayment:
allOf:
- $ref: '#/components/schemas/PaymentBase'
- { type: object, required: [cardToken], properties: { method: { const: card }, cardToken: { type: string } } }
BankPayment:
allOf:
- $ref: '#/components/schemas/PaymentBase'
- { type: object, required: [iban], properties: { method: { const: bank }, iban: { type: string } } }Remember
- allOf = all, oneOf = exactly one, anyOf = at least one
- Make oneOf variants mutually exclusive or validation fails
- A discriminator names the property that selects the variant
- Use
conston the discriminator property in each variant
Watch out for
- oneOf variants that overlap, so valid payloads fail with 'matches more than one schema'.