我正在尝试使用 Python 验证 Python 中的json
有效负载,使用jsonschema 3.0.1
,大致看起来像这样(简化为麻烦的部分(:
{
"request": {
"topic": {
"param1": "bleep beep topic",
"param2": "bloop boop topic"
},
"message": {
"param1": "bleep beep message",
"param2": "bloop boop message"
}
}
}
有效请求应具有两个字段:topic
和匹配message
。
它们中的每一个都可以仅包含param1
,也可以由param1
和param2
组成。
- 有效:
topic { param1, param2 }, body { param1, param2 }
- 有效:
topic { param1 }, body { param1 }
但它既不能有只有param1
的topic
和身体,也不能有两者兼而有之的topic
和只有param2
的身体:
- 无效:
topic { param1, param2 }, body { param1 }
- 无效:
topic { param1}, body { param1, param2 }
由于一个节点的内容取决于另一个节点的内容,因此我无法使用dependencies
关键字或if-then-else
构造,因此我尝试使用oneOf
,并提供有效子架构的列表,其中包含对该字段的one_param
和both_params
版本的引用,如下所示:
from jsonschema import validate
one_param = {
"type": "object",
"properties": {
"param1": {
"type": "string",
}
},
"required": ["param1"]
}
both_params = {
"type": "object",
"properties": {
"param1": {
"type": "string",
},
"param2": {
"type": "string",
}
},
"required": ["param1", "param2"]
}
test_schema = {
"type": "object",
"properties": {
"request": {
"oneOf": [
{
"type": "object",
"properties": {
"topic": one_param,
"message": one_param
},
"required": ["topic", "message"]
},
{
"type": "object",
"properties": {
"topic": both_params,
"message": both_params
},
"required": ["topic", "message"]
}
],
}
}
}
验证器的行为不是我所期望的:它在两个参数的情况下都失败了,并且成功地验证了一个参数或不匹配的参数的情况。
为什么我的验证架构无法像我解释的那样工作?
这是我为此目的编写的整个测试:
good_1
案例验证失败good_2
、bad_1
和bad_2
案例成功验证
from jsonschema import validate
one_param = {
"type": "object",
"properties": {
"param1": {
"type": "string",
}
},
"required": ["param1"]
}
both_params = {
"type": "object",
"properties": {
"param1": {
"type": "string",
},
"param2": {
"type": "string",
}
},
"required": ["param1", "param2"]
}
test_schema = {
"type": "object",
"properties": {
"request": {
"oneOf": [
{
"type": "object",
"properties": {
"topic": one_param,
"message": one_param
},
"required": ["topic", "message"]
},
{
"type": "object",
"properties": {
"topic": both_params,
"message": both_params
},
"required": ["topic", "message"]
}
],
}
}
}
good_1 = {
"request": {
"topic": {
"param1": "bleep beep",
"param2": "bloop boop"
},
"message": {
"param1": "bleep beep message",
"param2": "bloop boop message"
}
}
}
good_2 = {
"request": {
"topic": {
"param1": "bleep beep"
},
"message": {
"param1": "bleep beep message"
}
}
}
bad_1 = {
"request": {
"topic": {
"param1": "bleep beep",
},
"message": {
"param1": "bleep beep message",
"param2": "bloop boop message with no matching topic"
}
}
}
bad_2 = {
"request": {
"topic": {
"param1": "bleep beep",
"param2": "bloop boop topic with no matching message"
},
"message": {
"param1": "bleep beep message"
}
}
}
validate(good_1, test_schema) # should validate
validate(good_2, test_schema) # should validate
validate(bad_1, test_schema) # should fail
validate(bad_2, test_schema) # should fail
使用oneOf
时,数组中的每个项目(子架构(都应用于数据。如果你测试oneOf
中的每个子架构,会发生什么?
你会发现两者都是有效的!
"one_param"
架构需要确保包含param2
会导致其失败。您可以使用additionalProperties
来执行此操作...
{
"type": "object",
"properties": {
"param1": {
"type": "string"
}
},
"required": [
"param1"
],
"additionalProperties": false
}
我认为您假设只允许在properties
中定义的属性,但事实并非如此,因此您还需要在required
中定义它们。
您可以通过在 https://jsonschema.dev 上尝试架构来了解此功能。我已经使用更新的架构和实例预加载了链接。
顺便说一句,如果您希望将架构保存到单个 json 文件中,您可以使用definitions
和$ref
来避免重复子架构。