Joi是什么?

官方文档描述是:joi lets you describe your data using a simple, intuitive, and readable language.
简单理解就是:可以简单直接描述你的数据模型的语言。
所以重点是描述,然后校验很简单。
官方文档地址:joi.dev/api/?v=17.4…

安装

在项目目录里执行 npm i joi

试用环境

@google-cloud/functions-framework

简单试用

对一个字符串型参数进行校验
代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
vbnet复制代码const Joi = require('joi');
const schema = Joi.object({
username: Joi.string()
.alphanum()
.min(3)
.max(30)
})

exports.helloWorld = (req, res) => {
const { error, value } = schema.validate(req.query)
if (error) {
return res.status(422).json({ error: error })
}
res.send('Hello, World')
}

效果如下:
访问 http://localhost:8080/
返回 Hello, World
访问 http://localhost:8080/?username=aaaa
返回 Hello, World
访问 http://localhost:8080/?username=aa
返回

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
swift复制代码{
"error": {
"_original": {
"username": "aa"
},
"details": [
{
"message": "\"username\" length must be at least 3 characters long",
"path": [
"username"
],
"type": "string.min",
"context": {
"limit": 3,
"value": "aa",
"label": "username",
"key": "username"
}
}
]
}
}

访问 http://localhost:8080/?username=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

返回

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
swift复制代码{
"error": {
"_original": {
"username": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"details": [
{
"message": "\"username\" length must be less than or equal to 30 characters long",
"path": [
"username"
],
"type": "string.max",
"context": {
"limit": 30,
"value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"label": "username",
"key": "username"
}
}
]
}
}

访问 http://localhost:8080/?username=aaaa&password=1234

返回

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
swift复制代码{
"error": {
"_original": {
"username": "aaaa",
"password": "1234"
},
"details": [
{
"message": "\"password\" is not allowed",
"path": [
"password"
],
"type": "object.unknown",
"context": {
"child": "password",
"label": "password",
"value": "1234",
"key": "password"
}
}
]
}
}

对body进行校验

增加必填校验
代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
scss复制代码const Joi = require('joi');
const schema = Joi.object({
username: Joi.string()
.alphanum()
.min(3)
.max(30),
password: Joi.string()
.alphanum()
.min(6)
.max(12)
})

exports.helloWorld = (req, res) => {
const { error, value } = schema.validate(req.body)
if (error) {
return res.status(422).json({ error: error })
}
console.info(value)
res.send(value)
};

用postman访问http://localhost:8080
输入数据:

1
2
3
4
json复制代码{
"username": "postman",
"password": "123456"
}

返回:

1
2
3
4
json复制代码{
"username": "postman",
"password": "123456"
}

输入数据:

1
2
3
4
5
json复制代码{
"username": "postman",
"password": "123456",
"age":30
}

返回:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
swift复制代码{
"error": {
"_original": {
"username": "postman",
"password": "123456",
"age": "30"
},
"details": [
{
"message": "\"age\" is not allowed",
"path": [
"age"
],
"type": "object.unknown",
"context": {
"child": "age",
"label": "age",
"value": "30",
"key": "age"
}
}
]
}
}

输入数据:

1
2
3
4
json复制代码{
"username": "postman",
"password": ""
}

返回:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
css复制代码{
"error": {
"_original": {
"username": "postman",
"password": ""
},
"details": [
{
"message": "\"password\" is not allowed to be empty",
"path": [
"password"
],
"type": "string.empty",
"context": {
"label": "password",
"value": "",
"key": "password"
}
}
]
}
}

校验两个参数是否都输入

和required是有差别的
代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
scss复制代码const Joi = require('joi');
const schema = Joi.object({
username: Joi.string()
.alphanum()
.min(3)
.max(30),
password: Joi.string()
.alphanum()
.min(6)
.max(12),
mobile: Joi.string()
.alphanum()
}).and('username', 'password')

exports.helloWorld = (req, res) => {
const { error, value } = schema.validate(req.query)
if (error) {
return res.status(422).json({ error: error })
}
console.info(value)
res.send(value)
};

输入数据:

1
ini复制代码http://localhost:8080/?username=aaaaaaa&password=123456

返回:

1
2
3
4
json复制代码{
"username": "aaaaaaa",
"password": "123456"
}

输入数据:

1
ini复制代码http://localhost:8080/?username=aaaaaaa&mobile=123456

返回:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
swift复制代码{
"error": {
"_original": {
"username": "aaaaaaa",
"mobile": "123456"
},
"details": [
{
"message": "\"value\" contains [username] without its required peers [password]",
"path": [],
"type": "object.and",
"context": {
"present": [
"username"
],
"presentWithLabels": [
"username"
],
"missing": [
"password"
],
"missingWithLabels": [
"password"
],
"label": "value",
"value": {
"username": "aaaaaaa",
"mobile": "123456"
}
}
}
]
}
}

输入:http://localhost:8080/?mobile=123456
返回:

1
2
3
json复制代码{
"mobile": "123456"
}

二选一及伴随

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
scss复制代码const Joi = require('joi');
const schema = Joi.object({
username: Joi.string()
.alphanum()
.min(3)
.max(30),
password: Joi.string()
.alphanum()
.min(6)
.max(12),
mobile: Joi.string()
.alphanum()
}).xor('username', 'mobile')
.with('username', 'password')
.with('mobile','password')

exports.helloWorld = (req, res) => {
const { error, value } = schema.validate(req.query)
if (error) {
return res.status(422).json({ error: error })
}
console.info(value)
res.send(value)
};

输入:http://localhost:8080/?mobile=123456789&password=654321
输出:

1
2
3
4
json复制代码{
"mobile": "123456789",
"password": "654321"
}

输入:http://localhost:8080/?mobile=123456
输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
swift复制代码{
"error": {
"_original": {
"mobile": "123456"
},
"details": [
{
"message": "\"mobile\" missing required peer \"password\"",
"path": [],
"type": "object.with",
"context": {
"main": "mobile",
"mainWithLabel": "mobile",
"peer": "password",
"peerWithLabel": "password",
"label": "value",
"value": {
"mobile": "123456"
}
}
}
]
}
}

输入:http://localhost:8080/?username=abcdfe&password=654321
输出:

1
2
3
4
json复制代码{
"username": "abcdfe",
"password": "654321"
}

输入:http://localhost:8080/?username=abcdfe&password=654321&mobile=13999999999
输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
swift复制代码{
"error": {
"_original": {
"username": "abcdfe",
"password": "654321",
"mobile": "13999999999"
},
"details": [
{
"message": "\"value\" contains a conflict between exclusive peers [username, mobile]",
"path": [],
"type": "object.xor",
"context": {
"peers": [
"username",
"mobile"
],
"peersWithLabels": [
"username",
"mobile"
],
"present": [
"username",
"mobile"
],
"presentWithLabels": [
"username",
"mobile"
],
"label": "value",
"value": {
"username": "abcdfe",
"password": "654321",
"mobile": "13999999999"
}
}
}
]
}
}

其他常用功能

直接验证某个变量或者值:Joi.attempt(‘x’, Joi.number());
允许对象里含有未定义的key:Joi.object({ a: Joi.any() }).unknown();
定义参数不能同时出现:

1
2
3
4
css复制代码const schema = Joi.object({
a: Joi.any(),
b: Joi.any()
}).nand('a', 'b');

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%