{"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"how-to-use-the-openapi-discriminator","__idx":0},"children":["How to use the OpenAPI discriminator"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When an API can return two or more different types of objects (aka polymorphism), use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["oneOf"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["anyOf"]}," to describe those schemas (a JSON Schema concept)."," ","You might also want to use the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["discriminator"]}," (an OpenAPI concept)."," ","But why?"," ","And how?"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"oneof-vs-anyof","__idx":1},"children":["oneOf vs. anyOf"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["anyOf"]}," when the item might be valid against more than one of the schemas."," ","Use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["oneOf"]}," when it can ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["only"]}," be valid against one of the schemas."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["How could it be valid against more than one of the schemas?"," ","This is easier than you may initially think."," ","Two schemas with some overlapping properties and no other required properties indicate the need for ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["anyOf"]},"."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The examples below with the vehicles would require ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["anyOf"]}," to be valid."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["oneOf"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["anyOf"]}," are visually presented in our reference docs by choice of buttons."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"Image","attributes":{"src":"/content-assets/1.vehicle-anyOf-208f7070aca28d21.png","alt":"anyOf with title"},"children":[]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Control the button labels by defining a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["title"]}," in the corresponding object schema."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"yaml","header":{"controls":{"copy":{}}},"source":"type: object\ntitle: Gas-powered Vehicle\nproperties:\n  vehicleType:\n    description: The type of vehicle.\n","lang":"yaml"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"Image","attributes":{"src":"/content-assets/2.vehicle-anyOf-9ae09b5b93a4a2c1.png","alt":"anyOf with title"},"children":[]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"when-to-use-the-openapi-discriminator","__idx":2},"children":["When to use the OpenAPI discriminator"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Whenever you see the discriminator used, engage in this dialog:"]},{"$$mdtype":"Tag","name":"blockquote","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The discriminator adds complexity. Is it necessary?"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If the clarity gained by describing the objects distinctly is greater than the cost of the complexity added by doing so, then it may be a good idea to use the discriminator."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["It is also possible to create nested discriminators (which involves extra complexity and should be used sparingly)."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The discriminator explicitly declares which property you can inspect to determine the object type."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"Electric Vehicle","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"yaml","header":{"controls":{"copy":{}}},"source":"type: object\ndescription: Electric Vehicle\nproperties:\n  vehicleType:\n    description: The type of vehicle.\n    type: string\n    example: Tesla\n  idealTerrain:\n    type: string\n    description: A road, river, air... Where does this vehicle thrive?\n    example: roads\n  topSpeed:\n    description: The top speed in kilometers per hour rounded to the nearest integer.\n    type: integer\n    example: 83\n  range:\n    description: The 95th percentile range of a trip in kilometers.\n    type: integer\n    example: 100\n  powerSource:\n    description: How is the vehicle powered.\n    type: string\n    example: electricity\n  chargeSpeed:\n    description: In range kilometers per hour.\n    type: integer\n  chargeAmps:\n    description: Amps recommended for charging.\n    type: integer\n  chargeVoltage:\n    description: Voltage recommended for charging.\n    type: integer\n","lang":"yaml"},"children":[]}]},{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"Fueled Vehicle","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"yaml","header":{"controls":{"copy":{}}},"source":"type: object\ntitle: Gas-powered Vehicle\nproperties:\n  vehicleType:\n    description: The type of vehicle.\n    type: string\n    example: car\n  idealTerrain:\n    type: string\n    example: roads\n  topSpeed:\n    description: The top speed in kilometers per hour rounded to the nearest integer.\n    type: integer\n    example: 83\n  range:\n    description: The 95th percentile range of a trip in kilometers.\n    type: integer\n    example: 100\n  powerSource:\n    description: Describes how the vehicle is powered.\n    type: string\n    example: gasoline\n  tankCapacity:\n    type: number\n    format: double\n    description: Capacity of the fuel tank in gallons.\n  milesPerGallon:\n    type: number\n    format: double\n    description: Miles per gallon on the highway.\n","lang":"yaml"},"children":[]}]},{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"Pedaled Vehicle","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"yaml","header":{"controls":{"copy":{}}},"source":"type: object\ndescription: Pedaled Vehicle\nproperties:\n  vehicleType:\n    description: The type of vehicle.\n    type: string\n    example: bicycle\n    enum:\n      - bicycle\n  idealTerrain:\n    type: string\n    example: roads\n  topSpeed:\n    description: The top speed in kilometers per hour rounded to the nearest integer.\n    type: integer\n    example: 83\n  range:\n    description: The 95th percentile range of a trip in kilometers.\n    type: integer\n    example: 100\n  powerSource:\n    description: How is the vehicle powered.\n    type: string\n    example: pedaling\n","lang":"yaml"},"children":[]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The discriminator must apply to the same level of the schema it is declared in (common mistake when using nested objects)."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Also, it must be used in combination with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["anyOf"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["oneOf"]},", or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]},"."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["We represent the discriminator like a pull down menu on the discriminated property."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"yaml","header":{"controls":{"copy":{}}},"source":"  requestBody:\n    content:\n      application/json:\n        schema:\n          discriminator:\n            propertyName: powerSource\n            mapping:\n              electricity: ../components/schemas/ElectricVehicle.yaml\n              gasoline: ../components/schemas/FueledVehicle.yaml\n              human-energy: ../components/schemas/PedaledVehicle.yaml\n          anyOf:\n            - $ref: ../components/schemas/ElectricVehicle.yaml\n            - $ref: ../components/schemas/FueledVehicle.yaml\n            - $ref: ../components/schemas/PedaledVehicle.yaml\n","lang":"yaml"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["In this example the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["powerSource"]}," property must be declared in each of the corresponding schemas."]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"warning"},"children":["The discriminated property must be of type string."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["mapping"]}," is optional and we ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["recommend"]}," using it explicitly."," ","If it is not explicitly declared, implicit ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["mapping"]}," is introspected from the schema names from the list of schemas included in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]},"/",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["anyOf"]},"/",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["oneOf"]}," including ",{"$$mdtype":"Tag","name":"Link","attributes":{"href":"#allof-for-inheritance"},"children":["children schema"]}," names."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Schema names (including case) must match exactly to the discriminated properties values."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A better alternative is to use the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["mapping"]}," property and making the names explicitly declared."," ","The possible values are determined from introspection by the schema names."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"Image","attributes":{"src":"/content-assets/3.vehicle-discriminator-4a80e674261a5c90.gif","alt":"discriminator gif"},"children":[]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"allof-for-inheritance","__idx":3},"children":["allOf for inheritance"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Another common technique used with the discriminator is to define a base schema, and then inherit from it using ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]},"."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For example, we could have created a base ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Vehicle"]}," schema."," ","Then, each of the specific implementations would \"extend\" the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Vehicle"]}," schema using ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]},":"]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"Vehicle.yaml","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"yaml","header":{"controls":{"copy":{}}},"source":"type: object\ndescription: Vehicle\ndiscriminator:\n  propertyName: powerSource\n  mapping:\n    electricity: ./ElectricVehicle.yaml\n    gasoline: ./FueledVehicle.yaml\n    human-energy: ./PedaledVehicle.yaml\nproperties:\n  vehicleType:\n    description: The type of vehicle.\n    type: string\n    example: bicycle\n  idealTerrain:\n    type: string\n    example: roads\n  powerSource:\n    description: How is the vehicle powered.\n    type: string\n    example: pedaling\n","lang":"yaml"},"children":[]}]},{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"PedaledVehicle.yaml","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"yaml","header":{"controls":{"copy":{}}},"source":"# I think of allOf like a \"merge\"\nallOf:\n  - $ref: ./Vehicle.yaml\n  - type: object\n    description: Pedaled Vehicle\n    properties:\n      topSpeed:\n        description: The top speed in kilometers per hour rounded to the nearest integer.\n        type: integer\n        example: 83\n      range:\n        description: The 95th percentile range of a trip in kilometers.\n        type: integer\n        example: 100\n","lang":"yaml"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"common-mistakes","__idx":4},"children":["Common mistakes"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"property-outside-of-the-object","__idx":5},"children":["Property outside of the object"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The discriminator property name is not inside of the object."," ","This typically causes the object to not be rendered."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"Image","attributes":{"src":"/content-assets/4.vehicle-common-mistake-f26d8f82f1f6825f.png","alt":"discriminator property outside of the object"},"children":[]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"case-sensitivity","__idx":6},"children":["Case sensitivity"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The discriminator property value is case sensitive (as well as the schema or mapping name)."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"discriminator-is-described-inline","__idx":7},"children":["Discriminator is described inline"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The discriminator must use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["anyOf"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["oneOf"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allOf"]},"."," ","When you define it inline, for example, as I did on a version of the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ElectricVehicle"]}," schema below, it ignores that schema (per the spec):"]},{"$$mdtype":"Tag","name":"blockquote","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When using the discriminator, inline schemas will not be considered."]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"yaml","header":{"controls":{"copy":{}}},"source":"type: object\ndescription: Electric Vehicle\ndiscriminator:\n  propertyName: powerSource\nproperties:\n  vehicleType:\n    description: The type of vehicle.\n    type: string\n    example: bicycle\n  idealTerrain:\n    type: string\n    description: A road, river, air... Where does this vehicle thrive?\n    example: roads\n  topSpeed:\n    description: The top speed in kilometers per hour rounded to the nearest integer.\n    type: integer\n    example: 83\n  range:\n    description: The 95th percentile range of a trip in kilometers.\n    type: integer\n    example: 100\n  powerSource:\n    description: How is the vehicle powered.\n    type: string\n    example: electricity\n  chargeSpeed:\n    description: In range kilometers per hour.\n    type: integer\n  chargeAmps:\n    description: Amps recommended for charging.\n    type: integer\n  chargeVoltage:\n    description: Voltage recommended for charging.\n    type: integer\n","lang":"yaml"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Catch mistakes early by using our ",{"$$mdtype":"Tag","name":"Link","attributes":{"href":"/redocly-cli"},"children":["Redocly CLI tool"]},"."]}]},"frontmatter":{},"tagList":["html","tab","tabs"],"title":"How to use the OpenAPI discriminator","lastModified":"2025-05-28T16:01:32.000Z"}