如何用JSON Schema验证数组中必填与可选对象及问题排查
问题分析与修正方案
核心问题定位
你的三个验证异常,根源在于原Schema未做到以下几点:
- 未精准强制必填对象的出现次数与唯一性
- 未严格限制对象的枚举字段与额外属性
- 未用排他性规则锁定允许的对象结构范围
修正后的完整JSON Schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "ArrayElements": { "type": "array", "maxItems": 6, "items": { "oneOf": [ // 必填对象类型A { "type": "object", "properties": { "name": { "const": "required-type-a" }, "keyA": { "type": "string" } }, "required": ["name", "keyA"], "additionalProperties": false }, // 必填对象类型B { "type": "object", "properties": { "name": { "const": "required-type-b" }, "keyB": { "type": "number" } }, "required": ["name", "keyB"], "additionalProperties": false }, // 可选对象集合(name为枚举值) { "type": "object", "properties": { "name": { "enum": ["optional-type-1", "optional-type-2", "optional-type-3", "optional-type-4"] }, "optionalKey": { "type": "boolean" } }, "required": ["name"], "additionalProperties": false } ] }, // 强制两个必填对象各出现1次 "allOf": [ { "contains": { "properties": { "name": { "const": "required-type-a" } }, "required": ["name"] }, "minContains": 1, "maxContains": 1 }, { "contains": { "properties": { "name": { "const": "required-type-b" } }, "required": ["name"] }, "minContains": 1, "maxContains": 1 } ], // 可选对象最多出现4次 "maxContains": { "properties": { "name": { "enum": ["optional-type-1", "optional-type-2", "optional-type-3", "optional-type-4"] } }, "required": ["name"] }, // 所有对象唯一(基于整体结构) "uniqueItems": true } }, "required": ["ArrayElements"], "additionalProperties": false }
关键修正说明
- 必填对象管控:通过
allOf嵌套两个contains规则,分别限定两类必填对象各出现恰好1次,满足“必填2个、唯一”的要求。 - 非法结构拦截:
items下的oneOf严格限定仅允许3类对象(2个必填+1组可选),每个对象设置additionalProperties: false,彻底禁止未定义属性。 - 可选对象限制:用
maxContains控制可选对象最多4次,同时给name字段设置枚举值,非枚举值直接验证失败。 - 总长度控制:
maxItems:6确保数组总长度不超过2(必填)+4(可选)的上限。
测试验证
- 有效案例(仅2个必填对象)
{ "ArrayElements": [ { "name": "required-type-a", "keyA": "demo" }, { "name": "required-type-b", "keyB": 456 } ] }
该案例会正常通过验证。
- 无效案例(非枚举name值)
{ "ArrayElements": [ { "name": "required-type-a", "keyA": "demo" }, { "name": "invalid-name", "keyX": "test" } ] }
非枚举name触发oneOf验证失败,被拦截。
- 无效案例(含额外属性)
{ "ArrayElements": [ { "name": "required-type-a", "keyA": "demo", "extraProp": "foo" }, { "name": "required-type-b", "keyB": 456 } ] }
额外属性触发additionalProperties: false验证失败,被拦截。
内容的提问来源于stack exchange,提问作者Kaz
相关产品推荐
相关产品推荐

