5 / 6

Lesson 5: Combining Schemas

Schema Editor
Data Editor
Validation Result

Type in the editors to see validation results.

allOfanyOfoneOfif/then/else

"allOf" requires the data to satisfy every sub-schema in the array simultaneously, useful for merging requirements. "anyOf" requires the data to match at least one sub-schema, while "oneOf" requires it to match exactly one. The "if/then/else" keywords enable conditional validation: if the data satisfies the "if" schema, the "then" schema is also applied; otherwise the "else" schema is applied. This is particularly powerful for modeling discriminated unions like different payment method shapes.

Why This Matters

Real-world data is rarely one uniform shape — a payment can be a card, a bank transfer, or cash, each needing different required fields; a webhook event can be one of a dozen event types with a shared envelope but a different payload. Without combinators, you'd either write one loose schema that fails to catch shape-specific mistakes, or maintain the conditional logic by hand in application code, disconnected from the schema. "if/then/else" and "oneOf" let you express these discriminated unions directly in the schema, so a single JSON Schema document can validate an entire family of related shapes and stay the single source of truth for API documentation and generated types.

Common Mistakes

  • Reaching for "anyOf" when the branches are meant to be mutually exclusive."anyOf" happily accepts data that matches more than one branch, which can hide genuinely ambiguous data. If exactly one shape should ever apply — like exactly one payment method — use "oneOf" so overlapping matches become a validation error instead of passing silently.
  • Combining "allOf" (often via $ref) with "additionalProperties": false in one of the branches.This is the classic "allOf + additionalProperties" gotcha: each sub-schema in "allOf" is evaluated independently, so a branch with additionalProperties: false will reject properties defined by a sibling branch, even though the merged shape looks like it should allow them. Prefer applying additionalProperties: false once, at the outermost schema, rather than inside an allOf branch.
  • Nesting if/then/else many levels deep with no final else.Without a trailing else, data that matches none of the "if" conditions gets no extra constraints applied at all, which can silently let invalid combinations through. Always account for the "none of the above" case explicitly.
  • Expecting a single, simple error message when "oneOf" fails.When none of the oneOf branches match, most validators report one set of errors per branch, which can look like a wall of noise. Read it as "here's why each option failed" rather than one linear error.

Challenge

Change paymentType to 'bank_transfer'. Notice cardNumber is no longer required but accountNumber is. Fix the data.

Frequently Asked Questions

"anyOf" passes if the data matches one or more of the listed sub-schemas. "oneOf" passes only if the data matches exactly one — if it satisfies two or more branches, oneOf fails even though anyOf would have passed.

Each schema inside "allOf" is validated independently against the whole object. If one branch sets additionalProperties: false, it doesn't know about properties introduced by a sibling branch or by the object merging conceptually — so it rejects them. Put additionalProperties: false on the single top-level schema instead of inside an allOf branch.

Yes — nest another if/then/else inside the "else" branch, as shown in this lesson's schema, to handle three or more mutually exclusive cases (card, bank_transfer, cash). For many branches, oneOf with a shared discriminator field is often more readable.

Implementations vary, but most report the failure reasons for every branch, since there's no single 'correct' one to blame. Expect a list of per-branch errors rather than one pinpoint message, and use it to see which branch the data was probably meant to satisfy.