I'm trying to validate the following JSON
{
"domain": "example.com",
"docker": {
"services": {
"app": {
"image": "nginxdemos/hello:latest",
"expose_port": 80,
"volumes": [
"./:/test"
]
},
"db": {
"image": "mariadb:10.5"
}
}
}
}
I want to make sure that expose_port
inside the services
children can only be defined once. So adding "expose_port": 1234
to "db" should invalidate the JSON.
That's my schema so far:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://saitho.me/project-configuration.schema.json",
"title": "Project Configuration",
"description": "Project configuration file",
"type": "object",
"definitions": {
"docker-service": {
"properties": {
"image": {
"description": "Name of Docker image",
"type": "string"
},
"volumes": {
"description": "Docker volumes to be mounted",
"type": "array",
"items": {
"type": "string"
},
"minItems": 1
}
},
"required": [ "image" ]
}
},
"properties": {
"domain": {
"description": "The domain from which the app can be reached",
"type": "string"
},
"docker": {
"description": "Configuration for Docker containers that will be deployed",
"type": "object",
"properties": {
"services": {
"description": "List of Docker services to be started",
"type": "object",
"patternProperties": {
".*": {
"$ref": "#/definitions/docker-service",
"oneOf": [
{
"properties": {
"expose_port": {
"description": "Port that receives web traffic (e.g. 80, 3000, 8080 for most applications). Only one in this file!",
"type": "integer"
}
}
}
],
"type": "object"
}
},
"additionalProperties": false
}
},
"required": [ "services" ]
}
},
"required": [ "domain" ]
}
So far I've tried combining of allOf and oneOf but that seems only to work on the current child rather than looking at the siblings as well. Does anyone know a solution to my problem? :)
Thanks!
If you have a specific set of services (e.g. the exposed port will only ever be on either "app" or "db"), you may use "oneOf" to test that exactly one of the two has a property (or neither, as a third test).
If you have an arbitrary set of services, then you're no longer performing "structural" validation, but moved on into the realm of business logic. In this case, each value depends on the value of potentially all other values. Validating this is not possible with JSON Schema validation alone, see the page Scope of JSON Schema Validation for some more information.
However, you can layout the JSON document to match what you're trying to accomplish. If there's a property that may only be defined once, then factor out the property definition into a place where it may only be defined once:
{
"domain": "example.com",
"docker": {
"services": {
"app": {
"image": "nginxdemos/hello:latest",
"volumes": [
"./:/test"
]
},
"db": {
"image": "mariadb:10.5"
}
},
"expose_service": "app",
"expose_port": 80
}
}