如何基于数据条件实现带子Schema的AJV自定义关键字验证
实现AJV自定义条件选择子Schema的关键字
核心思路
直接用AJV的addKeyword方法注册自定义关键字,在关键字的验证逻辑里根据数据的特定条件(比如示例中n的奇偶性)动态选择对应的子Schema执行验证,替代原生oneOf+discriminator的生硬逻辑,避免返回一堆无关错误。
完整实现代码
const Ajv = require('ajv'); const ajv = new Ajv(); // 注册自定义关键字,这里命名为conditionalSchema ajv.addKeyword('conditionalSchema', { type: 'object', // 验证逻辑函数,参数为关键字配置、待验证数据等 validate: function (schemaConfig, data) { // 根据数据条件匹配对应的子Schema let targetSchema; if (data.n % 2 === 0) { targetSchema = schemaConfig.even; } else { targetSchema = schemaConfig.odd; } // 编译并验证选中的子Schema const validateSub = ajv.compile(targetSchema); const isValid = validateSub(data); // 把子Schema的验证错误挂载到当前上下文 if (!isValid) { this.errors = validateSub.errors; return false; } return true; } }); // 定义验证Schema const mySchema = { "type": "object", "properties": { "n": {"type": "number"} }, "required": ["n"], "conditionalSchema": { "even": { "properties": { "p": {"type": "string"} }, "required": ["p"] }, "odd": { "properties": { "p": {"type": "number"} }, "required": ["p"] } } }; // 编译Schema并测试 const validate = ajv.compile(mySchema); // 测试用例1:偶数n对应字符串p const data1 = {n: 2, p: "test"}; console.log(validate(data1), validate.errors); // true, null // 测试用例2:奇数n对应数字p const data2 = {n: 3, p: 123}; console.log(validate(data2), validate.errors); // true, null // 测试用例3:偶数n但p是数字,返回对应错误 const data3 = {n: 4, p: 567}; console.log(validate(data3), validate.errors); // false, [{instancePath: '/p', message: 'must be string', ...}]
针对oneOf场景的适配说明
如果你的实际场景是把分支Schema放在oneOf数组里,只需修改自定义关键字的逻辑:给每个oneOf子Schema加自定义匹配字段(比如matchCondition),然后在验证逻辑里遍历oneOf数组,找到符合条件的子Schema单独验证,这样就不会像原生oneOf那样返回所有不匹配的错误,只会输出选中Schema的验证问题。
内容的提问来源于stack exchange,提问作者MattBas
相关产品推荐
相关产品推荐

