手记

#试用# #nodejs# Joi库进行入参校验

Joi是什么?

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

安装

在项目目录里执行 npm i joi

试用环境

@google-cloud/functions-framework

简单试用

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

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
返回

{
    "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"
                }
            }
        ]
    }
}
{
    "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"
                }
            }
        ]
    }
}
{
    "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进行校验

增加必填校验
代码:

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
输入数据:

{
    "username": "postman",
    "password": "123456"
}

返回:

{
    "username": "postman",
    "password": "123456"
}

输入数据:

{
    "username": "postman",
    "password": "123456",
		"age":30
}

返回:

{
    "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"
                }
            }
        ]
    }
}

输入数据:

{
    "username": "postman",
    "password": ""
}

返回:

{
    "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是有差别的
代码:

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

输入数据:

http://localhost:8080/?username=aaaaaaa&password=123456

返回:

{
    "username": "aaaaaaa",
    "password": "123456"
}

输入数据:

http://localhost:8080/?username=aaaaaaa&mobile=123456

返回:

{
    "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"
                    }
                }
            }
        ]
    }
}
{
    "mobile": "123456"
}

二选一及伴随

代码

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)
};
{
    "mobile": "123456789",
    "password": "654321"
}
{
    "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"
                    }
                }
            }
        ]
    }
}
{
    "username": "abcdfe",
    "password": "654321"
}
{
    "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();
定义参数不能同时出现:

const schema = Joi.object({
    a: Joi.any(),
    b: Joi.any()
}).nand('a', 'b');
1人推荐
随时随地看视频
慕课网APP