【问题标题】:JSON Schema - require all propertiesJSON Schema - 需要所有属性
【发布时间】:2015-09-01 07:08:45
【问题描述】:

JSON Schema 中的required 字段

JSON Schema 具有 propertiesrequiredadditionalProperties 字段。例如,

{
    "type": "object",
    "properties": {
        "elephant": {"type": "string"},
        "giraffe": {"type": "string"},
        "polarBear": {"type": "string"}
    },
    "required": [
        "elephant",
        "giraffe",
        "polarBear"
    ],
    "additionalProperties": false
}

将验证 JSON 对象,例如:

{
    "elephant": "Johnny",
    "giraffe": "Jimmy",
    "polarBear": "George"
}

但如果属性列表不是完全正确 elephant, giraffe, polarBear,则会失败。

问题

我经常将properties 的列表复制粘贴到required 的列表中,当由于拼写错误和其他愚蠢的错误导致列表不匹配时,我会遇到烦人的错误。

有没有更简洁的方式来表示所有属性都是必需的,而不明确命名它们?

【问题讨论】:

  • 如果 JSON Schema 规范支持 "required": true 就好了,其中布尔值替换了通常的数组。

标签: jsonschema


【解决方案1】:

您可以只使用“minProperties”属性而不是显式命名所有字段。

{
    "type": "object",
    "properties": {
        "elephant": {"type": "string"},
        "giraffe": {"type": "string"},
        "polarBear": {"type": "string"}
    },
    "additionalProperties": false,
    "minProperties": 3
}

【讨论】:

  • 迄今为止最好的方法。
  • 谢谢,这很好用。但要记住的一件事是,它取决于 "additionalProperties": false 的规范如果 additionalProperties 按规范或默认为 true(如果未指定),则 minProperties 约束可以通过 not 架构对象中的指定之一。
  • 错误信息这样用处不大。您知道自己缺少一处房产,但必须弄清楚是哪一处。尽管如此,还是比每次都复制所有属性要好。
  • 很好的解决方案。我想使用它,尽管我发现它是一个挑战,因为我在给定对象中的#properties 依赖于“oneOff”选择。因此,minProperties 应该理想地在两个整数之间切换,具体取决于用户在另一个属性中的选择。关于是否/如何实现这一点的任何想法?
  • 当您的对象是使用allOf 的另一个对象的扩展时,这不能很好地工作。它要求父对象具有除子对象之外所需的所有属性。如果父对象发生变化,它还需要遍历每个子对象并更新属性计数。
【解决方案2】:

我怀疑是否存在指定所需属性的方法,而不是在所需数组中显式命名它们。

但是如果你经常遇到这个问题,我建议你编写一个小脚本,对你的 json-schema 进行后处理,并为所有定义的对象自动添加所需的数组。

脚本只需要遍历json-schema树,并且在每一层,如果找到“properties”关键字,添加一个“required”关键字,所有定义的key都包含在同一层的properties中。

让机器做无聊的事情。

【讨论】:

    【解决方案3】:

    如果您在 python 中使用库 jsonschema,请使用自定义验证器:

    首先创建自定义验证器:

    # Custom validator for requiring all properties listed in the instance to be in the 'required' list of the instance
    def allRequired(validator, allRequired, instance, schema):
        if not validator.is_type(instance, "object"):
            return
        if allRequired and "required" in instance:
            # requiring all properties to 'required'
            instanceRequired = instance["required"]
            instanceProperties = list(instance["properties"].keys())
            for property in instanceProperties:
                if property not in instanceRequired:
                    yield ValidationError("%r should be required but only the following are required: %r" % (property, instanceRequired))
            for property in instanceRequired:
                if property not in instanceProperties:
                    yield ValidationError("%r should be in properties but only the following are properties: %r" % (property, instanceProperties))
    
    

    然后扩展一个现有的验证器:

    all_validators = dict(Draft4Validator.VALIDATORS)
    all_validators['allRequired'] = allRequired
    
    customValidator = jsonschema.validators.extend(
        validator=Draft4Validator,
        validators=all_validators
    )
    

    现在测试:

    schema =  {"allRequired": True}
    instance = {"properties": {"name": {"type": "string"}}, "required": []}
    v = customValidator(schema)
    errors = validateInstance(v, instance)
    

    你会得到错误: 'name' should be required but only the following are required: []

    【讨论】:

    • 好主意。如果我不想在实现中保持语言不可知论,我会选择这个答案。我想这可以推到源头。
    【解决方案4】:

    我使用单行代码在代码中执行此操作,例如,如果我想在 DB 中将 required 用于 insert,但只想在执行 update 时验证架构。

    prepareSchema(action) {
        const actionSchema = R.clone(schema)
        switch (action) {
            case 'insert':
                actionSchema.$id = `/${schema.$id}-Insert`
                actionSchema.required = Object.keys(schema.properties)
                return actionSchema
            default:
                return schema
        }
    }
    

    【讨论】:

      【解决方案5】:

      按照其他人的建议,这是这样的后处理python代码:

      def schema_to_strict(schema):
          if schema['type'] not in ['object', 'array']:
              return schema
      
          if schema['type'] == 'array':
              schema['items'] = schema_to_strict(schema['items'])
              return schema
      
          for k, v in schema['properties'].items():
              schema['properties'][k] = schema_to_strict(v)
      
          schema['required'] = list(schema['properties'].keys())
          schema['additionalProperties'] = False
          return schema
      

      【讨论】:

        猜你喜欢
        • 2012-07-28
        • 1970-01-01
        • 2021-01-25
        • 1970-01-01
        • 2015-10-23
        • 1970-01-01
        • 2017-01-16
        • 1970-01-01
        • 2020-02-05
        相关资源
        最近更新 更多