ZetCode

Joi 教程

最后修改于 2023 年 10 月 18 日

在本文中,我们将展示如何使用 Hapi Joi 模块在 JavaScript 中验证值。

Hapi Joi

Hapi Joi 是一种 JavaScript 对象的对象模式描述语言和验证器。

使用 Hapi Joi,我们为 JavaScript 对象(存储信息的对象)创建蓝图或模式,以确保关键信息的验证。

Hapi 是一个易于使用的以配置为中心的框架,内置了对输入验证、缓存、身份验证以及构建 Web 和服务应用程序的其他基本功能的支持。

Hapi Joi 安装

首先,我们安装该库。

$ node -v
v11.5.0

我们使用 Node 版本 11.5.0。

$ npm init -y
$ npm i @hapi/js

我们使用 nmp i @hapi/joi 启动项目并安装 Hapi Joi。

Joi 验证

验证使用 validate 函数执行

validate(value, schema, [options], [callback])

value 是正在验证的值,而 schema 是验证模式。

options 是验证选项。 abortEarly 选项在第一个错误时停止验证,否则返回找到的所有错误。 默认为 true。 convert 选项尝试将值转换为所需的类型。 默认情况下,它也为 true。

callback 是可选的同步回调方法,使用签名 function(err, value)。 如果验证失败,则 err 包含错误原因,否则为 nullvalue 是应用了任何类型转换和其他修饰符的值。

Joi 版本

在第一个示例中,我们打印 Hapi Joi 的版本。

version.js
const Joi = require('@hapi/joi');

console.log(Joi.version)

Joi 的版本存储在 Joi.version 中。

const Joi = require('@hapi/joi');

我们包含 Hapi Joi 模块。

$ node version.js
15.0.3

Joi 同步函数

在下面的示例中,我们在同步函数内执行验证。

sync_fun.js
const Joi = require('@hapi/joi');

const schema = Joi.object().keys({

    username: Joi.string().required(),
    email: Joi.string().email().required()
});

let username = 'Roger Brown';
let email = 'roger@example';

let data = { username, email };

Joi.validate(data, schema, (err, value) => {

    if (err) {

        console.log(err.details);

    } else {

        console.log(value);
    }
});

我们有两个值需要验证:用户名和电子邮件。

const schema = Joi.object().keys({

    username: Joi.string().required(),
    email: Joi.string().email().required()
});

这是验证模式。 用户名必须是字符串并且是必需的。 电子邮件必须是有效的电子邮件地址,并且也是必需的。

let username = 'Roger Brown';
let email = 'roger@example';

let data = { username, email };

这是要验证的数据。

Joi.validate(data, schema, (err, value) => {

    if (err) {

        console.log(err.details);

    } else {

        console.log(value);
    }
});

Joi.validate 使用提供的模式验证数据。

$ node sync_fun.js
[ { message: '"email" must be a valid email',
    path: [ 'email' ],
    type: 'string.email',
    context: { value: 'roger@example', key: 'email', label: 'email' } } ]

Joi 返回值

在下一个示例中,我们不使用同步函数;我们使用返回值。

ret_vals.js
const Joi = require('@hapi/joi');

const schema = Joi.object().keys({

    username: Joi.string().required(),
    born: Joi.date().required()
});

let username = 'Roger Brown';
let born = '1988-12-11';

let data = { username, born };

const { err, value } = Joi.validate(data, schema);

if (err) {
    console.log(err.details);
} else {
    console.log(value);
}

该示例验证两个值:用户名和出生日期。

const { err, value } = Joi.validate(data, schema);

使用 validate 的另一种方法是获取其返回值。

if (err) {
    console.log(err.details);
} else {
    console.log(value);
}

基于返回值,我们打印错误详细信息或原始值。

$ node ret_vals.js
{ username: 'Roger Brown', born: 1988-12-11T00:00:00.000Z }

我们没有错误,因此打印了验证后的值。

Joi abortEarly

默认情况下,Joi 在第一个错误时停止验证。 如果我们想获取所有错误,我们必须将 abortEarly 选项设置为 true

abort_early.js
const Joi = require('@hapi/joi');

const schema = Joi.object().keys({

    username: Joi.string().min(2).max(30).required(),
    password: Joi.string().regex(/^[\w]{8,30}$/),
    registered: Joi.number().integer().min(2012).max(2019),
    married: Joi.boolean().required()
});

let username = 'Roger Brown';
let password = 's#cret12';
let registered = '2011';
let married = false;

let data = { username, password, registered, married };
let options = { abortEarly: false };

const { error, value } = Joi.validate(data, schema, options);

if (error) {
    console.log(error.details);
} else {
    console.log(value);
}

在示例中,我们打印了发生的所有错误。

const schema = Joi.object().keys({

    username: Joi.string().min(2).max(30).required(),
    password: Joi.string().regex(/^[\w]{8,30}$/),
    registered: Joi.number().integer().min(2012).max(2019),
    married: Joi.boolean().required()
});

我们有四个值需要验证。

let options = { abortEarly: false };

const { error, value } = Joi.validate(data, schema, options);

