如何为指定数据编写正确的Joi Schema验证?
问题:Joi验证Schema报错"refinementGoals[2].value" is not allowed
待验证的输入数据
{ "submissionReason": "new TPV required", "alignerInfo": { "name": "UPPER", "value": [ { "name": "set", "value": "18/20" }, { "name": "zenStage", "value": "2" } ] }, "archesToTreat": "BOTH", "refinementGoals": [ { "name": "Alignment" }, { "name": "Close Residual Space", "value": [ { "position": [ "2.1", "2.2" ], "value": "0.5" }, { "position": [ "2.4", "2.5" ], "value": "0.7" } ] }, { "name": "Resolve posterior Open Bite", "value": [ { "name": "Attachments Only", "value": { "name": "teeth Attachment", "value": [ "2.1", "2.2" ] } }, { "name": "Add Button for elastic", "value": [ "2.1", "2.2" ] } ] } ], "attachments": "keep all previous attachment and change", "iprInfo": { "name": "ipr not performed as prescibed", "value": [ { "position": [ "2.1", "2.2" ], "value": "0.5" } ] }, "specialNotes": "Doctor Notes" }
当前使用的验证代码
Joi.object({ submissionReason: Joi.string().required(), alignerInfo: Joi.object({ name: Joi.string().required(), value: Joi.array().items(Joi.object({ name: Joi.string().required(), value: Joi.string().required(), })).required() }).required(), archesToTreat: Joi.string().valid('UPPER', 'LOWER', 'BOTH').required(), refinementGoals: Joi.array().items(Joi.object({ name: Joi.string().required(), value: Joi.array().items(Joi.object({ position: Joi.array().items(Joi.string().required()).required(), value: Joi.string().required(), name: Joi.string().forbidden() })).when('name', { is: 'Close Residual Space', then: Joi.required(), otherwise: Joi.forbidden() }) })).required(), attachments: Joi.string().required(), iprInfo: Joi.object({ name: Joi.string().required(), value: Joi.array().items(Joi.object({ position: Joi.array().items(Joi.string().required()).required(), value: Joi.string().required() })).required() }).required(), specialNotes: Joi.string().required() })
问题原因
当前的refinementGoals验证规则有两个核心问题:
- 仅允许
name为"Close Residual Space"的项存在value,其他所有name的value都被标记为forbidden,但实际数据中"Resolve posterior Open Bite"也有合法的value字段,因此触发报错。 - 定义的
value结构仅适配"Close Residual Space"的情况,无法匹配"Resolve posterior Open Bite"的value结构(后者的子项包含name和不同格式的value)。
正确的验证方案
需要针对refinementGoals中不同的name值,分别定义对应的value结构规则:
Joi.object({ submissionReason: Joi.string().required(), alignerInfo: Joi.object({ name: Joi.string().required(), value: Joi.array().items(Joi.object({ name: Joi.string().required(), value: Joi.string().required(), })).required() }).required(), archesToTreat: Joi.string().valid('UPPER', 'LOWER', 'BOTH').required(), refinementGoals: Joi.array().items( Joi.object({ name: Joi.string().valid('Alignment', 'Close Residual Space', 'Resolve posterior Open Bite').required() }) // 针对Alignment的规则:禁止value字段 .when('name', { is: 'Alignment', then: Joi.object({ value: Joi.forbidden() }) }) // 针对Close Residual Space的规则:value为固定结构的数组 .when('name', { is: 'Close Residual Space', then: Joi.object({ value: Joi.array().items(Joi.object({ position: Joi.array().items(Joi.string().required()).required(), value: Joi.string().required(), name: Joi.forbidden() })).required() }) }) // 针对Resolve posterior Open Bite的规则:value为另一种结构的数组 .when('name', { is: 'Resolve posterior Open Bite', then: Joi.object({ value: Joi.array().items(Joi.object({ name: Joi.string().required(), value: Joi.alternatives().try( // 匹配teeth Attachment的对象结构 Joi.object({ name: Joi.string().required(), value: Joi.array().items(Joi.string().required()).required() }), // 匹配直接的牙齿数组结构 Joi.array().items(Joi.string().required()) ).required() })).required() }) }) ).required(), attachments: Joi.string().required(), iprInfo: Joi.object({ name: Joi.string().required(), value: Joi.array().items(Joi.object({ position: Joi.array().items(Joi.string().required()).required(), value: Joi.string().required() })).required() }).required(), specialNotes: Joi.string().required() })
关键修改点
- 给
name字段添加valid约束,限定允许的取值范围,避免非法值。 - 对三种不同的
name值分别定义value规则:- "Alignment":禁止
value字段 - "Close Residual Space":保持原有的
position+value结构验证 - "Resolve posterior Open Bite":适配其
value的两种子结构(对象或字符串数组)
- "Alignment":禁止
内容的提问来源于stack exchange,提问作者Dr Doom
相关产品推荐
相关产品推荐

