openapijsonschemafastify

Using oneOf in OpenAPI response schema


Stack

Data

server.addSchema({
    $id: 'event',
    type: 'object',
    properties: {
        event_id: {
            $ref: 'id'
        },
        address: {
            $ref: 'address'
        },
        starttime: {
            $ref: 'time'
        },
        name: {
            type: 'string'
        }
    },
    required: ['event_id', 'address', 'starttime']    
})

server.addSchema({
    $id: 'callEvent',

    type: 'object',
    allOf: [{ $ref: 'event' }],

    properties: {
        type: {
            type: 'string',
            const: 'call'
        },
        num: {
            type: 'integer'
        },
        result: {
            type: 'integer',
            minimum: 0,
            maximum: 3
        }
    },
    required: ['type', 'num', 'result'],
    unevaluatedProperties: false
})

server.addSchema({
     $id: 'appEvent',

    type: 'object',
    allOf: [{ $ref: 'event' }],

    properties: {
        type: {
            type: 'string',
            const: 'app'
        }
    },
    required: ['type'],
    unevaluatedProperties: false    
})
{
    "response": {
        "200": {
            "type": "object",
            "additionalProperties": {
                "type": "array",
                "items": {
                    "type": "object",
                    "oneOf": [
                        { "$ref": "appEvent" },
                        { "$ref": "callEvent" }
                    ]
                }
            }
        }
    }
}

My goal: I need to specify that the response returns an object where the key can be any value, and the property is an array where the elements can match any of the specified schemas.

Expected valid result:

{
    "otherkey": [
        {
            "event_id": 1,
            "address": "string",
            "starttime": " 00:00",
            "name": "string",
            "type": "app"  //  this scheme appEvent
        },
        {
            "event_id": 2,
            "address": "string",
            "starttime": " 06:08",
            "name": "string",
            "type": "call",
            "num": 0,
            "result": 3  // this scheme callEvent
        }
    ],
    "otherkey2": [
        {
            "event_id": 1,
            "address": "string",
            "starttime": " 00:00",
            "name": "string",
            "type": "app"  // this scheme appEvent
        }
    ],
    "otherkey3": [
        {
            "event_id": 2,
            "address": "string",
            "starttime": " 06:08",
            "name": "string",
            "type": "call",
            "num": 0,
            "result": 3  // this scheme callEvent
        }
    ]
}

Actual result:

{
    "statusCode": 500,
    "error": "Internal Server Error",
    "message": "The value of '#/additionalProperties/items' does not match schema definition."
}

If I am doing something wrong, please correct me. But according to the schema https://json-schema.org/draft-07/schema, this should work correctly.

Note: I am also using @fastify/swagger and @fastify/swagger-ui in my stack. In the generated Swagger documentation, the example for this endpoint is displayed as I expect

Here is what the example looks like in Swagger:

{
  "additionalProp1": [
    {
      "event_id": 1,
      "address": "string",
      "starttime": "23:07",
      "name": "string",
      "type": "string"
    },
    {
      "event_id": 1,
      "address": "string",
      "starttime": "22:40",
      "name": "string",
      "type": "string",
      "num": 0,
      "result": 3
    }
  ],
  "additionalProp2": [
    {
      "event_id": 1,
      "address": "string",
      "starttime": "23:07",
      "name": "string",
      "type": "string"
    },
    {
      "event_id": 1,
      "address": "string",
      "starttime": "22:40",
      "name": "string",
      "type": "string",
      "num": 0,
      "result": 3
    }
  ],
  "additionalProp3": [
    {
      "event_id": 1,
      "address": "string",
      "starttime": "23:07",
      "name": "string",
      "type": "string"
    },
    {
      "event_id": 1,
      "address": "string",
      "starttime": "22:40",
      "name": "string",
      "type": "string",
      "num": 0,
      "result": 3
    }
  ]
}

I have tried searching for different information on this topic, but all the examples show the use of oneOf and anyOf in the same way I am using them.

Usually, if there are invalid keys in the schema or the schema is incorrect, Fastify throws an error during the build and startup phase of the server, but it is not doing so in this case.


Solution

  • to have a dynamic property you can use additionalProperties just like your example but you're missing the content and media-type key entries.

    My goal: I need to specify that the response returns an object where the key can be any value, and the property is an array where the elements can match any of the specified schemas.

    {
      "response": {
        "200": {
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": {
                  "type": "array",
                  "items": { 
                    "oneOf": [
                      { "$ref": "appEvent"},
                      { "$ref": "callEvent"}
                    ]
                  }
                }
              }
            }
          }
        }
      }
    }