2

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"
        }
    ]
}

2 Answers2

3

anyOf gives you a closer match for the semantics than oneOf;

The problem (or benefit!) of oneOf is that it will fail if you happen to match 2 different cases.

That is unlikely to be what you want, given the source of your conversion which has those looser semantics.

Imagine converting ["integer","number"], for example; if the input was a 1, you'd match both and fail using oneOf.

Matthew Adams
  • 464
  • 3
  • 6
1

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.

Helen
  • 87,344
  • 17
  • 243
  • 314
  • Thanks @Helen for this detailed answer. But as you stated above that enum and const are mutually exclusive to each other, this does not make sense because enum and cost are of different types not the same. In other words if i need to add const (for string type schema) and enums (for integer or number type schema) using multiple types approach how can I do that? – Ali Raza Abbasi Jul 05 '21 at 06:36
  • Having both `const` and `enum` in the same schema does not make sense because `const` is a just syntactic sugar for an enum with only one element. That is, `"const": "sample const entry"` is the same as `"enum": ["sample const entry"]`. – Helen Jul 05 '21 at 09:23
  • In general, `const` and `enum` can be used with [_any_ data types](https://json-schema.org/draft/2020-12/json-schema-validation.html#rfc.section.6.1) - not just primitives (string, number, integer, boolean, null) but also arrays and objects. Note that these JSON Schema keywords are evaluated [in isolation from each other](https://stackoverflow.com/q/27847063/113116) and regardless of the type of the instance/value being validated against the schema. Your example is an impossible schema because nothing can match both `"const": "sample const entry"` and `"enum": [2, 3, 4, 5]` at the same time. – Helen Jul 05 '21 at 09:31