Python:使用jsonschema包验证模式和自定义错误消息

16

假设有这个架构:

{
    "type": "object",
    "properties": {
        "account": {
            "type": "object",
            "required": ["id"],
            "properties": {
                "id": {"type": "number"}
            }
        },
        "name": {"type": "string"},
        "trigger": {
            "type": "object",
            "required": ["type"],
            "properties": {
                "type": {"type": "string"}
            }
        },
        "content": {
            "type": "object",
            "properties": {
                "emails": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                        "type": "object",
                        "required": ["fromEmail","subject"],
                        "properties": {
                            "fromEmail": {"type": "string", "format": "email"},
                            "subject": {"type": "string"}
                        }
                    }
                }
            }
        }
    }
}

我正在尝试使用jsonschema.Draft4Validator来验证POST的JSON对象,以检查其有效性,但是我遇到了一些问题,尝试从返回的错误中获得更好的人类可读消息。

这是我如何进行验证:

from jsonschema import Draft4Validator

v = Draft4Validator(self.schema)
errors = sorted(v.iter_errors(autoresponder_workflow), key=lambda e: e.path)

if errors:
    print(', '.join(
        '%s %s %s' % (error.path.popleft(), error.path.pop(), error.message) for error in errors
    ))

错误信息如下:

content emails [] is too short, trigger type None is not of type u'string'

我试图创建一个更像是请在您的工作流中至少添加一个电子邮件," "请确保所有电子邮件都包含主题行等的错误消息。

4个回答

19
我需要在错误发生时向用户显示更详细的自定义消息。我通过在模式的属性中添加一个字段,然后在ValidationError中查找它来实现这一点。
import json
import jsonschema


def validate(_data, _schema):
    try:
        jsonschema.validate(_data, _schema)
    except jsonschema.ValidationError as e:
        return e.schema.get("error_msg", e.message)


schema = {
    "title": "index",
    "type": "object",
    "required": [
        "author",
        "description"
    ],
    "properties": {
        "author": {
            "type": "string",
            "description": "Name of the Author",
            "minLength": 3,
            "default": "",
            "error_msg": "Please provide a Author name"
        },
        "description": {
            "type": "string",
            "description": "Short description",
            "minLength": 10,
            "default": "",
            "error_msg": "Please add a short description"
        }
    }
}

data = {
    "author": "Jerakin",
    "description": ""
}

这真的很好。我对相同的问题感到沮丧,开始考虑在jsonschema规范中添加像“error_msg”这样的字段会是一个不错的补充。这是一个不错的解决办法。唯一想要添加的是错误消息中的插值,可能是。然而,考虑到通常用于处理传入数据(用户数据),这可能本质上是有风险的。另一个选择是将error_msg设置为回调函数。 - rfportilla
绝妙的解决方案。 - Rolly
@Jerakin 如果主键 - authordescription 缺失,这个会起作用吗? - user5319825
1
@user5319825 你可能需要在模式的根目录中添加一个 error_msg 来捕获它。但是,由于此阶段可能会有很多错误,我认为最好将错误消息返回给用户。我已经通过对 validate() 进行微调来更新我的答案。 - Jerakin

1
你可以捕获 ValidationError exception 并根据 ValidationError 的元数据构建特定情况下所需的自定义消息。在这个对象中,你有以下信息:
失败验证器的信息:其值和模式路径 失败实例的信息:其路径和验证失败时的值 子模式中可能存在的错误 原因(非验证错误导致的错误)

0

在运行验证之前,我使用这个擦洗函数。它将None转换为空字符串,因为jsonschema不喜欢处理None类型。在验证时,它会抛出:jsonschema.exceptions.ValidationError: None is not of type u'string'

def scrub(x):
    ret = copy.deepcopy(x)
    if isinstance(x, dict):
        for k, v in ret.items():
            ret[k] = scrub(v)
    if isinstance(x, (list, tuple)):
        for k, v in enumerate(ret):
            ret[k] = scrub(v)
    if x is None:
        ret = ''
    return ret

5
JSON模式标准强制进行类型检查,jsonschema只是符合该标准。实际上,None(又名"null")并不属于"string"类型。如果您希望null成为有效值,只需在架构对象中设置"type": ["string", "null"]即可。或者对于更复杂的类型,可以使用"oneOf"并将"null"添加为其中的一个选项。 - CivFan

0
你可以尝试使用 jsonschema.exceptions.ValidationError:
try:
    v = Draft4Validator(self.schema)
except jsonschema.exceptions.ValidationError as err:
    print(err.message)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接