I have this field assignments
:
chapters
is optional inside assignments object.type
is required.- when the type is
multi
:
pointer
value should be present in eachchapters
object if its
not part of the parentassignments
object. - when type is
notes
:
pointer
is required, unless whencompleted
is true.
{
"assignments": [
{
"type": "multi",
"pointer": "1",
"chapters": [
{
"id": "203"
},
{
"id": "204"
}
]
},
{
"type": "multi",
"chapters": [
{
"id": "201",
"pointer": "3"
},
{
"id": "202",
"pointer": "3"
}
]
},
{
"type": "notes",
"pointer": "4"
},
{
"type": "notes",
"completed": true
}
]
}
for validating this schema with json-schema.org/draft-04, I am not sure how to satisfy all the conditions with nested-dependencies. I have tried the following schema but it is not working as expected.
As its expecting completed to be false to validate pointer
, completed
is optional and will only be present when it has to set as true
. And for type multi
its expecting pointer
to be present when pointer
is part of chapters
.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"assignments": {
"type": "array",
"items": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["multi", "notes"]
},
"pointer": {
"type": "string"
},
"completed": {
"type": "boolean"
},
"chapters": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"pointer": {
"type": "string"
}
},
"required": ["id"]
}
}
},
"required": ["type"],
"dependencies": {
"type": {
"oneOf": [
{
"properties": {
"type": { "enum": ["multi"] }
},
"oneOf": [
{
"properties": {
"pointer": { "type": "string" }
}
},
{
"properties": {
"chapters": {
"type": "array",
"items": {
"type": "object",
"properties": {
"pointer": { "type": "string" }
},
"required": ["pointer"]
}
}
}
}
]
},
{
"properties": {
"type": { "enum": ["notes"] },
"completed": { "enum": [true] }
}
},
{
"properties": {
"type": { "enum": ["notes"] }
},
"required": ["pointer"]
}
]
}
}
}
}
},
"required": ["assignments"]
}
Examples:
- Example 1
{
"assignments": [
{
"type": "notes",
"completed": true
}
]
}
- Expected Result: Should pass
- Actual Result: passing
- Example 2
{
"assignments": [
{
"type": "notes",
"pointer": "4"
}
]
}
- Expected Result: Should pass
- Actual Result:
notes is not a valid enum value,#/assignments/0: #: 2 subschemas matched instead of one
- Example 3
{
"assignments": [
{
"type": "notes"
}
]
}
- Expected Result: Fail with required key [pointer] not found
- Actual Result: Passing
- Example 4
{
"assignments": [
{
"type": "multi",
"chapters": [
{
"id": "201",
"pointer": "3"
},
{
"id": "202",
"pointer": "3"
}
]
}
]
}
- Expected Result: Fail with required key [pointer] not found
- Actual Result: passing
- Example 5
{
"assignments": [
{
"type": "multi",
"pointer": "4",
"chapters": [
{
"id": "201"
},
{
"id": "202"
}
]
}
]
}
- Expected Result: should pass
- Actual Result: Failing with
multi is not a valid enum value,#/assignments/0: #: 2 subschemas matched instead of one, multi is not a valid enum value,#/assignments/0: required key [pointer] not found
- Example 6
{
"assignments": [
{
"type": "multi",
"chapters": [
{
"id": "201",
"pointer": "4"
},
{
"id": "202",
"pointer": "4"
}
]
}
]
}
- Expected Result: should pass
- Actual Result: passing
- Example 7
{
"assignments": [
{
"type": "multi",
"chapters": [
{
"id": "201",
"pointer": "4"
},
{
"id": "202"
}
]
}
]
}
- Expected Result: Fail with required key [pointer] not found (either
pointer
should be present outside ‘chapters’ array or should be part of every ‘chapter’ object ) - Actual Result: passing
3
Unfortunately, draft-04 requires a big, verbose schema to achieve conditional behaviors.
this is much cleaner in draft-07 or newer.
I’ve modularized each condition in a definitions
entry and then used oneOf
to reference each one. The error output is extremely verbose because it needs to report on each oneOf failure during evaluation.
Couple things to consider here are the following use cases:
- Example 3:
type: notes
andcompleted
missing from the schema is not covered. It’s not possible to evaluate a keyword that is missing. - Example 4: your expected result doesn’t seem correct. You said
pointer
is valid at the parent OR the child, not both. So this one is passing as I think it should.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"required": [
"assignments"
],
"properties": {
"assignments": {
"type": "array",
"items": {
"type": "object",
"properties": {
"type": {},
"pointer": {
"type": "string"
},
"completed": {
"type": "boolean"
},
"chapters": {
"type": "array",
"items": {
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "string"
},
"pointer": {
"type": "string"
}
}
}
}
},
"oneOf": [
{
"$ref": "#/definitions/multi-pointer-in-child"
},
{
"$ref": "#/definitions/multi-pointer-at-root"
},
{
"$ref": "#/definitions/notes-completed:false"
},
{
"$ref": "#/definitions/notes-completed:true"
}
]
}
}
},
"definitions": {
"multi-pointer-in-child": {
"properties": {
"type": {
"enum": [
"multi"
]
},
"chapters": {
"minItems": 1,
"items": {
"required": [
"pointer"
]
}
},
"completed": {}
},
"required": [
"type"
],
"not": {
"required": [
"pointer"
]
},
"additionalProperties": false
},
"multi-pointer-at-root": {
"properties": {
"type": {
"enum": [
"multi"
]
},
"pointer": {},
"chapters": {
"items": {
"not": {
"required": [
"pointer"
]
}
}
},
"completed": {}
},
"required": [
"type"
],
"additionalProperties": false
},
"notes-completed:false": {
"additionalProperties": false,
"properties": {
"type": {
"enum": [
"notes"
]
},
"chapters": {},
"completed": {
"enum": [
false
]
},
"pointer": {}
},
"required": [
"type",
"pointer"
]
},
"notes-completed:true": {
"additionalProperties": false,
"properties": {
"type": {
"enum": [
"notes"
]
},
"chapters": {},
"completed": {
"enum": [
true
]
}
},
"required": [
"type"
],
"not": {
"required": [
"pointer"
]
}
}
}
}