JSON Schema - 需要所有属性

Posted

技术标签:

【中文标题】JSON Schema - 需要所有属性【英文标题】:JSON Schema - require all properties 【发布时间】: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 就好了,其中布尔值替换了通常的数组。 【参考方案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

【讨论】:

以上是关于JSON Schema - 需要所有属性的主要内容,如果未能解决你的问题,请参考以下文章

使用 json-schema 来要求或禁止基于另一个属性值的属性?

JSON Schema 是不是可以使用引用外部属性的 if/then/else

具有未知属性名称的 JSON Schema

jsonSchema 属性有条件地需要

如何在 JSON Schema 和 Open API (OAS) 中定义 UUID 属性

基于枚举的 JSON Schema 切换对象属性