在编写api的时候通常都需要对参数进行校验,包括:
Joi 是 hapijs 自带的数据校验模块,它已经高度封装常用的校验功能。
//安装
npm install joi --save
//引用
import Joi from 'joi'
使用joi进行校验,首先要定义它的校验规则,也叫schema。
const schema = Joi.string()
上面就定义了一个校验字符串类型的规则,这个schema会有一个 validate方法,传入需要校验的值:
validate方法会返回一个对象,如果验证通过,就只会返回value属性,如果验证错误,就还有一个error对象,其中error对象的message描述了失败原因:
const schema = Joi.string()
const result = schema.validate(1)
console.log(result)
// result:
{
value: 1,
error: [Error [ValidationError]: "value" must be a string] {
_original: 1,
details: [ [Object] ]
}
}
因此,在此次介绍中,我将验证结果进行了封装,且下文将延续使用
/**
* joi数据校验
* @param schema joi校验schema
* @param data 需要验证的数据
*/
function joiVerification(schema, data) {
const {error, value} = schema.validate(data);
if (error) throw new Error(JSON.stringify({code: 4003, message: `入参信息有误: ${error.message}`}));
return value;
}
检验字符串类型
let stringSchema = Joi.string();
joiVerification(stringSchema, 1);
检验数字类型
let Schema = Joi.number();
joiVerification(Schema, 1);
检验数组类型
let Schema = Joi.array();
joiVerification(Schema, []);
检验布尔类型
let Schema = Joi.boolean();
joiVerification(Schema, true);
检验对象类型
let Schema = Joi.object();
joiVerification(Schema, {});
检验时间类型
let Schema = Joi.date();
joiVerification(Schema, new Date("2022-01-01"));
必选属性,如果需要此校验字段,需要将这个校验规则放到最后面。
let Schema = Joi.object({
name:Joi.string().required()
});
joiVerification(Schema, {name:"long"});
正则校验
let Schema =Joi.string().pattern(/\d/ig);
可选字段,默认所有的字段都是可选的,
但是这个校验允许值为undefined但是不允许为null;
可以于.allow()一起使用
let info = {
name:"long",
age:null,
sex:null
};
let Schema = Joi.object({
name: Joi.string().required(),
age: Joi.string().optional(),
sex: Joi.string().optional().allow(null),
});
joiVerification(Schema, info);
//输出:"入参信息有误: \"sex\" must be a string"
let info = {
name:"long",
age:undefined,
sex:null
};
let Schema = Joi.object({
name: Joi.string().required(),
age: Joi.string().optional(),
sex: Joi.string().optional().allow(null),
});
joiVerification(Schema, info);
//输出:成功通过校验
在校验条件外允许某些值通过
let Schema = Joi.object({
sex: Joi.string().optional().allow(null,"1234"),
});
joiVerification(Schema, info);
不允许以下值存在
let info = {
sex:"100"
};
let Schema = Joi.object({
sex: Joi.string().invalid("100").required(),
});
joiVerification(Schema, info);
//输出:"入参信息有误: \"sex\" contains an invalid value"
any.allow()与、any.invalid()和一起使用的特殊值,any.valid()作为重置任何先前设置的值的第一个值。
个人认为,这个校验并没什么用;
Joi.valid(1).valid(Joi.override, 2);
// Same as:
Joi.valid(2);
// Whereas:
Joi.valid(1).valid(2);
// Is the same as:
Joi.valid(1, 2);
默认值
let Schema = Joi.object({
sex: Joi.string().optional().default("1").allow(null,"1234"),
});
joiVerification(Schema, info);
//下面是官方的函数例子,
const generateUsername = (parent, helpers) => {
return parent.firstname.toLowerCase() + '-' + parent.lastname.toLowerCase();
};
generateUsername.description = 'generated username';
const schema = Joi.object({
username: Joi.string().default(generateUsername),
firstname: Joi.string(),
lastname: Joi.string(),
created: Joi.date().default(Date.now),
status: Joi.string().default('registered')
});
允许的枚举值
let info = {
sex:"1"
};
let Schema = Joi.object({
sex: Joi.string().valid("0","1").required(),
});
joiVerification(Schema, info);
//同样效果,逻辑相同,不要问为什么不能传array了,运算符...了解一下
let info = {
sex:"1"
};
let sexEnum = ["0","1"];
let Schema = Joi.object({
sex: Joi.string().valid(...sexEnum).required(),
});
joiVerification(Schema, info);
官方解释:添加在验证期间评估的条件并在将架构应用于值之前对其进行修改
其实就是:相当于条件判断
一般情况,options包含is、then、otherwise即可,甚至,otherwise都可以不要
//如果email存在时,判断email是否符合邮箱格式,符合,则判断name字段必填,都则,name属性可以选填
let info = {
email: "test@163.com",
name:"long"
};
let Schema = Joi.object({
email: Joi.string(),
name: Joi.string().when("email",{is:Joi.string().email(),then:Joi.string().required()})
});
joiVerification(Schema, info);
指定数组中的最小项目数、数字最小值、字符串最小长度
let info = {
email: "test@163.com",
age:16,
address:["郑州","衢州","广州"]
};
let Schema = Joi.object({
email: Joi.string().min(1),
age: Joi.number().min(15),
address:Joi.number().min(2)
});
joiVerification(Schema, info);
指定数组中的最大项目数、数字最大值、字符串最大长度
let info = {
email: "test@163.com",
age:16,
address:["郑州","衢州","广州"]
};
let Schema = Joi.object({
email: Joi.string().min(1).max(18),
age: Joi.number().min(15).max(100),
address:Joi.number().min(2).max(15)
});
joiVerification(Schema, info);
指定所需的确切字符串长度
let info = {
mobile: "13027711111"
};
let Schema = Joi.object({
mobile: Joi.string().length(11)
});
joiVerification(Schema, info);
要求字符串值是有效的电子邮件地址,一般options不用传入任何信息
let info = {
email: "test@163.com"
};
let Schema = Joi.object({
email: Joi.string().email()
});
joiVerification(Schema, info);
校验uri是否符合规范
let info = {
callbackUri: "https://www.baidu.com"
};
let Schema = Joi.object({
callbackUri: Joi.string().uri({scheme:["https"]})
});
joiVerification(Schema, info);
指定是否string.max()应将限制用作截断
let info = {
name: "long1234"
};
let Schema = Joi.object({
name: Joi.string().max(4).truncate()
});
let value = joiVerification(Schema, info);
console.log(value);
//输出:long