Reputation: 4596
I'm trying to validate a simple json schema and I simply can't seem to get this right. I'm trying to implement this piece of code into JsonSchema, but it doesn't validate correctly.
Code:
if (field1 is "REAL") {
then both attributes.A and attributes.B are present
if (attributes.field2 is "true") {
then attributes.C is also present
}
}
I've converted this to a JsonSchema as follows:
{
"$schema": "https://json-schema.org/draft/2019-09/schema#",
"properties": {
"field1": {},
"attributes": {
"type": "object",
"properties": {
"field2": {
"type": "string",
"default": "false"
}
}
}
},
"allOf": [
{
"if": {
"properties": {
"field1": {
"enum": [
"REAL"
]
}
}
},
"then": {
"properties": {
"attributes": {
"$id": "#/properties/realAttributes",
"type": "object",
"title": "The Attributes Schema",
"required": [
"A",
"B"
],
"properties": {
"A": {},
"B": {},
"C": {},
"D": {},
"field2": {}
}
}
}
}
},
{
"if": {
"properties": {
"field1": {
"enum": ["REAL"]
},
"attributes": {
"properties": {
"field2": {
"enum": ["true"]
}
}
}
}
},
"then": {
"properties": {
"attributes": {
"required": [
"C"
]
}
}
}
}
]
}
The second if
validation in allOf
is not working correctly and I can't figure out why. It's failing when I pass field1
, but not field2
. Play with the failing implementation here.
I would expect this to pass, but it reports an error saying that C
is missing. The failing case:
{
"field1": "REAL",
"attributes": {
"A": 4,
"B": 5
}
}
Upvotes: 0
Views: 3309
Reputation: 12295
JSON Schema works by applying the schema (and subschemas) to instance locations.
The conditional keywords if/then/else
work by applying the schema value of if
to the instance location, and depending on the result, applying then
or else
if provided.
The key here is JSON Schema is a constraints based language, and anything you don't specify / constrain is allowable.
Let's take your if
subschema which isn't working as you expect...
{
"properties": {
"field1": {
"enum": ["REAL"]
},
"attributes": {
"properties": {
"field2": {
"enum": ["true"]
}
}
}
}
}
Let's take a look at what you've specified here.
But first, let's check what properties
does...
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-02#section-9.3.2.1
In your if
subschema, you've said, "if field1
exists, it should be "REAL" " AND "if the object has a property attributes
, and if that object value has a property field2
, then it should be "true"
".
The problem is, if field1
doesn't exist, and if attributes
doesn't exist, then the subschema will still pass validation.
If you require the property to be present, you must require
it.
Let's take a look at your schema having added the required
keyword...
{
"$schema": "https://json-schema.org/draft/2019-09/schema#",
"properties": {
"field1": {},
"attributes": {
"type": "object",
"properties": {
"field2": {
"type": "string",
"default": "false"
}
}
}
},
"allOf": [
{
"if": {
"required": [
"field1"
],
"properties": {
"field1": {
"enum": [
"REAL"
]
}
}
},
"then": {
"properties": {
"attributes": {
"$id": "#/properties/realAttributes",
"type": "object",
"title": "The Attributes Schema",
"required": [
"A",
"B"
],
"properties": {
"A": {},
"B": {},
"C": {},
"D": {},
"field2": {}
}
}
}
}
},
{
"if": {
"required": [
"field1"
],
"properties": {
"field1": {
"enum": [
"REAL"
]
},
"attributes": {
"required": [
"field2"
],
"properties": {
"field2": {
"enum": [
"true"
]
}
}
}
}
},
"then": {
"properties": {
"attributes": {
"required": [
"C"
]
}
}
}
}
]
}
Playground: https://www.jsonschemavalidator.net/s/mAPFXugk
Now the subschemas have required the keywords too, the validation works as you expect.
If you run into problems using conditionals in JSON Schema, you can test your assumptions by changing a subschema to false
, such as the value of then
. You can use this technique to check which conditions are met or not.
Upvotes: 1