You can do this with a boolean logic concept called implication (!A or B). It can be used like an "if-then" statement. For example, either "color" is not "red" or "redQuote" is required. Any time I need to use this, I break it down with definitions so it reads as nice as possible.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"colour": { "enum": ["red", "black", "blue"] },
"blackQuote": { "type": "string", "maxLength": 11 },
"redQuote": { "type": "string", "maxLength": 11 }
},
"allOf": [
{ "$ref": "#/definitions/red-requires-redQuote" },
{ "$ref": "#/definitions/black-requires-blackQuote" }
],
"required": ["colour"],
"definitions": {
"red-requires-redQuote": {
"anyOf": [
{ "not": { "$ref": "#/definitions/is-red" } },
{ "required": ["redQuote"] }
]
},
"black-requires-blackQuote": {
"anyOf": [
{ "not": { "$ref": "#/definitions/is-black" } },
{ "required": ["blackQuote"] }
]
},
"is-red": {
"properties": {
"colour": { "enum": ["red"] }
},
"required": ["colour"]
},
"is-black": {
"properties": {
"colour": { "enum": ["black"] }
},
"required": ["colour"]
}
}
}
Answer from Jason Desrosiers on Stack OverflowYou can do this with a boolean logic concept called implication (!A or B). It can be used like an "if-then" statement. For example, either "color" is not "red" or "redQuote" is required. Any time I need to use this, I break it down with definitions so it reads as nice as possible.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"colour": { "enum": ["red", "black", "blue"] },
"blackQuote": { "type": "string", "maxLength": 11 },
"redQuote": { "type": "string", "maxLength": 11 }
},
"allOf": [
{ "$ref": "#/definitions/red-requires-redQuote" },
{ "$ref": "#/definitions/black-requires-blackQuote" }
],
"required": ["colour"],
"definitions": {
"red-requires-redQuote": {
"anyOf": [
{ "not": { "$ref": "#/definitions/is-red" } },
{ "required": ["redQuote"] }
]
},
"black-requires-blackQuote": {
"anyOf": [
{ "not": { "$ref": "#/definitions/is-black" } },
{ "required": ["blackQuote"] }
]
},
"is-red": {
"properties": {
"colour": { "enum": ["red"] }
},
"required": ["colour"]
},
"is-black": {
"properties": {
"colour": { "enum": ["black"] }
},
"required": ["colour"]
}
}
}
Simplest answer in draft-04 (as noted by Ganesh in a comment):
{
"definitions": {},
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"colour": {
"type": "string",
"enum": ["red", "black", "blue"]
},
"blackQuote": {
"type": "string",
"maxLength": 11
},
"redQuote": {
"type": "string",
"maxLength": 11
}
},
"oneOf": [
{
"properties": {
"colour": {"enum": ["red"]}
},
"required": ["redQuote"]
},
{
"properties": {
"colour": {"enum": ["black"]}
},
"required": ["blackQuote"]
},
{
"properties": {
"colour": {"enum": ["blue"]}
}
}
],
"required": [
"colour"
]
}
jsonschema - Json Schema Validation: Dependencies on subschema - Stack Overflow
Proposal: Add propertyDependencies keyword (aka discriminator)
dependencies - JSON Schema - specify field is required based on value of another field - Stack Overflow
Is it possible to have "dependencies" based on values instead of presence?
This is definitely possible with version 3 of the draft. Since you have a complete list of allowed countries, then you could do something like this:
{
"type": [
{
"title": "New Zealand (no postcode)",
"type": "object",
"properties": {
"country": {"enum": ["NZ", "NZL", "NEW ZEALAND"]}
}
},
{
"title": "Other countries (require postcode)",
"type": "object",
"properties": {
"country": {"enum": [<all the other countries>]},
"postcode": {"required": true}
}
}
],
"properties": {
"country": {
"type" : "string",
"default" : "AUS"
},
"postcode": {
"type" : "string"
}
}
}
So you actually define two sub-types for your schema, one for countries that require a postcode, and one for countries that do not.
EDIT - the v4 equivalent is extremely similar. Simply rename the top-level "type" array to "oneOf".
If anybody is looking for a solution for draft 4 you can use dependencies keyword together with a enum keyword:
{
"type": "object",
"properties": {
"play": {
"type": "boolean"
},
"play-options": {
"type": "string"
}
},
"dependencies": {
"play-options": {
"properties": {
"play": {
"enum": [true]
}
}
}
}
}
In this wayplay-options will always require play value to be true.