【问题标题】:Schema Draft v7 if statement is not informing error in detailSchema Draft v7 if 语句未详细告知错误
【发布时间】:2018-11-09 11:55:20
【问题描述】:

我正在尝试使用 JsonSchema 中的 if 语句验证所需的属性,但它没有详细通知我该属性的错误。

验证已正确进行,但错误未指定属性以及哪个验证失败。

它适用于对象根级别中的必需属性,但是当我在对象内指定必需属性时,它只会警告 json 不匹配并指定 then 或 else 模式的路径。

架构示例:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": [
    "name",
    "partners"
  ],
  "properties": {
    "partners": {
      "type": "array",
      "items": {
        "type": "object",
        "if": {
          "properties": {
            "juridical": {
              "type": "object"
            },
            "natural": {
              "type": "null"
            }
          }
        },
        "then": {
          "properties": {
            "juridical": {
              "required": [ "tradeName" ],
              "properties": {
                "tradeName": {
                  "type": "string"
                }
              }
            }
          }
        },
        "else": {
          "properties": {
            "natural": {
              "required": ["name"],
              "properties": {
                "name": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  }
}

Json 示例:

{
  "name": "Joao",
  "partners": [
    {
      "juridical": null,
      "natural": {

      }
    },
    {
      "juridical": {
        "tradeName": ""
      },
      "natural": null
    }
  ]
}

它应该警告第一个合作伙伴具有所需的“名称”(Required properties are missing from object: name.),而不是只告诉我:JSON does not match schema from 'else'.。

使用像这样的简单架构,它可以按预期工作:

架构示例:

{
    "if": { "properties": { "power": { "minimum": 9000 } } },
    "then": { "required": [ "disbelief" ] },
    "else": { "required": [ "confidence" ] }
}

Json 示例:

{ "power": 10000 }

我正在使用JsonSchemaValidator.net 来验证结果。

【问题讨论】:

  • 您为什么相信“它应该警告第一个合作伙伴具有所需的“名称””?错误输出是否记录在案?

标签: json json.net jsonschema


【解决方案1】:

基本上,JSON 文档要么根据 JSON 模式进行验证,要么不进行验证。此逻辑贯穿所有子模式和条件。

错误信息的内容取决于 JSON Schema 验证器的具体实现。您使用的那个来自特定的提供商。正如 Relequestal 所指出的,您不能期望从特定实现中处理特定类型的错误消息,除非它是提供者文档所描述的。

如何向您使用的验证器的作者提出关于扩展 if-then-else 案例的消息的建议,以提供您的案例?

替代方法:据我了解,您的目标是使用这个特定的验证器获得尽可能多的特定错误信息。它就是这样,因此替代模式可能适合目标。由于 JSON Schema 本身是一个 JSON 文档,因此您可以考虑一种解决方法,以某种一致的方式命名 Schema 中的节点并使用逻辑运算符之一(“anyOf”(逻辑 OR)、“allOf”(逻辑 AND)、“oneOf” (逻辑异或))而不是 if-then-else。

请注意:基于模式的验证器,在“allOf”、“anyOf”、“oneOf”的情况下,预计会遍历所有模式,直到满足逻辑条件。

  • "allOf" - 将始终检查 JSON 文档是否针对所有模式进行验证 (与)

  • "anyOf" - 将检查 JSON 文档是否至少针对 1 个模式进行验证 (或者,因此某些验证器实现可能会在之后停止检查 第一个积极的结果,因为它足以评估检查 "anyOf" 到 true),

  • "oneOf" - 将始终检查 JSON 文档是否完全针对 通过检查所有模式(XOR)

(见:https://json-schema.org/draft-07/json-schema-validation.html#rfc.section.6.7.1)

因此,如果在上述情况下验证的实例与模式不匹配,验证器实现可能会在错误消息方面产生一些“误报”,因为它会列出遇到的问题与所有模式。它根本无法读懂我们的想法并猜测我们提供特定 JSON 文档的意思,所以它把一切都交给我们来判断和决定。

许多解决方案之一可能是定义“司法”和“自然”的变体,并将它们在逻辑上组合成模式,正如您所期望的那样:

要么法律是一个对象(+相关约束)并且自然不是一个对象或者法律不是一个对象并且自然是一个对象 (+相关约束)。

替代架构(请注意包含一些测试 JSON 文档的“示例”部分):

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": [
    "name",
    "partners"
  ],
  "properties": {
    "partners": {
      "type": "array",
      "items": {
        "type": "object",
        "anyOf" : [
          {"$ref" : "#/definitions/juridical-is-object-and-natural-is-null"},
          {"$ref" : "#/definitions/juridical-is-not-an-object-and-natural-is-an-object"}
        ],
        "required" : ["natural","juridical"]
      }
    }
  },
  "examples" : [
    {
      "name": "Joao",
      "partners": [
        {
          "juridical": null,
          "natural": {

          }
        },
        {
          "juridical": {
            "tradeName": ""
          },
          "natural": null
        }
      ]
    },
    {
      "name": "Joao",
      "partners": [
        {
          "juridical": null,
          "natural": {
            "name" : ""
          }
        },
        {
          "juridical": {
            "tradeName": ""
          },
          "natural": null
        }
      ]
    },
    {
      "name": "Joao",
      "partners": [
        {
          "juridical": null,
          "natural": {

          }
        },
        {
          "juridical": {
            "tradeName": ""
          },
          "natural": null
        },
        {
          "juridical" : [],
          "natural" : {}
        }
      ]
    }
  ],
  "definitions" : {
    "natural" : {
        "is-object" : {
          "type" : "object",
          "required": ["name"],
          "properties": {
            "name": {
              "type": "string"
            }
          }
        },
        "is-not-an-object" : {
          "not" : { "type" : "object" }
        },
    },
    "juridical" : {
      "is-object" : {
        "type" : "object",
        "required": ["tradeName"],
        "properties": {
          "name": {
            "type": "string"
          }
        }
      },
      "is-not-an-object" : {
        "not" : { "type" : "object" }
      },
    },
    "juridical-is-object-and-natural-is-null" : {
      "properties" : {
        "natural" : {"$ref" : "#/definitions/natural/is-not-an-object"},
        "juridical" : {"$ref" : "#/definitions/juridical/is-object"}
      },
    },
    "juridical-is-not-an-object-and-natural-is-an-object" : {
      "properties" : {
        "natural" : {"$ref" : "#/definitions/natural/is-object"},
        "juridical" : {"$ref" : "#/definitions/juridical/is-not-an-object"}
      }
    },
  }
}

注意事项:

"not" : { schema } 错误消息可能会让临时用户感到困惑,但它符合规范:https://json-schema.org/draft-07/json-schema-validation.html#rfc.section.6.7.4

更新

如 cmets 中所述,您需要了解错误详细信息。鉴于所选工具对更复杂模式的 if-then-else 错误详细信息的限制,您是否尝试使用不同的关键字重塑模式以触发尽可能少的开销消息?

替代架构 2

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": [
    "name",
    "partners"
  ],
  "properties": {
    "partners": {
      "type": "array",
      "items" : {
        "properties" : {
          "natural" : {
            "if" : { "type" : "object" },
            "then" : { "required" : ["name"] },
            "dependencies" : {
              "name" : {
                 "properties" : {
                  "name" : {"type" : "string"}
                 }
               }
            }
          },
          "juridical" : {
            "if" : { "type" : "object" },
            "then" : { "required" : ["tradeName"] },
            "dependencies" : {
              "tradeName" : {
                 "propertyNames" : {
                   "enum" : ["tradeName"]
                 },
                 "properties" : {
                  "tradeName" : {"type" : "string"}
                 }
               }
            }
          }
        },
        "anyOf" : [
          {"$ref" : "#/definitions/natural-is-null-juridical-is-an-object"},
          {"$ref" : "#/definitions/natural-is-an-object-juridical-is-null"}
        ]
      }
    }
  },
  "definitions" : {
    "natural-is-null-juridical-is-an-object" : {
        "properties" : {
            "natural" : { "type": "null"},
            "juridical" : { "type" : "object"}
        }
    },
    "natural-is-an-object-juridical-is-null" : {
        "properties" : {
            "natural" : { "type": "object"},
            "juridical" : { "type" : "null"}
        }
    },
  },
  "examples" : [
    {
      "name": "Joao",
      "partners": [
        {
          "juridical": null,
          "natural": {

          }
        },
        {
          "juridical": {
            "tradeName": "",
          },
          "natural": null
        },
        {
          "juridical" : {},
          "natural" : {}
        },
        {
          "juridical" : null,
          "natural" : null
        }
      ]
    },
  ]
} 

【讨论】:

  • 在了解 json 模式中的 if 语句之前,我尝试使用这些逻辑运算符(anyOf、oneOf、allOf)。问题是如果陈述不匹配,它会同时向所有对象显示错误,自然的和法律的。因此,如果某些、任何或所有模式不匹配,它会为每个合作伙伴应用所有模式,并向我显示错误。
  • 我的目标是知道何时通知某个字段。我想要一个字段是必需的特定错误,因此我可以将其保存在数据库中并公开一个端点以请求实体的缺失字段。我使用 JSON Path 实现了一个解决方案,但它似乎不是验证必填字段的正确工具,主要是当我必须像与合作伙伴一样应用验证逻辑时,这有时是自然的或合法的(我知道这是一个糟糕的合同设计)。所以我创建了一个规则模型,它存在一个前置 JSON 路径验证器字段,如果为 true,则应用其他相关规则。
  • 好吧,看来你应该向验证者作者提交一份关于 if-then-else 详细消息的票。是的,逻辑运算符——这就是我的意思,它把它们都扔给你,因为在无效对象的情况下,没有心灵感应预测对象请求者的意思。您也可以考虑使用“依赖项” - 但它可能会迫使您更改模型。您是否尝试过使用“依赖项”,例如:当出现司法领域时,它是一个对象 - 需要一些东西?
  • 只是跟进:为了在对象级别使用“依赖项”和/或在数组级别使用“包含”(甚至是元组验证),您需要在此定义其他条件案子。有吗?例如。该表是否必须包含至少一个具有法律或自然属性不为空的对象?每种一种?或者它们可能需要在表格中以特定顺序出现?
  • @JoãoPedro 我已经用另一个替代模式更新了答案,考虑到 if-then-else 错误详细信息的工具限制,它的形状可以触发尽可能多的唯一有意义的错误。然而,有一个“anyOf”,错误细节的意义取决于“定义”部分中的命名节点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-09-07
  • 2017-04-28
  • 2018-01-06
  • 2018-09-20
  • 2011-09-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多