Reputation: 27
Imagine a JSON document with only two possible properties:
persist
: a boolean flag. defaults to true
dbName
: a string.When persist
is true
, the dbName
property must be present in the document. When persist
is false
, the dbName
property must not be present in the document.
Seems simple enough--here's the schema I've come up with:
{
"description": "Example",
"$id": "https://example.com/example",
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"persist": {
"type": "boolean"
},
"dbName": {
"type": "string"
}
},
"additionalProperties": false,
"oneOf": [
{
"$comment": "persist attr is present and == false, dbName should not be present",
"properties": {
"persist": {
"enum": [
false
]
}
},
"not": {
"required": [
"dbName"
]
}
},
{
"$comment": "persist attr is present and == true, require dbName",
"properties": {
"persist": {
"enum": [
true
]
}
},
"required": [
"dbName"
]
},
{
"$comment": "persist attr is missing, its default value is true, require dbName",
"properties": {
"persist": false
},
"required": [
"dbName"
]
}
]
}
It almost works. Three test documents to exercise the three possible cases:
{ "persist": true, "dbName": "dn" }
--> Valid
{ "persist": false }
--> Valid
{ "dbName": "dn" }
--> Invalid with the errors below:
[{
keyword: 'not',
dataPath: '',
schemaPath: '#/oneOf/0/not',
params: {},
message: 'should NOT be valid'
},
{
keyword: 'oneOf',
dataPath: '',
schemaPath: '#/oneOf',
params: {
passingSchemas: [Array]
},
message: 'should match exactly one schema in oneOf'
}
]
Through trial and error, it's clear that this last document is actually matching two of the conditions in the oneOf
: oneOf/1
and oneOf/2
.
I have no idea why it would match oneOf/1
since the persist
property is absent from the json document. I'm sure I'm missing something obvious, any help is much appreciated.
Upvotes: 0
Views: 887
Reputation: 12335
In your comments for your oneOf
subschemas, you have said you expect the schema to validate that the persist
attribute is present, but it does not.
Let's take a look at why this is the case...
Validation succeeds if, for each name that appears in both the
instance and as a name within this keyword's value, the child
instance for that name successfully validates against the
corresponding schema.
https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.5.4
This means that, the value subschemas are applied to the instance values in the object IF the corrosponding key exists. If it does not, then it's not applied.
As such, if you discount properties
from oneOf/1
and oneOf/2
, they are equivilent subschemas.
What you want for oneOf/2
is...
{
"$comment": "persist attr is present and == true, require dbName",
"properties": {
"persist": {
"const": true
}
},
"required": [
"persist",
"dbName"
]
}
Here's a demo: https://jsonschema.dev/s/cqMDM
You'll want to make the same change to oneOf/0
too.
If you don't specify persist
as required, the subschema will not be checking if the key exists or not.
Upvotes: 1