Reputation: 1293
I'm trying to create a schema for a JSON object that varies its schema depending on the value of one of its properties: type
.
Like this:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["INT", "PERCENT"]
}
},
"required": ["type"],
"allOf": [
{
"if": {
"properties": {"type": {"const": "INT"}}
},
"then": {
"properties": {
"value": {"type": "number", "multipleOf": 1}
},
"required": ["value"],
"additionalProperties": false
}
},
{
"if": {
"properties": {"type": {"const": "PERCENT"}}
},
"then": {
"properties": {
"value": {"type": "number"},
"min": {"type": "number"},
"max": {"type": "number"}
},
"required": ["value", "min", "max"],
"additionalProperties": false
}
}
]
}
But I'm getting all sorts of misbehaviour from the various validators I'm trying.
Some examples with problems noted after the //
:
{
"type": "PERCENT", // property type has not been defined(?!)
"value": 0.0,
"min": 10,
"max": 25
}
{
"type": "INT", // no errors allowed, and value
"value": 0.1, // should've been flagged as not multiple of 1
"min": 10, // should've been flagged as disallowed additional property
"max": 25 // same as above
}
Here's the validator I'm trying
Thanks in advance for your help!
Upvotes: 1
Views: 1460
Reputation: 24439
It seems that you've figured out that the problem is that addtionalProperties
only considers the properties defined in the sub-schema it's defined in. That's why you have to include the "type" property in your then
. You have a few options that are an improvement over the solution you posted that you weren't happy with.
unevaluatedProperties
Draft 2019-09 introduced the unevaluatedProperties
keyword. If you use this at the top level of your schema and don't use addtionalProperties
anywhere, you will get the behavior you expected from additionalProperties
. I see you are using draft-07, so you have to upgrade in order to use this solution.
The solution you came up with is to re-define the "type" property in the then
schemas. additionalProperties
just needs "type" to be declared, you don't need to include the schema for it again. You can use true
or the empty schema {}
instead.
propertyNames
Instead of additionalProperties
you can use propertyNames
. This allows you to declare a list of which property names are allowed in the object rather than hacking additionalProperties
with true
or {}
to figure out the allowed property names the way you want it to.
Upvotes: 1
Reputation: 1293
well I found a way to get what I wanted, but it doesn't mean I like it. Having to redefine "type" doesn't seem right to me.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["INT", "PERCENT"]
}
},
"required": ["type"],
"allOf": [
{
"if": {
"properties": {"type": {"const": "INT"}}
},
"then": {
"properties": {
"value": {"type": "number", "multipleOf": 1},
"type": {"type": "string"}
},
"required": ["value", "type"],
"additionalProperties": false
}
},
{
"if": {
"properties": {"type": {"const": "PERCENT"}}
},
"then": {
"properties": {
"value": {"type": "number"},
"min": {"type": "number"},
"max": {"type": "number"},
"type": {"type": "string"}
},
"required": ["value", "min", "max", "type"],
"additionalProperties": false
}
}
]
}
tests...
This validates:
{
"type": "PERCENT",
"value": 0,
"min": 10,
"max": 20
}
so does this:
{
"type": "INT",
"value": 0
}
this errors in the way I want:
{
"type": "INT",
"value": 0.1, // not a multiple of 1
"min": 4, // not expected
"max": 5 // not expected
}
and so does this:
{
"type": "PERCENT",
"value": 0.1,
"max": 5 // min is a required property
}
Upvotes: 0