I'm trying to validate a json
payload in Python, using jsonschema 3.0.1
, that roughly looks like that (simplified to the troublesome part):
{
"request": {
"topic": {
"param1": "bleep beep topic",
"param2": "bloop boop topic"
},
"message": {
"param1": "bleep beep message",
"param2": "bloop boop message"
}
}
}
A valid request is expected to have two fields: a topic
and matching message
.
Each of them can consist of either param1
only or both param1
and param2
.
- valid:
topic { param1, param2 }, body { param1, param2 }
- valid:
topic { param1 }, body { param1 }
But it can't have neither topic
with only param1
and body with both, nor a topic
with both and body with only param2
:
- invalid:
topic { param1, param2 }, body { param1 }
- invalid:
topic { param1}, body { param1, param2 }
Because the content of one node depends on the content of another node, I wasn't able to use the dependencies
keyword or the if-then-else
construction, so I've tried to use the oneOf
, and provide a list of valid subschemas with references to the one_param
and both_params
versions of the field, like so:
from jsonschema import validate
one_param = {
"type": "object",
"properties": {
"param1": {
"type": "string",
}
},
"required": ["param1"]
}
both_params = {
"type": "object",
"properties": {
"param1": {
"type": "string",
},
"param2": {
"type": "string",
}
},
"required": ["param1", "param2"]
}
test_schema = {
"type": "object",
"properties": {
"request": {
"oneOf": [
{
"type": "object",
"properties": {
"topic": one_param,
"message": one_param
},
"required": ["topic", "message"]
},
{
"type": "object",
"properties": {
"topic": both_params,
"message": both_params
},
"required": ["topic", "message"]
}
],
}
}
}
The behavior of the validator is not what I expected: it fails on the case with both params, and successfully validates the case with one param or mismatched params.
Why does my validation schema not work as I've explained?
Here's entire test that I wrote for that purpose:
good_1
case fails validationgood_2
,bad_1
andbad_2
cases are successfully validated
from jsonschema import validate
one_param = {
"type": "object",
"properties": {
"param1": {
"type": "string",
}
},
"required": ["param1"]
}
both_params = {
"type": "object",
"properties": {
"param1": {
"type": "string",
},
"param2": {
"type": "string",
}
},
"required": ["param1", "param2"]
}
test_schema = {
"type": "object",
"properties": {
"request": {
"oneOf": [
{
"type": "object",
"properties": {
"topic": one_param,
"message": one_param
},
"required": ["topic", "message"]
},
{
"type": "object",
"properties": {
"topic": both_params,
"message": both_params
},
"required": ["topic", "message"]
}
],
}
}
}
good_1 = {
"request": {
"topic": {
"param1": "bleep beep",
"param2": "bloop boop"
},
"message": {
"param1": "bleep beep message",
"param2": "bloop boop message"
}
}
}
good_2 = {
"request": {
"topic": {
"param1": "bleep beep"
},
"message": {
"param1": "bleep beep message"
}
}
}
bad_1 = {
"request": {
"topic": {
"param1": "bleep beep",
},
"message": {
"param1": "bleep beep message",
"param2": "bloop boop message with no matching topic"
}
}
}
bad_2 = {
"request": {
"topic": {
"param1": "bleep beep",
"param2": "bloop boop topic with no matching message"
},
"message": {
"param1": "bleep beep message"
}
}
}
validate(good_1, test_schema) # should validate
validate(good_2, test_schema) # should validate
validate(bad_1, test_schema) # should fail
validate(bad_2, test_schema) # should fail