如何使用Joi基于计算值验证JavaScript对象?
使用Joi实现自定义计算值验证的方案
没问题,我帮你把这段原生JavaScript的验证逻辑转换成Joi的实现。Joi的custom()方法正好适合这种需要基于计算值做验证的场景,下面是完整的实现步骤和代码:
1. 先安装Joi(如果还没安装)
npm install joi
2. 完整的Joi Schema实现
const Joi = require('joi'); // 定义单个question的验证规则 const questionSchema = Joi.object({ question: Joi.string().required().description('问题文本不能为空'), answer: Joi.number().required().description('答案值不能为空'), factor: Joi.number().optional().default(1).description('权重因子可选,默认值为1') }); // 定义整个文档的验证规则 const docSchema = Joi.object({ scoreThreshold: Joi.number().required().description('分数阈值不能为空'), questions: Joi.array().items(questionSchema).min(1).description('问题列表不能为空') }) .custom((value, helpers) => { // 计算maxScore,和原生逻辑一致 const maxScore = value.questions.reduce((total, item) => { return total + 1000 * item.factor; }, 0); // 第一个验证点:maxScore不能为0 if (maxScore === 0) { return helpers.error('custom.maxScoreZero'); } // 第二个验证点:scoreThreshold不能大于maxScore if (value.scoreThreshold > maxScore) { return helpers.error('custom.thresholdExceedsMax'); } // 第三个验证点:scoreThreshold与maxScore的比值不能超过0.95 if ((value.scoreThreshold / maxScore) > 0.95) { return helpers.error('custom.thresholdTooClose'); } // 验证通过,返回原对象 return value; }) // 自定义错误消息,让提示更友好 .messages({ 'custom.maxScoreZero': 'maxScore 不能为0', 'custom.thresholdExceedsMax': 'scoreThreshold 不能大于 maxScore', 'custom.thresholdTooClose': 'scoreThreshold 与 maxScore 的比值不能超过0.95' });
3. 使用方式
// 待验证的对象 const doc = { "scoreThreshold": 1, "questions": [ { "question": "someString", "answer": 1, "factor": 2 }, { "question": "someString", "answer": 3 }, { "question": "someString", "answer": 0, "factor": 3 }, { "question": "someString", "answer": 1 } ] }; // 执行验证 const { error, value } = docSchema.validate(doc); if (error) { console.error('验证失败:', error.details[0].message); } else { console.log('验证通过:', value); }
关键逻辑说明
- 我们先用
questionSchema定义了单个问题的字段规则,确保question和answer必填,factor可选且默认值为1,和你原生逻辑里的item.factor == undefined ? 1 : item.factor对应。 - 主schema里给
questions加了min(1),避免空数组导致maxScore为0的情况(当然自定义验证里也做了兜底判断)。 - 使用
custom()方法注入自定义验证逻辑,这里完全复用了你原生代码里的计算和判断逻辑,通过helpers.error()抛出自定义错误。 - 最后用
messages()给每个自定义错误添加了友好的提示信息,方便调试和返回给用户。
内容的提问来源于stack exchange,提问作者Alok
相关产品推荐
相关产品推荐

