Reputation: 5
I'm using jsonschema to validate a configuration file. Currently I'm running into trouble validating value combinations of nested properties.
I originally implemented if/then/else, but did not see the desired behavior after several passes. The same was done for switch, dependencies, and lastly using implication.
This is my schema:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"name": {
"type": "string"
},
"account_group": {
"type": "string"
},
"region": {
"type": "string",
"pattern": "^(us(-gov)?|ap|ca|cn|eu|sa)-(central|(north|south)?(east|west)?)-\\d$"
},
"appid": {
"type": "string"
},
"services": {
"type": "object",
"minProperties": 1,
"patternProperties": {
"^[A-Za-z_]*$": {
"type": "object",
"properties": {
"source": {
"type": "string"
},
"port": {
"type": "number"
},
"cpu": {
"type": "number",
"enum": [256, 512, 1024, 2048, 4096]
},
"memory": {
"type": "number",
"enum": [0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30]
}
},
"required": [
"source",
"port",
"cpu",
"memory"
],
}
},
"additionalProperties": false
},
"stages": {
"type": "object",
"minProperties": 1
},
"workingDirectory": {
"type": "string"
}
},
"required": [
"name",
"account_group",
"appid",
"services"
]
}
Note: I removed my latest allOf block to avoid presenting broken code I've already tested against
What I'm trying to accomplish is validating the correct combination of cpu/memory values in the configuration file being parsed and compared against the schema.
The combinations are:
256/[0.5, 1, 2]
512/[1-4]
1024/[2-8]
2048/[2-16]
4096/[2-30]
Would someone kindly suggest the appropriate schema design to validate these combinations?
Essentially I need validation to fail if the cpu is 256, and value of memory is anything but 0.5, 1, 2 - to fail if cpu is 512 and value of memory is anything but 1 - 4, etc.
I've gotten the closest using implication, but I've seen many combinations using dependencies which has further muddied the waters for me. Personally I felt if/then/else would be the most logical approach, but it did not produce the expected behavior.
Upvotes: 0
Views: 975
Reputation: 24479
if
/then
is the best choice for this. The implication pattern works too, but if
/then
is nicer to work with. The general strategy is to create a definition for each of your conditions and then use an allOf
to combine them. You could of course put the conditions inline instead of using definitions
, but it reads a lot better this way which makes maintenance easer. I did the first two to illustrate. You can extrapolate from there.
{
"type": "object",
"properties": {
"source": { "type": "string" },
"port": { "type": "number" },
"cpu": { "enum": [256, 512, 1024, 2048, 4096] },
"memory": { "enum": [0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30] }
},
"required": ["source", "port", "cpu", "memory"],
"allOf": [
{ "$ref": "#/definitions/if-cpu-256-then-memory-0.5-1-2" },
{ "$ref": "#/definitions/if-cpu-512-then-memory-1-4" }
],
"definitions": {
"if-cpu-256-then-memory-0.5-1-2": {
"if": {
"properties": {
"cpu": { "const": 256 }
},
"required": ["cpu"]
},
"then": {
"properties": {
"memory": { "enum": [0.5, 1, 2] }
}
}
},
"if-cpu-512-then-memory-1-4": {
"if": {
"properties": {
"cpu": { "const": 512 }
},
"required": ["cpu"]
},
"then": {
"properties": {
"memory": { "minimum": 1, "maximum": 4 }
}
}
}
}
}
Upvotes: 2