Pragmatism in the real world

Using OneOf for a property in an OpenAPI spec

When writing an OpenAPI specification, I came across the need for a particular property in an error response to be either a string or an object.

This situation came about when validating a POST request that takes an items property that is a list of objects

As a contrived example of a pet with accessories, consider this example request in curl:

curl -X "POST" "http://api.example.com/pets" \
     -H 'Content-Type: application/json' \
     -d $'{
  "name": "Rover",
  "items": [
    {
      "name": "collar"
      "count": 1
    },
    {
      "name": "bowl"
      "count": 2
    }
  ],
}'

For the items property, there are two error responses if validation fails:

  1. Property missing or wrong type.
    For example:
    {
      "items": "Items property is required"
    }
    
  2. Missing or invalid sub property
    For example on the count property of the second item:
    {
      "items": [
        {
        },
        {
            "count": "Item count must be a positive integer"
        }
      ]
    }
    

To document this in OpenAPI, I wrote the following for my '400' response (simplified):

'400':
  description: Validation failed
  content:
      application/json:
        schema:
          type: object
          properties:
            errors:
              type: object
              properties:
                name:
                  type: string
                  example: "Pet name must not be empty"
                items:
                  oneOf:
                    - $ref: '#/components/schemas/ValidationErrorPetItemsObject'
                    - $ref: '#/components/schemas/ValidationErrorPetItemsString'

Within the components -> schemas section, we define both schemas:

ValidationErrorPetItemsString:
  type: string
  example: "Items property is required"


ValidationErrorPetItemsPropertyObject:
  type: array
  items:
    type: object
    properties:
      id:
        type: string
        example: "Item name is required"
      count:
        type: string
        example: "Item count must be a positive integer"

I don’t know how to specify that an empty array will be included so that the client can work out which item object has the problem, so for now it is documented in the description.

There’s probably other ways to solve this, but this is the one I came up with. If there’s a better way, let me know.

Thoughts? Leave a reply

Your email address will not be published. Required fields are marked *