我们将 abortEarly 选项设置为 false

$ node abort_early.js
[ { message:
        '"password" with value "s#cret12" fails to match the required pattern: /^[\\w]{8,30}$/',
    path: [ 'password' ],
    type: 'string.regex.base',
    context:
        { name: undefined,
        pattern: /^[\w]{8,30}$/,
        value: 's#cret12',
        key: 'password',
        label: 'password' } },
    { message: '"registered" must be larger than or equal to 2012',
    path: [ 'registered' ],
    type: 'number.min',
    context:
        { limit: 2012,
        value: 2011,
        key: 'registered',
        label: 'registered' } } ]

我们有两个验证错误。

Joi 转换值

Joi 默认转换值;要禁用转换,我们将 convert 选项设置为 false

casting.js
const Joi = require('@hapi/joi');

const schema = Joi.object().keys({

    timestamp: Joi.date().timestamp(),
    val: Joi.number()
});

let val = '23543';
let timestamp = 1559761841;

let data = { val, timestamp };

const { error, value } = Joi.validate(data, schema);

if (error) {
    console.log(error.details);
} else {
    console.log(value);
}

在示例中,我们有两个值被 Joi 自动转换。

let val = '23543';
let timestamp = 1559761841;

字符串被转换为数字,时间戳被转换为 ISO 字符串。

$ node casting.js
{ val: 23543, timestamp: 1970-01-19T01:16:01.841Z }

Joi 验证数字

使用 Joi.number 我们可以验证数字。

numbers.js
const Joi = require('@hapi/joi');

const schema = Joi.object().keys({

    age: Joi.number().min(18).max(129),
    price: Joi.number().positive(),
    experience: Joi.number().greater(5)
});

let age = 35;
let price = -124.3;
let experience = 6;

let data = { age, price, experience };

const { error, value } = Joi.validate(data, schema);

if (error) {
    console.log(error.details);
} else {
    console.log(value);
}

在示例中,我们验证了三个数字。

const schema = Joi.object().keys({

    age: Joi.number().min(18).max(129),
    price: Joi.number().positive(),
    experience: Joi.number().greater(5)
});

age 值必须是 18-129 之间的数字。price 必须为正数,experience 必须大于 5。

$ node numbers.js
[ { message: '"price" must be a positive number',
    path: [ 'price' ],
    type: 'number.positive',
    context: { value: -124.3, key: 'price', label: 'price' } } ]

由于价格为负数,我们得到了这些错误详细信息。

Joi 验证日期

使用 Joi.date,我们可以验证日期。

dates.js
const Joi = require('@hapi/joi');

const schema = Joi.object().keys({

    timestamp: Joi.date().timestamp(),
    isodate: Joi.date().iso(),
    registered: Joi.date().greater('2018-01-01')
});

let timestamp = 1559761841;
let isodate = '1970-01-19T01:16:01.841Z';
let registered = '2019-02-12';

let data = { timestamp, isodate, registered };

const { error, value } = Joi.validate(data, schema);

if (error) {
    console.log(error.details);
} else {
    console.log(value);
}

该示例验证了三个日期值。

const schema = Joi.object().keys({

    timestamp: Joi.date().timestamp(),
    isodate: Joi.date().iso(),
    registered: Joi.date().greater('2018-01-01')
});

在模式中,我们有规则来验证一个值是否为时间戳,具有 ISO 格式,并且大于指定值。

$ node dates.js
{ timestamp: 1970-01-19T01:16:01.841Z,
    isodate: 1970-01-19T01:16:01.841Z,
    registered: 2019-02-12T00:00:00.000Z }

所有值都已成功验证。 请注意,这些值已自动转换为 ISO 格式。

Joi 验证数组

可以使用 array 验证数组。

arrays.js
const Joi = require('@hapi/joi');

const schema = Joi.array().min(2).max(10);

let data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ];

const { error, value } = Joi.validate(data, schema);

if (error) {
    console.log(error.details);
} else {
    console.log(value);
}

在示例中,我们验证了一个整数数组。

const schema = Joi.array().min(2).max(10);

我们验证我们的数组至少有两个元素,最多十个元素。

$ node arrays.js
[ { message: '"value" must contain less than or equal to 10 items',
    path: [],
    type: 'array.max',
    context:
        { limit: 10, value: [Array], key: undefined, label: 'value' } } ]

Joi 验证函数

可以使用 func 验证函数。

functions.js
const Joi = require('@hapi/joi');

const schema = Joi.func().arity(2);

function add2int(x, y) {

    return x + y;
}

const { error, value } = Joi.validate(add2int, schema);

if (error) {
    console.log(error.details);
} else {
    console.log(value);
}

在示例中,我们验证一个函数。

const schema = Joi.func().arity(2);

我们验证函数的元数(参数的数量)。

来源

Hapi Joi 文档

在本文中,我们使用 Hapi Joi 模块在 JavaScript 中进行了验证。

作者

我的名字是 Jan Bodnar,我是一位充满激情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直在撰写编程文章。 迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

查看 所有 JavaScript 教程。