如何使用Ajv验证包含不同嵌套$schema值的数据?
问题分析与解决方案
核心问题
Ajv 默认不会识别数据中的$schema字段来自动切换验证使用的 schema。你当前代码里的anyOf逻辑只是让foo匹配intSchema或strSchema中的任意一个,所以dataB里的value:1因为符合intSchema的规则,导致anyOf条件满足,最终返回true——这和数据里的$schema字段完全无关,因为对Ajv来说,这个字段只是普通的对象属性。
解决方案:用$data关键字实现动态schema引用
Ajv 支持通过$data关键字(需手动启用)引用数据字段的值,以此动态选择要使用的验证schema。
修改后的代码示例
const ajv = new Ajv({ $data: true }); // 启用$data关键字支持 const mainSchema = { $id: "mainSchema", type: "object", properties: { foo: { // 引用当前foo对象的$schema字段值对应的schema $ref: { $data: "0/$schema" } }, }, }; const intSchema = { $id: "intSchema", type: "object", properties: { value: { type: "integer" }, // 可选:强制数据中的$schema值必须与当前schema的$id匹配 $schema: { const: "intSchema" } }, required: ["value"] }; const strSchema = { $id: "strSchema", type: "object", properties: { value: { type: "string" }, $schema: { const: "strSchema" } }, required: ["value"] }; const dataA = { $schema: "mainSchema", foo: { $schema: "intSchema", value: 42, }, }; const dataB = { $schema: "mainSchema", foo: { $schema: "strSchema", value: 1, }, }; const dataC = { $schema: "mainSchema", foo: { $schema: "unknownSchema", value: false, }, }; ajv.addSchema([intSchema, strSchema]); const validate = ajv.compile(mainSchema); console.log(validate(dataA)); // true console.log(validate(dataB)); // false(符合预期) console.log(validate(dataC)); // false
代码说明
- 启用
$data选项:创建Ajv实例时传入{ $data: true },开启数据字段引用功能。 - 动态引用schema:
$ref: { $data: "0/$schema" }表示取当前foo对象的$schema字段值,作为要引用的schema的$id,实现根据数据指定的schema进行验证。 - 可选的字段一致性校验:在子schema中添加
$schema: { const: "xxxSchema" },可以确保数据里的$schema值和当前验证的schema严格匹配,避免出现“数据指定了strSchema但实际符合intSchema”的混淆情况。
备选方案:手动遍历数据验证
如果你不想依赖$data关键字,也可以手动遍历数据对象,提取每个嵌套对象的$schema字段值,从Ajv实例中获取对应的schema进行单独验证。这种方式更繁琐,但适合复杂的自定义场景。
内容的提问来源于stack exchange,提问作者Garth Braithwaite
相关产品推荐
相关产品推荐

