In my schema I declared these properties:
"index_name": {
"type": "string",
"examples": ["foo-wwen-live", "foo"]
},
"locale": {
"type": "string",
"examples": ["wwen", "usen", "frfr"]
},
"environment": {
"type": "string",
"default": "live",
"examples": [
"staging",
"edgengram",
"test"
]
}
I want a JSON body validated against my schema to be valid only if:
index_name
is present, and both locale
and environment
are not present;locale
and/or enviroment
are present, and index_name
is not presentIn short, locale
and environment
should never be mixed with index_name
.
These should pass:
Case #1
{
"locale": "usen"
}
Case #2
{
"environment": "foo"
}
Case #3
{
"environment": "foo",
"locale": "usen"
}
Case #4
{
"index_name": "foo-usen"
}
These should NOT pass:
Case #5
{
"index_name": "foo-usen",
"locale": "usen"
}
Case #6
{
"index_name": "foo-usen",
"environment": "foo"
}
Case #7
{
"index_name": "foo-usen",
"locale": "usen",
"environment": "foo"
}
I created the following rule for my schema, however it does not cover all the cases. For example, if both locale
and environment
are present, validation returns failure if index_name
is also present, which is correct behavior according to case #7. But if only one of locale
and environment
is present, it allows index_name
to also be present (fails at cases #5 and #6).
"oneOf": [
{
"required": ["index_name"],
"not": {"required": ["locale", "environment"]}
},
{
"anyOf": [
{
"required": ["locale"],
"not": {"required": ["index_name"]}
},
{
"required": ["environment"],
"not": {"required": ["index_name"]}
}
]
}
]
I'm getting mixed information on how "not": {"required": []}
declaration works. Some people claim this means that it forbids anything declared in the array to be present, in contrary to what idea does the syntax give. Other claim that this should be taken exactly as it sounds: properties listed in the array are not required - they can be present, but it doesn't matter if they aren't.
Apart from this rule, I also require one non-related property to be present in all cases and I set "additionalProperties": false
.
What is the rule that would satisfy all my test cases?
In a JSON schema, a $ref keyword is a JSON Pointer to a schema, or a type or property in a schema. A JSON pointer takes the form of A # B in which: A is the relative path from the current schema to a target schema. If A is empty, the reference is to a type or property in the same schema, an in-schema reference.
Gets or sets a flag indicating whether the value can not equal the number defined by the minimum attribute (Minimum).
Here oneOf is a keyword construct in the JSON Schema, which is used to provide an array of criteria where, if exactly one of them is valid, the whole block is valid. As per the exampe above, objects having ( "email" AND "password" ) OR ( "username" AND "password" ) attributes are considered valid.
allOf: (AND) Must be valid against all of the subschemas. anyOf: (OR) Must be valid against any of the subschemas. oneOf: (XOR) Must be valid against exactly one of the subschemas.
This is a job for the dependencies
keyword. The following says
|
"dependencies": {
"locale": { "not": { "required": ["index_name"] } },
"environment": { "not": { "required": ["index_name"] } }
}
not
-required
?There's a sub question about how not
-required
works. It's confusing because it doesn't mean how it reads in English, but it's similar enough to make us think it does sometimes.
In the above example, if we read it as "not required", it sounds like it means "optional". A more accurate description would be "forbidden".
That's awkward, but not too bad. Where it gets confusing is when you want to "forbid" more than one property. Let's assume we want to say, if "foo" is present, then "bar" and "baz" are forbidden. The first thing you might try is this.
"dependencies": {
"foo": { "not": { "required": ["bar", "baz"] } }
}
However, what this says is that if "foo" is present, then the instance is invalid if both "bar" AND "baz" are present. They both have to be there to trigger failure. What we really wanted is for it to be invalid if "bar" OR "baz" are present.
"dependencies": {
"foo": {
"not": {
"anyOf": [
{ "required": ["bar"] },
{ "required": ["baz"] }
]
}
}
}
JSON Schema is optimized for schemas that are tolerant to changes. The schema should enforce that the instance has a the necessary data to accomplish a certain task. If it has more than it needs, the application ignores the rest. That way, if something is add to the instance, everything still works. It shouldn't fail validation if the instance has a few extra fields that the application doesn't use.
So, when you try to do something like forbidding things that you could otherwise ignore, you're going a bit against the grain of JSON Schema and things can get a little ugly. However, sometimes it's necessary. I don't know enough about your situation to make that call, but I'd guess that dependencies
is probably necessary in this case, but additionalProperties
is not.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With