Reputation: 1130
I have an array of options. Each item in the array will have text and a boolean value isAnswer
I am trying to validate in a way that only one of the items can be and must be marked true. Anything else should be invalid. Via two items are true or 0 are true should fail. I have been playing around with oneOf
as that seems to make the most sense however it always validates successful.
First off, is this possible to validate? Secondly am I on the right track?
Thanks for any help you can offer
"question": {
"title": "Question",
"type": "object",
"properties": {
"options": {
"title": "Options",
"type": "array",
"minItems": 2,
"maxItems": 10,
"items": {
"title": "Option",
"type": "object",
"properties": {
"isAnswer": {
"title": "Answer",
"type": "boolean",
"format": "checkbox",
"default": false
},
"text": {
"title": "Choice Text",
"type": "string"
},
},
"oneOf": [
{
"properties": {
"isAnswer": true
}
}
]
}
}
}
}
Upvotes: 0
Views: 1414
Reputation: 645
This kind of test is called "business logic" or "data consistency validation" which falls outside the scope of JSON Schema (and most validation tools, such as XML Schema, RELAX NG, and the like). See Scope of JSON Schema Validation for more information on this.
It may be technically possible to write a schema that produces the results you're looking for, by crafting different schemas, one for each possible correct answer. Similar solutions are used to validate different classes of objects, where a "category" or "type" field determines how to validate all the other properties.
However, JSON Schema does not support comparing one value with another in the general.
As far as the schema layout goes, your schema is acceptable; but I would consider specifying the answer separately from the questions:
{
"options": [
{ "text": "Butaful" },
{ "text": "Bueatful" },
{ "text": "Beautiful" },
{ "text": "Beeyoutiful" }
],
"answer": "Beautiful"
}
This adds some redundancy, and supports freeform answers.
Upvotes: 1
Reputation: 725
this question is almost identical to How to enforce only one property value to true in an array (JSON Schema) - check the answer to that one.
this is a little bit different because you have a maxItems
- this opens up an ugly option of brute-forcing the possible combinations.
I'm going to pretend your maxItems is 3 instead of 10 to cut down on verbosity:
definitions:
correctAnswer:
{properties: {isAnwser: {const: true}}}
incorrectAnswer:
{properties: {isAnwser: {const: false}}}
oneOf:
- items: [{'$ref': '#/definitions/correctAnswer'}, {'$ref': '#/definitions/incorrectAnswer'}, {'$ref': '#/definitions/incorrectAnswer'}]
- items: [{'$ref': '#/definitions/incorrectAnswer'}, {'$ref': '#/definitions/correctAnswer'}, {'$ref': '#/definitions/incorrectAnswer'}]
- items: [{'$ref': '#/definitions/incorrectAnswer'}, {'$ref': '#/definitions/incorrectAnswer'}, {'$ref': '#/definitions/correctAnswer'}]
ugly and unmaintainable! better to write this requirement in your code, unless / until you can use 2019-09.
other notes:
oneOf
checks that one of a set of schemas validates against the instance, not whether one element of an array instance validates against a schema.
you have "properties": {"isAnswer": true}
- what you want there is "properties": {"isAnswer": {"const": true}}
. what you have will use the true
schema which matches any instance. const
matches an instance equal to its value.
Upvotes: 2