【问题标题】:JSON Schema - conditional validationJSON Schema - 条件验证
【发布时间】:2019-10-18 19:54:51
【问题描述】:

我有以下架构。我已经尽我所能实现了它,但它仍然没有像我想要的那样工作。

{
    "$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"
                    ]
                }
            }
        }
    }
}

期望用户将为 q-who-did-you-order-from 和 q-did-they-accept-your-order 输入一个值,然后根据他们的回答只输入其余两个问题之一对于 q-did-they-accept-your-order。

所以以下输入应该验证:

{
    "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"
}

同样,我希望以下输入验证失败并为包含空白字符串的字段抛出“必需”错误。第一个应该抛出一个错误,因为 q-why-did-they-accept 是空的:

{
    "q-did-you-order-from": "Pizza hut",
    "q-did-they-accept-your-order": "false",
    "q-why-didn't-they-accept": ""
}

这个应该抛出一个错误,因为 q-how-much-was-the-bill 是空的。

{
    "q-did-you-order-from": "Pizza hut",
    "q-did-they-accept-your-order": "true",
    "q-how-much-was-the-bill": ""
}

确实如此!这按预期工作。但是,我们发现了一个错误,该错误是由于用户没有输入 q-did-they-accept-your-order 的答案而引起的。这些问题的答案在表单提交时通过浏览器发布。在浏览器中,布尔问题显示为是/否单选按钮。结果,当用户没有检查任何一个收音机,但尝试提交表单时,收音机的答案将被完全省略。发送的数据对象如下所示:

{
    "q-did-you-order-from": "Pizza hut",
    "q-how-much-was-the-bill": "",
    "q-why-didn't-they-accept": "",
}

我的预期结果在这里:

AJV 只为 q-did-they-accept-your-order 抛出一个“必需”错误。它不应该为其他任何事情抛出“必需”错误,因为不需要 q-how-much-was-the-bill 和 q-why-did-they-accept 除非 q-did 的相关值-他们接受您的订单。

我的实际结果:

AJV 为所有三个空输入引发错误。

所以我的问题是,我如何让 AJV 验证此架构,并且只有 q-did-they-accept-your-order 在未回答问题时抛出所需的错误。

编辑:

AJV 的输出如下:

[
    {
        "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"
    }
]

【问题讨论】:

  • 它抛出的错误是什么?您能否将您的架构编辑为有效的 JSON 而不是 javascript? (需要在键周围加上双引号)。这将使使用使用 ajv 的jsonschema.dev 进行调试和测试变得更加容易。
  • @Relequestual 感谢您的回复,我已根据您的要求编辑了我的问题。

标签: jsonschema json-schema-validator ajv


【解决方案1】:

您的if/then 模式的应用程序缺少一部分。让我们以这个简单的模式为例。

{
  "if": {
    "properties": {
      "foo": { "const": true }
    }
  },
  "then": {
    "required": ["bar"]
  }
}

如果我针对此架构验证{},它将失败,说属性“bar”是必需的。因为/if 架构不需要“foo”属性,所以{} 是有效的,因此/then 架构适用。要解决此问题,您只需将“foo”属性设为必需即可。

{
  "if": {
    "properties": {
      "foo": { "const": true }
    },
    "required": ["foo"]
  },
  "then": {
    "required": ["bar"]
  }
}

现在,{} 对架构有效。 /then 模式仅适用于存在“foo”属性且其值为 true 的情况。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-18
    • 2015-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多