如何在JSON Schema中根据Task Type引用对应子Schema验证数据?
根据Task的Type字段动态验证Properties的JSON Schema实现方案
问题描述
我正在编写JSON Schema以验证数据,但遇到实现需求的问题:需要根据Task的type字段,对properties字段做差异化验证,同时抽离Task的公共属性到统一Schema中。
数据示例
{ "orderName": "CoreCapital", "orderType": "Capital", "requestId": "Generated ID", "tasks": [ { "type": "User", "taskId": 1, "name": "Level-1", "executor": "Marine", "description": "Get Details", "properties": { "stateId": 123, "params": [ "parameter1", "parameter2" ] } }, { "type": "Manager", "taskId": 2, "name": "Level-2", "executor": "Shipping", "description": "Shipping Details", "properties": { "id": 2345, "baseId": "Shipping-23", "method": "POST", "params": { "Id": "1234", "tag": "Fire" }, "locale": { "USA": "tag-1", "Canada": "tag-2", "Europe": "tag-3" } } }, { "type": "Director", "taskId": 3, "name": "Level-3", "executor": "Transport", "description": "Transport Details", "properties": { "name": "Water-resource", "payload": "truck details", "Size": "40 ton", "State": { "CA": "tag-4", "AR": "tag-5", "MS": "tag-6" } } } ] }
(注:已修正原数据中的语法错误,不影响Schema验证逻辑)
需求
- 对每个Task做差异化验证:
type为User时,properties符合UserProperties子Schema;type为Manager时符合ManagerProperties;type为Director时符合DirectorProperties。 - 抽离Task的公共属性(如
taskId、name等)到统一Schema中。
解决方案
使用JSON Schema的if/then条件验证特性,结合allOf和oneOf来实现逻辑,以下是完整的Schema示例:
{ "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { "orderName": { "type": "string" }, "orderType": { "type": "string" }, "requestId": { "type": "string" }, "tasks": { "type": "array", "items": { "allOf": [ // 公共Task属性验证 { "type": "object", "required": ["type", "taskId", "name", "executor", "description", "properties"], "properties": { "type": { "enum": ["User", "Manager", "Director"] }, "taskId": { "type": "integer" }, "name": { "type": "string" }, "executor": { "type": "string" }, "description": { "type": "string" } } }, // 按type字段匹配对应的properties验证规则 { "oneOf": [ { "if": { "properties": { "type": { "const": "User" } } }, "then": { "properties": { "properties": { "$ref": "#/$defs/UserProperties" } } } }, { "if": { "properties": { "type": { "const": "Manager" } } }, "then": { "properties": { "properties": { "$ref": "#/$defs/ManagerProperties" } } } }, { "if": { "properties": { "type": { "const": "Director" } } }, "then": { "properties": { "properties": { "$ref": "#/$defs/DirectorProperties" } } } } ] } ] } } }, "required": ["orderName", "orderType", "requestId", "tasks"], "$defs": { "UserProperties": { "type": "object", "required": ["stateId", "params"], "properties": { "stateId": { "type": "integer" }, "params": { "type": "array", "items": { "type": "string" } } } }, "ManagerProperties": { "type": "object", "required": ["id", "baseId", "method", "params", "locale"], "properties": { "id": { "type": "integer" }, "baseId": { "type": "string" }, "method": { "type": "string", "enum": ["POST"] }, "params": { "type": "object", "required": ["Id", "tag"], "properties": { "Id": { "type": "string" }, "tag": { "type": "string" } } }, "locale": { "type": "object", "patternProperties": { "^(USA|Canada|Europe)$": { "type": "string" } }, "additionalProperties": false } } }, "DirectorProperties": { "type": "object", "required": ["name", "payload", "Size", "State"], "properties": { "name": { "type": "string" }, "payload": { "type": "string" }, "Size": { "type": "string" }, "State": { "type": "object", "patternProperties": { "^(CA|AR|MS)$": { "type": "string" } }, "additionalProperties": false } } } } }
关键逻辑说明
- 公共属性复用:通过
allOf将公共Task属性Schema与条件验证规则组合,确保所有Task都满足基础字段要求。 - 条件验证:使用
if/then搭配const精准匹配type值,当type符合指定值时,强制properties字段匹配对应的子Schema。 - 分支唯一性:用
oneOf包裹三个条件分支,确保每个Task只会触发其中一组验证规则,避免冲突。 - 子Schema管理:所有Properties子Schema定义在
$defs(Draft 07及以上版本推荐)中,提升可读性和维护性。
常见问题排查
如果验证器未按预期工作,可检查以下几点:
- 验证器是否支持JSON Schema Draft 07及以上版本:
if/then和const是Draft 07新增特性,需使用支持该版本的验证器(如Ajv v6+)。 $ref路径是否正确:确保引用路径与子Schema的定义位置一致(如用#/$defs/xxx而非旧版的#/definitions/xxx)。- 公共Schema是否限制了
properties字段:公共属性Schema中不要对properties字段做额外限制,避免覆盖条件规则中的定义。
内容的提问来源于stack exchange,提问作者Seegel
相关产品推荐
相关产品推荐

