bounding (v5 purposal) - sgpinkus/json-schema GitHub Wiki
JSON-SCHEMA-ORG/JSON-SCHEMA-SPEC REPOSITORY.
THIS WIKI IS OBSOLETE. PLEASE SEE THE NEWNOTE: This proposal has been incorporated into https://github.com/json-schema-org/json-schema-spec/issues/64
Proposed keywords
bounding
Problem
When you use OneOf
or AnyOf
grouping you can't easily determine is there error with fields inside one of nested schemas or actually none of the nested schemas is matching object.
You could consider http://json-schema.org/example2.html as the good example illustrating complex multi-schema pattern divided by the type: [enum] properties.
Purpose
The purpose of the bounding
keyword is to limit validation and errors generation to the schema OneOf
or AnyOf
branch when all
key (bounding) properties have been matched inside it.
Values
The bounding
is an option boolean flag with default false value.
Concerns
This keyword introduces a completely new concept in the design principles of JSON-schema. Currently the keywords are either fully independent of each other or only dependent on the keywords on the same level of the schema (minimum/exclusiveMinimum, items/additionalItems, etc.). If bounding
is introduced into the standard the keywords anyOf/oneOf will behave differently depending on the bounding
keyword on any level inside the contained schemas. Not only it is difficult to implement, it introduces potential ambiguity and contradictions: what if this keyword is encountered more than once? what if it binds more than one schema? or if it is in refs inside refs? Does it mean they have to be all resolved?
The suggestion is to consider alternative solutions to this problem. Maybe just to improve error reporting? It seems like this is an issue of a particular validator rather than JSON-schema standard.
For example if you use Ajv, you will get these errors (reduced to messages only): "data.record should have required property 'age', data.record.type should be equal to one of values, data.record should have required property 'pages', data.record should match exactly one schema in oneOf" (which is slightly better than the example below). But if you rewrite the schema using switch
keyword as in the example in tonic the error message is simply: "data.record should have required property 'age'" that is exactly what bounding is trying to achieve.
Validation
For object that have properties with bounding
set as true data record first of all is checking against this properties ignoring all other and if it matches no other objects with the same level is used for validation and validation continues bounded by this object.
- if object in the
OneOf
orAnyOf
scope have any property withbounding: true
then make pre-validation using only fields withbounding:true
of this object.- if any of the fields with
bounding: true
fails continue validation as usual. - if all properties of given object with
bounding: true
defined is matches (respecting required) then continue validate fields and nested objects:- if object validation is successful continue as usual.
- if object validation fails no any other neighbour OneOf is used for the validation and only this object validation errors is raised. No matching schema error is not raised.
- if any of the fields with
Example
{
"id": "http://some.site.somewhere/entry-schema#",
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "schema for an fstab entry",
"type": "object",
"required": [ "record" ],
"properties": {
"record": {
"type": "object",
"oneOf": [
{ "$ref": "#/definitions/student" },
{ "$ref": "#/definitions/book" }
]
}
},
"definitions": {
"student": {
"properties": {
"type": {
"enum": [ "student" ],
"bounding": true
},
"age": {
"type": "integer"
}
},
"required": [ "age" ],
"additionalProperties": false
},
"book": {
"properties": {
"type": {
"enum": [ "book" ],
"bounding": true
},
"pages": {
"type": "integer"
}
},
"required": [ "pages" ],
"additionalProperties": false
}
}
}
The valid data samples is:
{
"record": {
"type": "book",
"pages": 1
}
}
{
"record": {
"type": "student",
"age": 18
}
}
but if you use v4 schema against:
{
"record": {
"type": "student"
}
}
You will get uninformative that provide very little help when you trying to understand why schema has failed.
Message:
JSON is valid against more than one schema from 'oneOf'. No valid schemas.
Schema path:
http://some.site.somewhere/entry-schema#/properties/record/oneOf
Message:
Value "book" is not defined in enum.
Schema path:
http://some.site.somewhere/entry-schema#/definitions/student/properties/type/enum
Message:
Required properties are missing from object: pages.
Schema path:
http://some.site.somewhere/entry-schema#/definitions/book/required
Message:
Required properties are missing from object: age.
Schema path:
http://some.site.somewhere/entry-schema#/definitions/student/required
When bounding
flag is used error output should looks like:
Message:
Required properties are missing from object: age.
Schema path:
http://some.site.somewhere/entry-schema#/definitions/student/required
This is more informative and significally better for further automatic errors output and highlighting.