OneOf, anyOf, allOf Introduction

APIGit

2024-03-15

api-one-all-any

When designing or documenting an API with OpenAPI Specification (OAS), you'll often encounter the need to describe complex data structures. These structures might require the definition of various scenarios, such as different object structures for different conditions, a combination of multiple objects into one, or specifying that an object could match any one of several types. This is where oneOf, allOf, and anyOf shine, offering the flexibility and precision needed for these tasks.

Understanding allOf

allOf is used to combine multiple schemas into a single schema that includes all properties from the combined schemas. It's particularly useful when you want to create a complex schema that inherits properties from several other schemas.

For example, if you have a Person schema with common properties like name and age, and a Student schema that should include all properties of Person plus a studentId, you can use allOf to create the Student schema without repeating the Person properties.

components:
  schemas:
    Person:
      type: object
      properties:
        name:
          type: string
        age:
          type: integer
    Student:
      allOf:
        - $ref: '#/components/schemas/Person'
        - type: object
          properties:
            studentId:
              type: string

Exploring oneOf

oneOf specifies that the data should match exactly one of the referenced schemas. It's useful for defining different possible structures for a data object, where only one structure is valid for any given instance.

Consider an API endpoint that accepts a payment method, which could be either a credit card or a bank account, but not both. Using oneOf, you can define these options clearly:

components:
  schemas:
    CreditCard:
      type: object
      properties:
        number:
          type: string
        expiryDate:
          type: string
        cvv:
          type: string
    BankAccount:
      type: object
      properties:
        accountNumber:
          type: string
        routingNumber:
          type: string
    PaymentMethod:
      oneOf:
        - $ref: '#/components/schemas/CreditCard'
        - $ref: '#/components/schemas/BankAccount'

Deciphering anyOf

anyOf allows the data to match any (one or more) of the referenced schemas. It provides flexibility when the data could be in several forms, and there's no need for exclusivity as with oneOf.

For instance, if an API endpoint accepts a contact object that could be either a phone number, an email address, or both, you can use anyOf to represent this:

components:
  schemas:
    PhoneNumber:
      type: object
      properties:
        phone:
          type: string
    EmailAddress:
      type: object
      properties:
        email:
          type: string
    Contact:
      anyOf:
        - $ref: '#/components/schemas/PhoneNumber'
        - $ref: '#/components/schemas/EmailAddress'

Conclusion

The allOf, oneOf, and anyOf keywords add essential versatility to OpenAPI specifications, enabling the definition of complex and nuanced data models. By understanding and using these tools effectively, API designers and documenters can create more accurate and flexible API specifications. Whether you're inheriting properties, specifying exclusive types, or allowing multiple structures, these keywords ensure your API's data contracts are clear and robust.