使用joi来验证数据模型

本文作者:IMWeb zzbozheng 原文出处:IMWeb社区 未经同意,禁止转载

我们用nodejs实现一些功能时,往往需要对用户输入的数据进行验证。然而,验证是一件麻烦的事情,很有可能你需要验证数据类型,长度,特定规则等等,在前端做表单验证时,我们常用的做法是使用正则,正则表达式也许可以一步到位,但是他只会给你true or false,如果想要知道数据不符合哪些条件时,那么你要进一步判断,下面和大家分享一种可读性和易用性更好的实现方法。

Joi 是 hapijs 自带的数据校验模块,他已经高度封装常用的校验功能,本文就是介绍如何优雅地使用 joi 对数据进行校验。相信你会喜欢上他。便于大家理解,以登录为例,一般分两种方式:A或B (输入密码或二维码),那么 joi 的配置如下即可实现检验:

var Joi = require('joi');
var schema = Joi.object({
    username: Joi.string().min(3).max(30).required(),
    isA: Joi.boolean(),
    AVal: Joi.number(),
    isB: Joi.boolean(),
    BVal: Joi.string()
})
.with('isA', 'AVal')
.with('isB', 'BVal')
.without('isA', 'isB')
.or('isA', 'isB');

以上scheme配置大致意思如下:

username: 字符串类型,长度在3至30之间,必填。

isA: 布尔类型,可选

AVal: 数字类型, 可选

isB: 布尔类型, 可选

BVal: 字符串类型, 可选

with('isA', 'AVal') //意思是,isA 和 AVal 这两字段如果填写了isA,也必须要填写AVal

with('isB', 'BVal') //道理同上

without('isA', 'isB'); //意思是 isA 和 isB 只能填写其中一个

or('isA', 'isB') //意思是 isA 和 isB 这两字段至少填写其一

Let's try

var input = {
    username: 'zzbo'
}

var output = Joi.validate(input, schema);
//error: ValidationError: "value" must contain at least one of [isA, isB]

提示至少要填写 isA 或 isB 其中之一

再看:

var input = {
    username: 'zzbo',
    isA: true
}

var output = Joi.validate(input, schema);
//error: ValidationError: "isA" missing required peer "AVal"

提示 AVal 必填

再来:

var input = {
    username: 'zzbo',
    isA: true,
    AVal: 666666
}

var output = Joi.validate(input, schema);
//error: null

成功通过校验

这种极简易读的表达方式让你轻松快速实现校验功能,不需要 if else。这就是配置大于编码的魅力。

不仅于scheme对象

joi 不仅仅作用于scheme对象,而且还可以单独使用,比如:

Joi.string().validate(666666);  //error: ValidationError: "value" must be a string
Joi.string().validate('hehe'); // pass

有时一些意外的字段被传进来,会导致校验不通过,但你又不在乎这些多余的字段,可以这样配置:

Joi.validate({y: 3}, {x: Joi.string()}); // [ValidationError: "y" is not allowed]
Joi.validate({y: 3}, {x: Joi.string()}, {allowUnknown: true}); // pass, 配置 {allowUnknown: true}

除了表单常用的数值,布尔类型等,也可以校验函数类型:

var myObject = {
    a: 123,
    b: function () { }
}

var schema = {
  a: Joi.number().integer(),
  b: Joi.func()
}

Joi.validate(myObject, schema);
//pass

除此之外,还有更多类型Joi.any(), Joi.array(), Joi.boolean(), Joi.date(), Joi.func(), Joi.number(), Joi.object(), Joi.string()

更多玩法

数字 + 特定的字符串:

Joi.number().allow('a').validate('a');  // pass
Joi.number().valid('a').validate('a');   // pass  
Joi.number().valid(['a', 'b']).validate('b');   // pass  
Joi.number().allow('a').validate(3);   // pass

不能是数字5:

Joi.number().invalid(5).validate(5);  // error

允许是任何类型:

