I am trying to write a JSON Schema to impose additional required properties in a referenced schema. I have looked here and here, but check-jsonschema
tells me that I need the properties in the top level, not in the nested properties
object. How do I add a constraint on a nested object property?
Attempted schema:
{
"$schema": "https://json-schema.org/draft-07/schema#",
"$id": "https://example.com/sample.schema.json",
"type": "object",
"properties": {
"boundaries": {
"description": "Boundaries",
"allOf": [
{ "$ref": "http://geojson.org/schema/Feature.json" },
{
"geometry": {
"oneOf": [
{ "$ref": "http://geojson.org/schema/MultiPolygon.json" },
{ "$ref": "http://geojson.org/schema/Polygon.json" }
],
"additionalProperties": false
}
},
{
"type": "object",
"required" : ["name"]
}
]
}
}
}
I'd like the following to succeed, but the above validator asks me to put name
at the same level as type
, properties
, and geometry
.
JSON instance:
{
"boundaries": {
"type": "Feature",
"properties": {
"name": "Bounded Place",
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[ -100.0, 40.0 ],
[ -100.0, 45.0 ],
[ -110.0, 45.0 ],
[ -110.0, 40.0 ]
]
]
}
}
}
You have a couple of issues with the attempted schema
$schema
declaration for draft-07 must use http
rather than https
. This is not considered to be a network reachable uri, but rather an identifier for the meta-schema. src: draft-07 specallOf
subschema doesn't define the property geometry
correctly. This schema is completed unconstrained and will allow any data to pass. You can only constrain properties with the properties
keyword defined. Did you want to add additional validation on the geometry keyword that the referenced schema doesn't validate?additionalProperties: false
in the second subschema will also make this entire schema fail any instance because ALL subschemas of an allOf
must be valid. There are two reasons why this will fail. Firstly, when additionalProperties:false
is defined with any composition keyword (allOf, oneOf, anyOf), and no properties
keyword is defined, the schema will never pass any data instance because the additional properties are constrained at the root schema and it does not "reach into" the oneOf
array of subschemas, so it's not aware of any defined properties at the root, thus it fails any attempt to validate any schema. Secondly, When you constrain one of the subschemas to no additional properties inside an allOf
, if the properties from the other subschemas are not defined in the schema with additionalProperties: false
, all of the schemas will fail.required: ["name"]
at the wrong nested level because the Feature.json
schema has a property called properties
(which can be confusing) and this is where you have defined name
in your instance.From my understanding, you want to require name
in your data instance. To do this, you need to define the nested structure in an allOf
subschema and then require that property. Because the property properties
is defined in the geoJSON schema and it appears that is where you want this requirement, this is how you would achieve that.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://example.com/sample.schema.json",
"type": "object",
"properties": {
"boundaries": {
"description": "Boundaries",
"allOf": [
{
"type": "object",
"properties": {
"properties": {
"required": [
"name"
]
}
}
},
{
"$ref": "https://geojson.org/schema/Feature.json"
}
]
}
}
}
{
"boundaries": {
"type": "Feature",
"properties": {
"name": "Bounded Place"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[ -100.0, 40.0 ],
[ -100.0, 45.0 ],
[ -110.0, 45.0 ],
[ -110.0, 40.0 ]
]
]
}
}
}