如何通过Ajv库实现基于外部变量的嵌套Schema动态校验?
使用Ajv根据外部变量动态调整嵌套结构校验Schema的解决方案
Ajv的标准if-else、data关键字仅能访问当前校验的JSON数据内部,无法直接获取校验作用域外的变量,可通过以下两种可行方式实现需求:
方案1:动态编译Schema(最直观)
在编译Schema前,直接根据外部变量的值修改Schema规则,再传给Ajv编译。适合外部变量在编译阶段就能确定的场景。
示例代码:
const Ajv = require('ajv'); const ajv = new Ajv(); // 外部变量 const userRole = 'admin'; // 可动态切换为'user' // 动态生成嵌套结构的Schema const dynamicSchema = { type: 'object', properties: { profile: { type: 'object', properties: { nickname: { type: 'string' }, // 根据外部角色动态调整权限字段的校验规则 authScopes: userRole === 'admin' ? { type: 'array', minItems: 2, items: { type: 'string' } } : { type: 'array', maxItems: 1, items: { type: 'string' } } }, required: ['nickname', 'authScopes'] } } }; // 编译并校验数据 const validate = ajv.compile(dynamicSchema); const result = validate({ profile: { nickname: 'super_admin', authScopes: ['manage_users', 'modify_settings'] } }); console.log(result, validate.errors); // 输出true,无错误
方案2:自定义关键字(支持校验时动态传参)
如果外部变量需要在校验阶段才确定,可以通过Ajv的自定义关键字,结合context或者闭包来传递外部变量。
示例代码:
const Ajv = require('ajv'); const ajv = new Ajv({ context: true }); // 开启context支持,用于传递外部变量 // 自定义关键字:根据外部角色校验数组长度 ajv.addKeyword({ keyword: 'roleBasedLength', type: 'array', validate: (schema, data, _, context) => { // 从context中获取外部传入的角色 const { role } = context; if (role === 'admin') { return data.length >= 2; } return data.length <= 1; }, errors: true, error: (ctx) => { return { message: `权限范围不符合${ctx.context.role}角色要求` }; } }); // 固定嵌套结构的Schema,使用自定义关键字 const fixedSchema = { type: 'object', properties: { profile: { type: 'object', properties: { nickname: { type: 'string' }, authScopes: { type: 'array', items: { type: 'string' }, roleBasedLength: true // 应用自定义校验规则 } }, required: ['nickname', 'authScopes'] } } }; // 编译Schema const validate = ajv.compile(fixedSchema); // 校验admin角色的数据 const adminValid = validate( { profile: { nickname: 'admin', authScopes: ['manage', 'modify'] } }, { role: 'admin' } // 传入外部角色到context ); console.log(adminValid, validate.errors); // true,无错误 // 校验普通用户的数据 const userValid = validate( { profile: { nickname: 'user', authScopes: ['read'] } }, { role: 'user' } ); console.log(userValid, validate.errors); // true,无错误
注意事项
- 标准
data关键字只能指向当前校验的JSON数据内部路径,无法访问外部环境变量,不要尝试用它实现需求。 - 使用自定义关键字时,如果通过
context传参,必须在初始化Ajv时开启context: true选项;如果用闭包引用外部变量,要注意变量的作用域和生命周期问题。
内容的提问来源于stack exchange,提问作者Ajay Kumar
相关产品推荐
相关产品推荐

