{"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"how-to-use-allof-in-openapi","__idx":0},"children":["How to use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]}," in OpenAPI"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use of ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]}," comes from the desire for reuse."," ","When you have a single source of truth, maintenance is easier."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This makes sense."," ","You might want to reuse a lot of things."," ","But ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]}," is not appropriate in many cases and can result in illogical schemas."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["How do you know when to use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]}," and when to avoid it?"," ","This article covers:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["how to use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["how ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]}," is evaluated"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["valid use cases"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["common language patterns that warn that ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]}," use is not appropriate"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"usage-of-allof","__idx":1},"children":["Usage of ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Declare ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]}," as an array of schemas."]},{"$$mdtype":"Tag","name":"blockquote","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["All of these keywords must be set to an array, where each item is a schema."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This works in YAML."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"yaml","header":{"controls":{"copy":{}}},"source":"allOf:\n  - title: time\n    type: object\n    properties:\n      time:\n        type: string\n  - title: date\n    type: object\n    properties:\n      date:\n        type: string\n","lang":"yaml"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["And it works in JSON."," ","The remainder of this article uses YAML for schema definitions."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"allOf\": [\n    {\n      \"title\": \"time\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"time\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    {\n      \"title\": \"date\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"date\": {\n          \"type\": \"string\"\n        }\n      }\n    }\n  ]\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"evaluation-of-allof","__idx":2},"children":["Evaluation of ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A goal of JSON Schema is to be able to evaluate if JSON is valid or invalid with the defined schema."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["From the definition of ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]},", it is treated like a logical ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AND"]},":"]},{"$$mdtype":"Tag","name":"blockquote","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Must be valid against ",{"$$mdtype":"Tag","name":"em","attributes":{},"children":["all"]}," of the subschemas"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"js","header":{"controls":{"copy":{}}},"source":"$time && $date\n","lang":"js"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Based on our prior ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]}," declaration which requires ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["time"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["date"]}," schemas, the following JSON would match the schemas:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"time\": \"08:15:00+06:00\",\n  \"date\": \"2022-01-22\"\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Does the following JSON match the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]}," too?"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"date\": \"2022-01-22\"\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The \"time\" property is missing, and you may think that it only matches the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["date"]}," schema."," ","However, neither schema, including the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["time"]}," schema, has any required properties."," ","Therefore, it matches all of the schemas."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["In the same way, the following JSON matches the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]}," schemas too."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"temperature\": 25,\n  \"unit\": \"C\"\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["That doesn't seem right."," ","But it is."," ","The schema declares what some properties types must be if they are present."," ","It didn't declare them as required."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The following schema is invalid, because ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["date"]}," is not a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["string"]},"."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"temperature\": 25,\n  \"unit\": \"C\",\n  \"date\": 22\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If you declare a media type examples in your OpenAPI definition, and turn on the ",{"$$mdtype":"Tag","name":"Link","attributes":{"href":"/docs/cli/rules/oas/no-invalid-media-type-examples"},"children":["no-invalid-media-type-examples rule"]},", Redocly evaluates the examples against the schema to help you evaluate them."," ","You can also do this be evaluating real API responses with API testing. ",{"$$mdtype":"Tag","name":"Link","attributes":{"href":"/contact-us"},"children":["Contact us"]}," if you're interested in doing that."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"valid-cases","__idx":3},"children":["Valid cases"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["There are times when schemas are a combination of two pre-existing schemas."," ","If you find yourself wanting to add \"with minor exceptions\", then do not use the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]}," keyword, no matter how tempting."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For example, let's say you have a resource for User."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"yaml","header":{"controls":{"copy":{}}},"source":"title: User\nrequired:\n  - id\n  - email\ntype: object\nproperties:\n  id:\n    type: string\n  name:\n    type: string\n  email:\n    type: string\n  avatar:\n    type: string\n  phone:\n    type: string\n  dob:\n    type: string\n  createdAt:\n    type: string\n  recentLogInAt:\n    type: string\n","lang":"yaml"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["And then you have other resources that use an excerpt of the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["User"]}," schema such as ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["id"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["name"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["email"]},", and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["avatar"]},"."," ","(The topic of ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["API design"]}," is different from the topic of ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["API description"]},", and this article doesn't cover if you ",{"$$mdtype":"Tag","name":"em","attributes":{},"children":["should"]}," design an API this way.)"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["In order to reuse that excerpt of the User schema, you could rework the schema as follows."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"yaml","header":{"controls":{"copy":{}}},"source":"title: UserExcerpt\nrequired:\n  - id\n  - email\ntype: object\nproperties:\n  id:\n    type: string\n  name:\n    type: string\n  email:\n    type: string\n  avatar:\n    type: string\n","lang":"yaml"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Then, you could use that in the User and any other schemas with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]},"."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"yaml","header":{"controls":{"copy":{}}},"source":"title: User\nallOf:\n  - $ref: '#/components/schemas/UserExcerpt'\n  - type: object\n    properties:\n      phone:\n        type: string\n      dob:\n        type: string\n      createdAt:\n        type: string\n      recentLogInAt:\n        type: string\n","lang":"yaml"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["And another schema could reuse it similarly."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"yaml","header":{"controls":{"copy":{}}},"source":"title: ParkingSpot\nallOf:\n  - $ref: '#/components/schemas/UserExcerpt'\n  - type: object\n    properties:\n      licenseExpiration:\n        type: string\n      spotId:\n        type: string\n","lang":"yaml"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"siblings-to-ref-s","__idx":4},"children":["Siblings to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["$ref"]},"s"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["OpenAPI 3.0 has a limitation related to reuse."," ","Schemas have some properties that are informational and do not impact the validation of JSON."," ","Two of those properties are ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["summary"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["description"]},"."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A common use case is the desire to reuse the schema by change the description due to the context."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["OpenAPI 3.1 allows for siblings next to the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["$ref"]},"."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"yaml","header":{"controls":{"copy":{}}},"source":"type: object\nproperties:\n  transactionId:\n    $ref: '#/components/schemas/ResourceId'\n    description: ID of the transaction.\n","lang":"yaml"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["OpenAPI 3.0 and prior do not allow for siblings next to the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["$ref"]},", but the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]}," keyword could be used above it as a \"workaround\"."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"yaml","header":{"controls":{"copy":{}}},"source":"type: object\nproperties:\n  transactionId:\n    description: ID of the transaction.\n    allOf:\n      - $ref: '#/components/schemas/ResourceId'\n","lang":"yaml"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This behavior confuses people, and some people think of it as a way to override the reference object properties."," ","This is only for informational properties and not for properties that are used for evaluation."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"illogical-schemas-from-allof-misuse","__idx":5},"children":["Illogical schemas from ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]}," misuse"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Word to watch out for that could indicate misuse:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["override"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["extend"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"type-override-is-invalid","__idx":6},"children":["Type override is invalid"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Overriding a description and summary is allowed."," ","From an evaluation perspective, it works because the description is going to match any type."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The following example references a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ResourceId"]}," schema and its type is a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["string"]},"."," ","Therefore, the following example is illogical because ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["transactionId"]}," cannot be an ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["integer"]}," ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["and"]}," a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["string"]},"."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"yaml","header":{"controls":{"copy":{}}},"source":"type: object\nproperties:\n  transactionId:\n    description: ID of the transaction.\n    type: integer\n    allOf:\n      - $ref: '#/components/schemas/ResourceId'\n","lang":"yaml"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"different-types-are-invalid","__idx":7},"children":["Different types are invalid"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The following example demonstrates illogical schemas where types mismatch within a list of schemas provided to the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]}," keyword."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"yaml","header":{"controls":{"copy":{}}},"source":"allOf:\n  - $ref: '#/components/schemas/Foo'\n  - $ref: '#/components/schemas/Bar'\n","lang":"yaml"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Foo"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Bar"]}," are not of the same type, then the logical ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AND"]}," cannot be true."," ","For example, something cannot be a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["string"]}," and an ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["object"]}," at the same time."," ","Sometimes, this is more difficult to notice when using reference objects."," ","However, it's clear when written the following way."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"yaml","header":{"controls":{"copy":{}}},"source":"allOf:\n  - type: string\n  - type: object\n","lang":"yaml"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"closed-schemas-and-allof-are-invalid","__idx":8},"children":["Closed schemas and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]}," are invalid"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Even when the schemas are of the same type, there can still be illogical conflicts when using the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]}," keyword."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The following schema demonstrates and illogical conflict."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"yaml","header":{"controls":{"copy":{}}},"source":"allOf:\n  - type: object\n    properties:\n      date:\n        type: string\n    additionalProperties: false\n  - type: object\n    properties:\n      time:\n        type: string\n    additionalProperties: false\n","lang":"yaml"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["additionalProperties: false"]}," means that the schema cannot have any additional properties."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The following is invalid, because it matches the first schema, but the second schema does not have ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["date"]}," declared as a property and it declares there cannot be any additional properties."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"date\": \"2022-01-22\"\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"summary","__idx":9},"children":["Summary"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["In Swagger 2.0 or OpenAPI 3.0, use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]}," to override a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["description"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["summary"]}," of a schema."," ","In OpenAPI 3.1, use a sibling to the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["$ref"]}," to override a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["description"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["summary"]},"."," ","Do ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["NOT"]}," override any other properties including ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["type"]},"."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]}," keyword as a logical ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AND"]},"."," ","Be aware of common illogical combinations:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["mismatched types"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["schemas where additional properties are not allowed"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]}," keyword may be used with ",{"$$mdtype":"Tag","name":"Link","attributes":{"href":"/learn/openapi/discriminator"},"children":["the discriminator"]},"."," ","Also, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]}," is almost always used with at least one ",{"$$mdtype":"Tag","name":"Link","attributes":{"href":"/learn/openapi/ref-guide"},"children":["reference object"]},"."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Consider cases where the schema is the same with one minor exception as a possible design problem."," ","Refactoring to use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]}," may not be a good idea for those scenarios."]}]},"frontmatter":{},"tagList":[],"title":"How to use allOf in OpenAPI","lastModified":"2025-05-28T16:01:32.000Z"}