node最佳实践13-joi数据验证

402 阅读2分钟

接口传参的时候都需要对数据格式进行验证,在node中有express-valdiate和joi等工具可以使用,这里介绍的是joi

安装 npm install joi

使用

const Joi = require('joi')
module.exports = {
  async register(req,res,next){
    const schema =Joi.object({
      page: Joi.number().required(),
      pageSize: Joi.number().required()
    }) 
    const {error} = schema.validate(req.query)
    console.log(error)
    if(error){
      res.status(400).send({error: error.details[0].message})
    }else{
      next()
    }
  }
}

定义了一个schema对象,page和pageSize是schema内部的值,用于验证参数类型,joi.object.validate()方法验证参数,返回一个对象{value,error}

value:验证通过后返回的原参数值

error:验证失败后返回错误信息

// error的例子
[Error [ValidationError]: "date" must be in iso format] {
  _original: { page: '1', pageSize: '10', date: '2022-01-11120:00:00' },
  details: [
    {
      message: '"date" must be in iso format',
      path: [Array],
      type: 'string.isoDate',
      context: [Object]
    }
  ]
}

常用的验证

var Joi = require('joi');
var schema = Joi.object({
    username: Joi.string().min(3).max(30).required(),
    isA: Joi.boolean(),
    AVal: Joi.number(),
    isB: Joi.boolean(),
    BVal: Joi.string(),
    gender: Joi.string().valid('male','female'),// 只能输入male或者female
    date: joi.string().isoDate() // 支持格式2021-12-22或者2021-12-22 02:00或者2018-11-28T18:25:32+00:00
})
.with('isA', 'AVal')
.with('isB', 'BVal')
.without('isA', 'isB')
.or('isA', 'isB');

以上scheme配置大致意思如下:

  • username: 字符串类型,长度在3至30之间,必填。
  • isA: 布尔类型,可选
  • AVal: 数字类型, 可选
  • isB: 布尔类型, 可选
  • BVal: 字符串类型, 可选
  • with('isA', 'AVal') //意思是,isA 和 AVal 这两字段如果填写了isA,也必须要填写AVal
  • with('isB', 'BVal') //道理同上
  • without('isA', 'isB'); //意思是 isA 和 isB 只能填写其中一个
  • or('isA', 'isB') //意思是 isA 和 isB 这两字段至少填写其一
  • gender:只能输入male或者female
  • date:只支持日期格式

在项目中可以把数据验证写成一个中间件进行使用,例如 :

routes/book.route.js

import { bookIndexValidator } from '../validator/book.validtor.js'
router.get('/',bookIndexValidator,getRecordsByPage)

在访问项目localhost:3000/books/地址的时候就会跑bookIndexValidator进行入参验证,具体的写法:

新建一个src/validators文件夹,新增book.validator.js

// 项目支持es6的话,写成下面这样,否则按普通写法即可
import joi from 'joi'
import { Result } from '../libs/result'

export const bookIndexValidator = (req,res,next) => {
  console.log('query===',req.query)
  const schema = joi.object({
    page: joi.number().integer().required(),
    pageSize: joi.number().integer().required(),
  }) 
  const {error} = schema.validate(req.query)
  if(error){
    console.log(error)
    res.status(400).json(Result.validateFailed(error.details[0].message))
  }else{
    next()
  }
}

joi.dev/api/?v=17.9…