Joi.any().validate() // pass

如果需要校验对象的子对象,那么Joi的描述也可以作为了一个子对象:

var Joi = require('joi');

var schemeAB = Joi.object({
  A: Joi.string().required(),
  B: Joi.string().required()
});

var schemeCD = Joi.object({
  C: Joi.string().required(),
  D: schemeAB  //可以作为子对象
});

var output = Joi.validate({
  C: 'hehe',
  D: {
    A: 'haha',
    B: 'hoho'
  }
}, schemeCD);

console.log(output);
//pass

Joi提供的校验条件不够用?也可以使用正则:

Joi.object({
    password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/)
});

在 hapijs 中使用Joi

hapijs 自家的Joi 当然要无缝对接起来

var Hapi = require('hapi');
var Joi = require('Joi');

var server = new Hapi.Server();

server.connection({
    port: 8000
});

server.route({
    method: 'GET',
    path: '/',
    handler: function (request, reply) {
        if (request.query.hour && request.query.minute) {
            reply(request.query.hour + ':' + request.query.minute);
        } else {
            reply('time unknown');
        }
    },
    config: {
        validate: {
            query: {
                hour: Joi.number().min(0).max(23),
                minute: Joi.number().min(0).max(59)
            }
        }
     }
});

server.start(function(err) {
    if (err) throw err;
    console.log('Server running...');
});

就是如此简单的配置就即可完成数据验证,体配置大于 调试一下:

http://127.0.0.1:8000/?hour=2&minute=3 //pass

http://127.0.0.1:8000/?hour=2&minute=300 //error

最后

小伙伴们赶紧动手来尝试一下。

Joi 的更多用法可以参考文档:https://github.com/hapijs/joi/blob/v8.0.5/API.md

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏营旗的小记录

检验controller的入参是否符合我们的规范,@Valid与@Validated

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

7500
来自专栏前端资源

利用正则批量清理Teleport Ultra/Pro冗余代码

Teleport 是一款非常优秀的网站离线浏览工具(即网站整站下载工具),但该软件下载的网页文件里会包含大量冗余代码(如:tppabs),手动去修改工作量很大。

10100
来自专栏Java架构沉思录

我所经历的一次Dubbo服务雪崩,这是一个漫长的故事

这周,笔者经历了一次服务雪崩。服务雪崩,听到这个词就能想到问题的严重性。是的,整个项目,整条业务线都挂了,从该业务线延伸出来的下游业务线也跟着凉了。笔者是连续三...

5600
来自专栏Devops专栏

Flask URL默认转换器、自定义转换器、to_python、to_url

测试访问 http://127.0.0.1:5000/goods_info/123

6100
来自专栏前端资源

【笔记】5.2学习小程序用到的网站和资料

微信小程序页面引入公用头部底部:http://www.mamicode.com/info-detail-2276065.html

9700
来自专栏带你回家

Nginx配置vue项目 报错 Uncaught SyntaxError: Unexpected token

今天部署 VUE发现不能按正常的静态资源文件部署。部署VUE实数没有太多经验,惭愧惭愧。

21100
来自专栏Lambda

IDEA插件介绍(一) - RestfulToolkit(接口自测工具)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

6100
来自专栏SpringBoot 核心技术

Api架构奥义:ApiBoot实现零代码整合Spring Security & OAuth2

接口服务的安全性一直是程序员比较注重的一个问题,成熟的安全框架也比较多,其中一个组合就是Spring Security与OAuth2的整合,在ApiBoot内通...

8000
来自专栏小满

"timestamp":"2019-11-12T02:39:28.949+0000","status":

{"timestamp":"2019-11-12T02:39:28.949+0000","status":415,"error":"Unsupported Me...

20000
来自专栏前端资源

实现网页自动跳到其他页面的几种方法

某些时候我们需要实现网页的自动跳转,比如404错误页可以加入代码让它自动跳转到首页,下面介绍三种html页面自动跳转的方法。

7500

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励