如何为创建、更新请求编写不同规则的Joi校验Schema?
嘿,这个需求在Joi里其实有挺优雅的实现方式,我常用两种方案,给你详细说说:
方案一:基础Schema + 扩展(推荐)
因为POST和PUT请求的对象大部分字段是一致的,只有id的规则不同,所以我们可以先定义一个包含公共字段的基础Schema,再分别扩展出POST和PUT专用的Schema,这样既能复用代码,逻辑也清晰。
代码示例:
// 先定义公共字段的基础Schema const baseItemSchema = Joi.object({ name: Joi.string().required() // 这里假设name是必填项,你可以根据实际需求调整规则 }); // POST请求(创建资源):禁止传入id字段 const postItemSchema = baseItemSchema.keys({ id: Joi.string().forbidden().messages({ 'any.forbidden': '创建新资源时,请勿传入id字段' }) }); // PUT请求(更新资源):必须传入id字段 const putItemSchema = baseItemSchema.keys({ id: Joi.string().required().messages({ 'string.empty': 'id字段不能为空', 'any.required': '更新资源时,必须传入id字段' }) });
使用的时候,在对应的路由里选择对应的Schema就行:比如POST /api/v1/item/用postItemSchema,PUT /api/v1/item/用putItemSchema。
方案二:使用条件校验(.when())
如果你不想维护多个Schema,也可以用Joi的.when()方法,通过上下文参数来判断当前是创建还是更新操作,动态切换id的规则。
代码示例:
// 定义一个带条件的Schema const itemSchema = Joi.object({ name: Joi.string().required(), id: Joi.string().when(Joi.ref('$isUpdate'), { // 当isUpdate为true时(更新操作),id必填 is: true, then: Joi.required().messages({ 'any.required': '更新资源时必须传入id字段' }), // 否则(创建操作),id禁止传入 otherwise: Joi.forbidden().messages({ 'any.forbidden': '创建新资源时请勿传入id字段' }) }) }); // 校验POST请求(创建):传入context标记为非更新 const postResult = itemSchema.validate({ name: "Joe Doe" }, { context: { isUpdate: false } }); // 校验PUT请求(更新):传入context标记为更新 const putResult = itemSchema.validate({ name: "Joe Doe", id: "1234567890" }, { context: { isUpdate: true } });
这种方式适合字段规则差异不大的场景,比较灵活,但如果后续规则变复杂,可能会让单个Schema变得臃肿。
额外小提示
- 如果用的是Express、Koa这类Web框架,可以在路由中间件里根据
req.method自动选择对应的Schema,不用手动切换; - 自定义
messages能让返回的错误信息更友好,前端更容易理解; - 要是
id有格式要求(比如必须是10位数字),可以在Joi.string()后面追加.pattern(/^\d{10}$/)这类规则,进一步校验格式。
内容的提问来源于stack exchange,提问作者atasoyh
相关产品推荐
相关产品推荐

