# Reuse and Composition: $ref, allOf, oneOf, anyOf and Discriminators — OpenAPI / Swagger

Source: https://www.skillbyai.com/en/openapi/s-compose

> Reuse schemas and model inheritance and alternatives.

## Building complex models from parts

Define schemas once under **`components/schemas`** and reference them with **`$ref: '#/components/schemas/Order'`**, or reference other files (`$ref: './schemas/order.yaml'`). Composition keywords combine schemas. **`allOf`**: the value must satisfy **all** listed schemas, used to extend a base schema (a `PhysicalProduct` is a `Product` plus weight). **`oneOf`**: the value must match **exactly one** schema, used for alternatives such as payment methods (UPI, card or net banking). **`anyOf`**: the value must match **at least one**. **`not`** excludes a schema. For `oneOf` polymorphism, add a **`discriminator`** naming the property that tells variants apart (`method`), optionally with a `mapping` from values to schemas; code generators use it to create subtypes and deserialise correctly. Keep composition simple: deeply nested `allOf`/`oneOf` chains confuse readers and many generators. Note that `oneOf` requires exactly one match, so overlapping variants (both accepting the same data) fail validation; make variants distinguishable with required fields or `const` values.

## Polymorphic payment methods with a discriminator

Each variant is distinguishable by its method value.

```yaml
components:
  schemas:
    PaymentMethod:
      oneOf:
        - $ref: '#/components/schemas/UpiPayment'
        - $ref: '#/components/schemas/CardPayment'
        - $ref: '#/components/schemas/NetBankingPayment'
      discriminator:
        propertyName: method
        mapping:
          UPI: '#/components/schemas/UpiPayment'
          CARD: '#/components/schemas/CardPayment'
          NETBANKING: '#/components/schemas/NetBankingPayment'

    PaymentBase:
      type: object
      required: [method, amountInr]
      properties:
        method: { type: string }
        amountInr: { type: string, pattern: '^\d+\.\d{2}$' }

    UpiPayment:
      allOf:
        - $ref: '#/components/schemas/PaymentBase'
        - type: object
          required: [vpa]
          properties:
            method: { const: UPI }
            vpa: { type: string, examples: ['asha@okbank'] }

    CardPayment:
      allOf:
        - $ref: '#/components/schemas/PaymentBase'
        - type: object
          required: [cardToken]
          properties:
            method: { const: CARD }
            cardToken: { type: string, description: Token from the card vault, never a raw card number }

    NetBankingPayment:
      allOf:
        - $ref: '#/components/schemas/PaymentBase'
        - type: object
          required: [bankCode]
          properties:
            method: { const: NETBANKING }
            bankCode: { type: string }
```

## A form with sections that depend on a tick box

A payment form shows UPI fields if you tick UPI, card fields if you tick card. `oneOf` with a discriminator is that form: the ticked box decides which section must be filled in.

**Quiz:** Which composition keyword requires a value to match exactly one of several schemas?

- [ ] allOf
- [ ] anyOf
- [ ] not
- [x] oneOf

*Answer:* oneOf. oneOf succeeds only when exactly one alternative validates.
