Search code examples
jsonschemaopenapiopenapi-generatorjson-schema-validator

What is equivalent to multiple types in OpenAPI 3.1? anyOf or oneOf?


I want to change multiple types (supported in the latest drafts of JSON Schema so does OpenAPI v3.1) to anyOf, oneOf but I am a bit confused to which the types would be mapped to. Or can I map to any of the two.

PS. I do have knowledge about anyOf, oneOf, etc. but multiple types behavior is a little ambiguous. (I know the schema is invalid but it is just an example that is more focused towards type conversion)

{
    "type": ["null", "object", "integer", "string"],
    "properties": {
        "prop1": {
            "type": "string"
        },
        "prop2": {
            "type": "string"
        }
    },
    "enum": [2, 3, 4, 5],
    "const": "sample const entry",
    "exclusiveMinimum": 1.22,
    "exclusiveMaximum": 50,
    "maxLength": 10,
    "minLength": 2,
    "format": "int32"
}

I am converting it this way.

{
    "anyOf": [{
            "type": "null"
        },
        {
            "type": "object",
            "properties": {
                "prop1": {
                    "type": "string"
                },
                "prop2": {
                    "type": "string"
                }
            }
        },
        {
            "type": "integer",
            "enum": [2, 3, 4, 5],
            "exclusiveMinimum": 1.22,
            "exclusiveMaximum": 50,
            "format": "int32"
        },
        {
            "type": "string",
            "maxLength": 10,
            "minLength": 2,
            "const": "sample const entry"
        }
    ]
}

Solution

  • First of all, your example is not valid:

    1. The initial schema doesn't match anything, it's an "impossible" schema. The "enum": [2, 3, 4, 5] and "const": "sample const entry" constraints are mutually exclusive, and so are "const": "sample const entry" and "maxLength": 10.

    2. The rewritten schema is not equivalent to the original schema because the enum and const were moved from the root level into subschemas. Yes, this way the schema makes more sense and will sort of work (e.g. it will match the specified numbers - but not strings! because of const vs maxLength contradiction), but it's not the same the original schema.


    With regard to oneOf/anyOf:

    It depends.

    The choice between anyOf and oneOf depends on the context, i.e. whether an instance is can match more than one subschema or exactly one subschema. In other words, whether multiple subschema match is considered OK or an error. Nullable references typically need anyOf rather than oneOf, but other cases vary from schema to schema.

    For example,

    "type": ["number", "integer"]
    

    corresponds to anyOf because there's an overlap - integer values are also valid "number" values in JSON Schema.

    Whereas

    "type": ["string", "integer"]
    

    can be represented using either oneOf or anyOf. oneOf is semantically closer since strings and integers are totally different data types with no overlap. But technically anyOf also works, it's just there won't be more than one subschema match in this particular case.


    In your example, all base type values are distinct with no overlap, so I would use oneOf, but technically anyOf will also work.