JSON 架构 - 需要所有属性

JSON Schema - require all properties

JSON 架构中的 required 字段

JSON 架构具有 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 的列表中,当列表因拼写错误和其他愚蠢的错误而不匹配时,我会遇到烦人的错误。

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

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

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

脚本只需要遍历json-schema树,在每一层,如果找到"properties"关键字,添加一个包含所有定义键的"required"关键字在同一级别的属性中。

让机器做钻孔工作。

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

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

我在单行代码中执行此操作,例如,如果我想在数据库中将 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
    }
}

按照其他人的建议,这里是这样的 post-处理 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

如果您在 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: []

您可以使用以下功能:

export function addRequiredAttributeRecursive(schema) {
  if (schema.type === 'object') {
    schema.required = [];
    Object.keys(schema.properties).forEach((key) => {
      schema.required.push(key);
      if (schema.properties[key].type === 'object') {
        schema.properties[key] = addRequiredAttributeRecursive(
          schema.properties[key],
        );
      } else if (schema.properties[key].type === 'array') {
        schema.properties[key].items = addRequiredAttributeRecursive(
          schema.properties[key].items,
        );
      }
    });
  } else if (schema.type === 'array') {
    if (schema.items.type === 'object') {
      schema.items = addRequiredAttributeRecursive(schema.items);
    }
  }

  return schema;
}

它递归地为每个 属性 写入您拥有的架构中所有对象的 required 属性。

如果您使用Javascript,您可以使用property getter

{
    "type": "object",
    "properties": {
        "elephant": {"type": "string"},
        "giraffe": {"type": "string"},
        "polarBear": {"type": "string"}
    },
    get required() { return Object.keys(this.properties) },
    "additionalProperties": false
}