当前位置: 首页 > 工具软件 > Joi > 使用案例 >

Joi数据验证

斜单鹗
2023-12-01

在编写api的时候通常都需要对参数进行校验,包括:

  • 参数的类型、必填等;
  • 字符串,是否可以为空、该符合什么规则等;
  • 数字,最大值最小值是什么等等等等。

Joi 是 hapijs 自带的数据校验模块,它已经高度封装常用的校验功能。

1.安装及使用:

//安装
npm install joi --save

//引用
import Joi from 'joi'

2.基础使用

使用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;
}

3.schema基本校验方法

3.1 数据类型校验

.string()

检验字符串类型


    let stringSchema = Joi.string();
    joiVerification(stringSchema, 1);

.number()

检验数字类型

let Schema = Joi.number();
    joiVerification(Schema, 1);

.array()

检验数组类型

    let Schema = Joi.array();
    joiVerification(Schema, []);

.boolean()

检验布尔类型

    let Schema = Joi.boolean();
    joiVerification(Schema, true);

.object()

检验对象类型

    let Schema = Joi.object();
    joiVerification(Schema, {});

.date()

检验时间类型

    let Schema = Joi.date();
    joiVerification(Schema, new Date("2022-01-01"));

3.2 常用schema校验

.required()

必选属性,如果需要此校验字段,需要将这个校验规则放到最后面。

    let Schema = Joi.object({
        name:Joi.string().required()
    });
    joiVerification(Schema, {name:"long"});

.pattern()

正则校验

let Schema =Joi.string().pattern(/\d/ig);

.optional()

可选字段,默认所有的字段都是可选的,
但是这个校验允许值为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);
//输出:成功通过校验

.allow(…values)

在校验条件外允许某些值通过

  • …values:一个或多个值
    let Schema = Joi.object({
      sex: Joi.string().optional().allow(null,"1234"),
    });
    joiVerification(Schema, info);

.invalid(…values)/别名:disallow,not

不允许以下值存在

  • values:可以是任何类型的禁止值,在应用任何其他规则之前将与验证值匹配.
  • 如果第一个值为Joi.override, 将覆盖任何先前设置的值.
    let info = {
      sex:"100"
    };
    let Schema = Joi.object({
      sex: Joi.string().invalid("100").required(),
    });
    joiVerification(Schema, info);

//输出:"入参信息有误: \"sex\" contains an invalid value"

.override()

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);

.default([value])

默认值

  • 【value】:只允许有一个值,但是取值允许为
    • 字符串、数字、对象等
    • 使用签名返回默认值的函数,function(parent, helpers)其中:
      • parent- 包含正在验证的值的对象的克隆。请注意,由于指定parent参数会执行克隆,因此如果您不使用格式参数,请不要声明它们。
      • helpers- 与 中描述的相同any.custom()
    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')
});

.valid(…values)/别名:equal

允许的枚举值

   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);

.when([condition],options)

官方解释:添加在验证期间评估的条件并在将架构应用于值之前对其进行修改
其实就是:相当于条件判断

  • condition:属性名称
  • options:对象属性,判断条件及处理方案
    • is- 表示为joi模式的条件。任何不是joi模式的东西都将使用Joi.compile进行转换。默认情况下,is条件架构允许undefined值。用于.required()覆盖。例如,用于is: Joi.number().required()保证joi引用存在并且是一个数字。
    • not- 的否定版本is(then并且otherwise具有相反的角色)。
    • then- 如果条件为真,则要使用的joi模式。
    • otherwise- 如果条件为假,则使用joi模式。
    • switch-{ is, then }根据condition. 数组中的最后一项也可能包含otherwise.
    • break- 如果规则导致匹配then,otherwise则停止处理所有其他条件。switch

一般情况,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);

3.3 joi封装的实用校验规则

.min(limit)

指定数组中的最小项目数、数字最小值、字符串最小长度

  • limit- 允许的最小数组项数或引用。
    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);

.max(limit)

指定数组中的最大项目数、数字最大值、字符串最大长度

  • limit- 允许的最小数组项数或引用。
    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);

.length(limit,[encoding])

指定所需的确切字符串长度

  • limit- 所需的字符串长度或参考。
  • encoding- 如果指定,则使用提供的编码以字节为单位计算字符串长度。
    let info = {
      mobile: "13027711111"
    };
    let Schema = Joi.object({
      mobile: Joi.string().length(11)
    });
    joiVerification(Schema, info);

.email([oprions])

要求字符串值是有效的电子邮件地址,一般options不用传入任何信息

  • options- 可选设置:
    • allowFullyQualified- 如果,允许以字符true结尾的域。.默认为false.
    • allowUnicode- 如果true,则允许使用 Unicode 字符。默认为true.
    • ignoreLength- 如果true,忽略无效的电子邮件长度错误。默认为false.
    • minDomainSegments- 域所需的段数。默认设置不包括单个分段域,例如example@io哪个是有效的电子邮件但非常不常见。默认为2.
    • maxDomainSegments- 允许的域段的最大数量。默认为无限制。
    • multiple- 如果true, 允许在单个字符串中使用多个电子邮件地址,由, 或separator字符分隔。默认为false.
    • separator- 当multipleis时true,覆盖默认,分隔符。字符串可以是单个字符或多个分隔符。默认为’,'.
    • tlds- TLD(顶级域)验证选项。默认情况下,TLD 必须是IANA 注册表中列出的有效名称。要禁用验证,请设置tlds为false。要自定义 TLD 的验证方式,请设置以下选项之一:
      • allow- 之一:
        • true使用已注册 TLD 的 IANA 列表。这是默认值。
        • false允许deny列表中未列出的任何 TLD(如果存在)。
        • 允许的 TLD的一个Set或数组。不能与 一起使用deny。
      • deny- 之一:
        • 一个Set或一组被禁止的 TLD。不能与自定义allow 列表一起使用。
    let info = {
      email: "test@163.com"
    };
    let Schema = Joi.object({
      email: Joi.string().email()
    });
    joiVerification(Schema, info);

.uri([options])

校验uri是否符合规范

  • options- 可选设置:
    • scheme- 指定一个或多个可接受的方案,应该只包括方案名称。可以是数组或字符串(字符串会自动转义以在正则表达式中使用)。
    • allowRelative- 允许相对 URI。默认为false.
    • relativeOnly- 仅限制相对 URI。默认为false.
    • allowQuerySquareBrackets- 允许在查询字符串中使用未编码的方括号。这符合 RFC 3986 标准,但现在查询字符串abc[]=123&abc[]=456非常普遍。默认为false.
    • domain- 使用中指定的选项验证域组件string.domain()
    let info = {
      callbackUri: "https://www.baidu.com"
    };
    let Schema = Joi.object({
      callbackUri: Joi.string().uri({scheme:["https"]})
    });
    joiVerification(Schema, info);

truncate([enabled])

指定是否string.max()应将限制用作截断

  • enabled- 可选参数默认true允许您通过提供虚假值来重置截断的行为。
    let info = {
      name: "long1234"
    };
    let Schema = Joi.object({
      name: Joi.string().max(4).truncate()
    });
    let value =  joiVerification(Schema, info);
    console.log(value);

//输出:long

官方文档

https://joi.dev/api/?v=17.6.0#introduction

 类似资料: