能否在JSON Schema的if逻辑中修改$defs定义?
多语言翻译字段的JSON Schema条件验证复用问题
我需要为包含多语言翻译字符串的数据结构编写JSON Schema,示例数据如下:
{ "supportedLanguages": ["en", "fr"], "serviceName": { "en": "My App", "fr": "Mon Application" }, "customerSupportEmail": { "en": "help@myapp.com" } }
我已经实现了按属性单独设置条件验证:当supportedLanguages包含某语言时,对应翻译字段必须包含该语言的键。现在希望通过$defs复用验证逻辑,于是尝试在if-then结构中修改$defs里的translatedString定义,代码如下:
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "example", "type": "object", "properties": { "supportedLanguages": { "type": "array", "items": { "type": "string", "enum": ["en", "fr", "de"] }, "minItems": 1, "uniqueItems": true }, "serviceName": { "$ref": "#/$defs/translatedString" }, "customerSupportEmail": { "$ref": "#/$defs/translatedString" } }, "$defs": { "translatedString": { "type": "object", "properties": { "en": { "type": "string" }, "fr": { "type": "string" }, "de": { "type": "string" } } } }, "allOf": [ { "if": { "properties": { "supportedLanguages": { "type": "array", "contains": { "const": "en" } } } }, "then": { "$defs": { "translatedString": { "type": "object", "required": ["en"] } } } } ] }
但在Node.js的AJV中验证无效,请问是否存在方法在if-then-else结构中为$defs定义添加条件?
问题根源
你不能在if-then的then块中重新定义$defs——JSON Schema的$defs是静态的,只能在Schema的顶层(或嵌套的$defs块中)定义,无法通过条件逻辑动态修改引用的定义内容。AJV会忽略then块里的$defs,所以你的条件验证规则根本没生效。
正确实现方式
要复用验证逻辑,应该把条件验证逻辑直接整合到$defs的translatedString中,或者通过allOf结合动态规则来实现。这里推荐两种可行方案:
方案1:利用$data关键字动态关联(推荐)
通过AJV支持的$data关键字,可以直接根据supportedLanguages数组的值,动态要求翻译字段包含对应语言键:
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "example", "type": "object", "properties": { "supportedLanguages": { "type": "array", "items": { "type": "string", "enum": ["en", "fr", "de"] }, "minItems": 1, "uniqueItems": true }, "serviceName": { "$ref": "#/$defs/translatedString" }, "customerSupportEmail": { "$ref": "#/$defs/translatedString" } }, "$defs": { "translatedString": { "type": "object", "properties": { "en": { "type": "string" }, "fr": { "type": "string" }, "de": { "type": "string" } }, "required": { "$data": "/supportedLanguages" } } }, "required": ["supportedLanguages"] }
注意:使用此方案需要在初始化AJV时添加配置{ $data: true }来启用$data支持。
方案2:通过allOf批量添加条件规则
如果无法使用$data,可以为每个语言单独编写if-then规则,复用translatedString的基础定义:
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "example", "type": "object", "properties": { "supportedLanguages": { "type": "array", "items": { "type": "string", "enum": ["en", "fr", "de"] }, "minItems": 1, "uniqueItems": true }, "serviceName": { "$ref": "#/$defs/translatedString" }, "customerSupportEmail": { "$ref": "#/$defs/translatedString" } }, "$defs": { "translatedString": { "type": "object", "properties": { "en": { "type": "string" }, "fr": { "type": "string" }, "de": { "type": "string" } } } }, "allOf": [ { "if": { "properties": { "supportedLanguages": { "contains": { "const": "en" } } } }, "then": { "properties": { "serviceName": { "required": ["en"] }, "customerSupportEmail": { "required": ["en"] } } } }, { "if": { "properties": { "supportedLanguages": { "contains": { "const": "fr" } } } }, "then": { "properties": { "serviceName": { "required": ["fr"] }, "customerSupportEmail": { "required": ["fr"] } } } }, { "if": { "properties": { "supportedLanguages": { "contains": { "const": "de" } } } }, "then": { "properties": { "serviceName": { "required": ["de"] }, "customerSupportEmail": { "required": ["de"] } } } } ], "required": ["supportedLanguages"] }
这个方案兼容性更好,不需要依赖$data特性。
总结
- 禁止在
if-then块中修改$defs,这不符合JSON Schema规范。 - 优先使用
$data实现动态关联,代码更简洁高效。 - 若无法使用
$data,则通过allOf结合多个if-then规则复用验证逻辑。
内容的提问来源于stack exchange,提问作者Prave Uption
相关产品推荐
相关产品推荐

