# Joi 教程

> 原文： [http://zetcode.com/javascript/hapijoi/](http://zetcode.com/javascript/hapijoi/)

Joi 教程展示了如何使用 Hapi Joi 模块验证 JavaScript 中的值。

## Joi

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

使用 Hapi Joi，我们可以为 JavaScript 对象（存储信息的对象）创建蓝图或架构，以确保验证关键信息。

Hapi 是一个易于使用的以配置为中心的框架，具有对输入验证，缓存，认证以及用于构建 Web 和服务应用的其他基本函数的内置支持。

## Joi 安装

首先，我们安装库。

```js
$ node -v
v11.5.0

```

我们使用 Node 版本 11.5.0。

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

```

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

## Joi 验证

验证通过`validate()`函数执行：

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

```

`value`是要验证的值，`schema`是验证模式。

`options`是验证选项。 在`abortEarly`选项停在第一个错误的验证，否则返回发现的所有错误。 默认为`true`。 `convert`选项尝试将值转换为所需的类型。 它也默认为`true`。

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

## Joi 版本

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

`version.js`

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

console.log(Joi.version)

```

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

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

```

我们包括 Hapi Joi 模块。

```js
$ node version.js
15.0.3

```

这是一个示例输出。

## Joi 同步函数

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

`sync_fun.js`

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

```

我们有两个值可以验证：用户名和电子邮件。

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

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

```

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

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

let data = { username, email };

```

这是要验证的数据。

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

    if (err) {

        console.log(err.details);

    } else {

        console.log(value);
    }
});

```

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

```js
$ 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`

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

```

该示例验证两个值：用户名和生日。

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

```

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

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

```

根据返回的值，我们将打印错误详细信息或原始值。

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

```

我们没有错误，因此会打印验证值。

## Joi `abortEarly`

默认情况下，Joi 会在第一个错误时停止验证。 如果要获取所有错误，则必须将`abortEarly`选项设置为`true`。

`abort_early.js`

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

```

在示例中，我们将打印所有已发生的错误。

```js
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()
});

```

我们有四个值可以验证。

```js
let options = { abortEarly: false };

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

```

我们将`abortEarly`选项设置为`false`。

```js
$ 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 `convert`

Joi 默认情况下强制转换值； 要禁用投射，我们将`convert`选项设置为`false`。

`casting.js`

```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 自动转换的值。

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

```

该字符串将强制转换为数字，而时间戳则转换为 ISO 字符串。

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

```

这是输出。

## Joi 验证数字

使用`Joi.number()`，我们可以验证数字。

`numbers.js`

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

```

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

```js
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`必须大于五。

```js
$ 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`

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

```

该示例验证三个日期值。

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

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

```

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

```js
$ 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`

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

```

在示例中，我们验证了整数数组。

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

```

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

```js
$ 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`

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

```

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

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

```

我们验证函数的参数（参数数量）。

在本教程中，我们已经使用 Hapi Joi 模块在 JavaScript 中进行了验证。

列出所有 [JavaScript 教程](/all/#js)。