问题
I have the following Schema. I've implemented it as best I can, but it's still not working quite as I want it to.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"title": "Ordering pizza",
"propertyNames": {
"enum": [
"q-who-did-you-order-from",
"q-did-they-accept-your-order",
"q-how-much-was-the-bill",
"q-why-didnt-they-accept"
]
},
"properties": {
"q-who-did-you-order-from": {
"type": "string",
"title": "Who have you ordered pizza from?",
"maxLength": 50,
"errorMessages": {
"required": "Enter who you ordered from",
"maxLength":
"Who you ordered from must be 50 characters or less"
}
},
"q-did-they-accept-your-order": {
"title": "Have they accepted your order?",
"type": "boolean",
"errorMessages": {
"required":
"Select yes if they have accepted your order"
}
},
"q-how-much-was-the-bill": {
"type": "string",
"title": "How much was the bill?",
"maxLength": 50,
"errorMessages": {
"required": "Enter an amount",
"maxLength": "Amount must be 50 characters or less"
}
},
"q-why-didnt-they-accept": {
"type": "string",
"title": "Why wasnt your order accepted?",
"description":
"If you do not know you can say so.",
"maxLength": 50,
"errorMessages": {
"required": "Enter a reason",
"maxLength": "Reason must be 50 characters or less"
}
}
},
"required": ["q-who-did-you-order-from", "q-did-they-accept-your-order"],
"allOf": [
{
"$ref": "#/definitions/if-false-then-q-why-didnt-they-accept-is-required"
},
{
"$ref": "#/definitions/if-true-then-q-how-much-was-the-bill-is-required"
}
],
"definitions": {
"if-false-then-q-why-didnt-they-accept-is-required": {
"if": {
"properties": {
"q-did-they-accept-your-order": {
"const": false
}
}
},
"then": {
"required": ["q-why-didnt-they-accept"],
"propertyNames": {
"enum": [
"q-who-did-you-order-from",
"q-did-they-accept-your-order",
"q-why-didnt-they-accept"
]
}
}
},
"if-true-then-q-how-much-was-the-bill-is-required": {
"if": {
"properties": {
"q-did-they-accept-your-order": {
"const": true
}
}
},
"then": {
"required": ["q-how-much-was-the-bill"],
"propertyNames": {
"enum": [
"q-who-did-you-order-from",
"q-did-they-accept-your-order",
"q-how-much-was-the-bill"
]
}
}
}
}
}
The expectation is that the user will enter a value for q-who-did-you-order-from and q-did-they-accept-your-order, then only one of the remaining two questions based on their answer for q-did-they-accept-your-order.
So the following inputs should validate:
{
"q-did-you-order-from": "Pizza hut",
"q-did-they-accept-your-order": "true",
"q-how-much-was-the-bill": "20"
}
{
"q-did-you-order-from": "Pizza hut",
"q-did-they-accept-your-order": "false",
"q-why-didn't-they-accept": "Incorrect card details"
}
Similarly, I would expect the following inputs to fail validation and throw a 'required' error for the field containing a blank string. The first should throw an error because q-why-didn't-they-accept is empty:
{
"q-did-you-order-from": "Pizza hut",
"q-did-they-accept-your-order": "false",
"q-why-didn't-they-accept": ""
}
And this one should throw an error because q-how-much-was-the-bill is empty.
{
"q-did-you-order-from": "Pizza hut",
"q-did-they-accept-your-order": "true",
"q-how-much-was-the-bill": ""
}
And it does! This works as expected. However, we found a bug that arises from the user not entering an answer to q-did-they-accept-your-order. The answers to these questions are POSTed via the browser on form submission. In the browser, the boolean question is presented as yes/no radio buttons. As a result, when the user does not check either radio, but does try to submit the form, the answer for the radios is omitted entirely. The data object sent looks like this:
{
"q-did-you-order-from": "Pizza hut",
"q-how-much-was-the-bill": "",
"q-why-didn't-they-accept": "",
}
My EXPECTED result here:
AJV throws only one 'required' error for q-did-they-accept-your-order. It shouldn't throw a 'required' error for anything else as both q-how-much-was-the-bill and q-why-didn't-they-accept aren't required unless the related value for q-did-they-accept-your-order is selected.
My ACTUAL result:
AJV Throws an error for all three empty inputs.
So my question is, how do I get AJV to validate this schema and for ONLY q-did-they-accept-your-order to throw a required error when the question is not answered.
EDIT:
The output from AJV is as follows:
[
{
"keyword": "required",
"dataPath": "",
"schemaPath": "#/required",
"params": {
"missingProperty": "q-did-they-accept-your-order"
},
"message": "should have required property 'q-did-they-accept-your-order'"
},
{
"keyword": "required",
"dataPath": "",
"schemaPath": "#/definitions/if-false-then-q-why-didnt-they-accept-is-required",
"params": {
"missingProperty": "q-why-didnt-they-accept"
},
"message": "should have required property 'q-why-didnt-they-accept'"
},
{
"keyword": "if",
"dataPath": "",
"schemaPath": "#/definitions/if-false-then-q-why-didnt-they-accept-is-required/if",
"params": {
"failingKeyword": "then"
},
"message": "should match \"then\" schema"
},
{
"keyword": "required",
"dataPath": "",
"schemaPath": "#/definitions/if-true-then-q-how-much-was-the-bill-is-required/then/required",
"params": {
"missingProperty": "q-how-much-was-the-bill"
},
"message": "should have required property 'q-how-much-was-the-bill'"
},
{
"keyword": "if",
"dataPath": "",
"schemaPath": "#/definitions/if-true-then-q-how-much-was-the-bill-is-required/if",
"params": {
"failingKeyword": "then"
},
"message": "should match \"then\" schema"
}
]
回答1:
There's a part missing from your application of the if
/then
pattern. Let's use this simple schema as an example.
{
"if": {
"properties": {
"foo": { "const": true }
}
},
"then": {
"required": ["bar"]
}
}
If I validate {}
against this schema, it will fail saying that the property "bar" is required. Because the /if
schema doesn't require the "foo" property, {}
is valid and therefore the /then
schema applies. To fix this problem, you just need to make the "foo" property required.
{
"if": {
"properties": {
"foo": { "const": true }
},
"required": ["foo"]
},
"then": {
"required": ["bar"]
}
}
Now, {}
is valid against the schema. the /then
schema will only apply if there is a "foo" property and it's value is true
.
来源:https://stackoverflow.com/questions/56424330/json-schema-conditional-validation