On the face of it, this seems like a duplicate of this other Q&A, but in practical terms it is not.
I have a schema where I have an object that contains approximately a dozen different properties, but any given use of that object is only permitted to have exactly one of the properties. I have tried using a "oneOf" sequence of "required" definitions like:
...
"myObject": {
"type": "object",
"oneOf": [
{
"required": [
"a"
]
},
{
"required": [
"b"
]
},
{
"required": [
"c"
]
},
...
],
"properties": {
"a": {...},
"b": {...},
"c": {...},
...
}
}
...
However, when this schema is applied, using either IntelliJ IDEA and VSCode, I can still define a "myObject" that contains multiple properties, such as:
"myObject": {
"a": ...,
"b": ...
}
How can I define the schema to allow just one of these properties?
In addition, I have an extended version of this structure like:
...
"myExtendedObject": {
"type": "object",
"required": [
"op",
"val"
],
"allOf": [
{
"$ref": "#/definitions/myObject"
},
{
"properties": {
"op": {...},
"val": {...}
}
}
]
}
...
In this scenario I want the schema to require exactly one of the first dozen properties "a", "b", "c", or ..., plus "op" and "val". Again, how to achieve this?
In general terms to solve this "one and only one of these properties" validation rule, do I need to do something as verbose and horrid as:
"myObject": {
"type": "object",
"oneOf": [
{
"required": [
"a"
],
"not": {
"required": [
"b",
"c",
...
]
}
},
{
"required": [
"b"
],
"not": {
"required": [
"a",
"c",
...
]
}
},
{
"required": [
"c"
],
"not": {
"required": [
"a",
"b",
...
]
}
},
...
I would very much like to avoid this latter since it is a huge amount of additional repetition with subtle variation.
PS: Yes, I am aware there are many newer schema versions but I'm stuck on draft 7 since that's what the schema aware editors I have available can understand.
UPDATE:
I am already using
"additionalProperties": false
in my schema and note that this includes lots of hoop jumping in order to support the extension scenarios that use anallOf[{"$ref": "#/definitions/myObject"},{...}]
approach. I omitted this to reduce the size of the examples I provided.I have already tried
maxProperties
(which has to be done in a way that is compatible with the need to support extension), and while this helps flag error cases the actual error doesn't actually tell you what you shouldn't have put in the JSON, just that there are too many properties.
UPDATE 2:
After a nudge by @JasonDesrosiers, where he indirectly pointed out that De Morgan's law applies here (i.e. not(A AND B AND ...)
== not(A) OR not(B) OR ...
) I tried a slightly different, even more verbose, approach of:
"myObject": {
"type": "object",
"oneOf": [
{
"required": [
"a"
],
"not": {
"anyOf": [
{"required": ["b"]},
{"required": ["c"]},
...
]
}
},
...
While this resolved the validation, the feedback to the user isn't great (and actually can be a bit confusing) this didn't impact the editor auto-completion behaviour in the way I hoped (or, indeed, at all).