OpenAPI Specification - Use of Discriminator and oneOf - Spectral listing

3.4k views Asked by At

OpenAPI Discriminator using oneOf

A minimal example of using a discriminator with an openApi spec and linting with Spectral.

Error message:

~/git/openapi_discriminator/openapi/v1/api.yaml
 22:23  error  oas3-valid-media-example  "example" property must match exactly one schema in oneOf  paths./discriminatortest.get.responses[200].content.application/json.example

Background

OpenAPI schema with simple GET method which can return different types of Animal.

A subclass of Animal is defined which can either be a Chicken or a Dog.

The only property Animals have are legs. A discriminator is used to distinguish between a Chicken or Dog where a Chicken has two legs and a Dog has four legs.

Aim

I was to verify that the example in a request response matches only one schema.

Question

I thought using a discriminator might mean that anything with two legs is a Chicken and anything with four legs is a Dog.

Am I mistaken and it is still legitimate for a Dog to have two legs, and this is why it's erroring?

I could change it to anyOf but then the discriminator has no use?

Code

Code repo - openapi_discriminator

openapi_discriminator/openapi/v1/api.yaml:

openapi: "3.0.3"
info:
  title: Open API Discriminator Example
  version: "v1"

tags:
  - name: discriminator

paths:
  /discriminatortest:
    get:
      tags:
        - discriminator
      summary: Example using discriminator
      description: "Demonstrate a minimal example"
      responses:
        "200":
          description: Created
          content:
            application/json:
              schema: {$ref: "schemas.yaml#/components/schemas/Animal"}
              example:
                legs: "two"

openapi_discriminator/openapi/v1/schemas.yaml:

openapi: "3.0.3"

components:
  schemas:

    Animal:
      type: object
      discriminator:
        propertyName: legs
        mapping:
          two: Chicken
          four: Dog
      oneOf:
        - $ref: '#/components/schemas/Dog'
        - $ref: '#/components/schemas/Chicken'

    Chicken:
      type: object
      required:
        - legs
      properties:
        legs:
          type: string

    Dog:
      type: object
      required:
        - legs
      properties:
        legs:
          type: string

openapi_discriminator/openapi/.spectral.yml

extends: spectral:oas
rules:
  info-contact: false
  info-description: false
  oas3-api-servers: false
  openapi-tags: true
  operation-tags: true
  operation-operationId: false
  operation-description: true

Run linting command: spectral lint "openapi/v1/api.yaml" --ruleset openapi/.spectral.yml

1

There are 1 answers

0
Kenneth Teh On

Not sure if you're still looking for an answer, considering you asked this so long ago. The problem here is that you haven't explicitly declared the available values for legs. You know and I know that a dog has four legs and a chicken has two legs, but the schema doesn't. Put another way, the discriminator has to discriminate based only on the value of the propertyName, so that is what the example has to match.

Adding in the enum values will fix your problem:

openapi: "3.0.3"

components:
  schemas:

    Animal:
      type: object
      discriminator:
        propertyName: legs
        mapping:
          two: Chicken
          four: Dog
      oneOf:
        - $ref: '#/components/schemas/Dog'
        - $ref: '#/components/schemas/Chicken'

    Chicken:
      type: object
      required:
        - legs
      properties:
        legs:
          type: string
          enum:
            - two

    Dog:
      type: object
      required:
        - legs
      properties:
        legs:
          type: string
          enum:
            - four

Also, the mapping is probably not so useful for you right now:

          two: Chicken
          four: Dog

Depending on your use case, e.g. if you're generating documentation from the schema, this will mean your generated docs show two options ("two" and "four"). So perhaps you might consider making it:

          chicken: Chicken
          dog: Dog