1.1.9 • Published 5 years ago

js-param-checker v1.1.9

Weekly downloads
2
License
ISC
Repository
-
Last release
5 years ago

参数校验组件

前言

如果我们每个接口的开头都充斥着上十行参数校逻辑验的代码,想必这一定是一份非常不友好的代码。
而本组件的产生,就是为了解决这类问题,使用本组件,可以屏蔽大部分关于参数校验的逻辑,让接口的代码更加专注于处理业务逻辑,同时也能提高代码的可读性。

安装方式

$ npm install js-param-checker

快速上手

为了让读者更快了解本组件,我们举一个简单的例子来说明如何使用本组件

读者可以拷贝代码到本地运行看效果

const paramChecker = require('js-param-checker'); // 引入本组件

const checkInfo = { // 将参数的校验放到一个配置对象里面
    "productName": "require string(0,)", // 必填,且为字符串,字符串长度大于0
    "productPrice": "require int(0,)", // 必填,且为整数,整数大于0
    "productCount": "require uintz", // 必填,且为非负整数
    "productFrom": "require enums(中国,美国,加拿大)" // 必填,且必须是中国、美国、加拿大其中之一
};

const doBusiness = (dataInfo) => { // 假定这个方法用于处理业务逻辑
    // 按照通常情况下,我们可能会在前面这里对每个参数进行校验
    // 使用本组件,我们只需要短短的几行代码,甚至可以把它提取到公共是外部框架中去做处理
    const error = paramChecker.check(dataInfo, checkInfo); 
    //如果校验格式不正确,error为一个错误对象,error.msg为错误文本提示,否则为null
    if(error){
        throw new Error(error.msg);
    }
    console.log('dataInfo check ok !');
    // 业务逻辑
}

const dataInfo = {
    productName: "苹果",
    productPrice: 5000,
    productCount: 1,
    productFrom: "英国" // 这里会通不过,因为不在枚举的三个值中
};

doBusiness(dataInfo); // 这里我们调用该方法执行业务逻辑

上面的例子中,我们把参数校验通过调用 paramChecker.check 来处理,在实际项目中,我们可以把 checkInfo 写成一个配置文件,所有的校验文件统一放到专门的目录下统一管理,甚至连校验那一步都可以进一步封装,即业务方法里面不需要出现任何参数校验的代码,并且参数校验又是可配置的。

功能概览

  • 内置多种常见的格式校验类型
  • 支持必填和非必填
  • 支持校验任何复杂的json对象格式数据
  • 支持用户添加自定义校验格式
  • 支持用户修改默认的校验名称
  • 支持用户重写默认的校验格式
  • 支持对校验的格式进行扩展
  • 支持异步方式校验
  • 支持错误提示参数命名

功能详解

组件内置支持的校验格式如下

string ~字符串(可设置长度)
enums ~枚举
variable ~js变量
letter ~字母
upletter ~大写字母
lowletter ~小写字母
timestamp ~时间戳
time ~时间
date ~日期
datetime ~日期时间
email ~邮件
phone ~手机号码
ip ~IP地址
url ~url链接
postcode ~邮编号码
idcard ~身份证号
notchinese ~非中文
chinese ~中文
bool ~布尔
int ~整数(可设置取值范围)
uint ~正整数(可设置取值范围)
uintz ~自然数(可设置取值范围)
float ~浮点数
ufloat ~正浮点数
array ~数组
uarray ~非空数组
object ~对象
uobject ~非空对象

支持参数的必填和非必填校验

组件通过关键字 requireoptional 来声明参数是否必填,如

{
    "createDate": "require date", //创建时间必填
    "remark": "optional string" //备注可不填
}

上面例子中,createDate参数是必填的,且约定为date格式,如果检验结果为没值或格式不对,就会提示 "createDate必填,且为YYYY-MM-DD的日期格式",而remark参数如果没值则不会有错误提示

组件支持对任意复杂的json格式对象进行校验

有时候我们的参数并不是形如

{
    product: "apple", 
    count: 120
}   

这种简单的对象,而是各种数组和对象嵌套,如

{
    product: {
        name:"apple", 
        sale: {
            byMonth: [20, 10, 11, 12, 20, ...],  //数组每一项表示每个月的销售额
            bySaleman: { //每个销售员的销售额
                lilei: 20,
                lily: 30,
                ...
            }
        },
        ...
    }
}

而本组件就是针对这种场景,可支持对数组内的参数进行校验,甚至可以精确到校验数组的某一项,或者是更深层次的值校验(文章后面会有例子)。

支持用户添加自定义校验格式

有时候用户需要有自己的一些自定义校验规则,本组件支持用户添加自己的校验规则,方式如下:

paramChecker.setting({
    add: {
        myrule: (name, value) => {
            if(typeof value !== 'object'){
                return `${name}不符合自定义校验规则`;
            }else{
                return null;
            }
        }
    }
});

在使用的时候,就可以通过如

{
    "createDate": "require date", // 创建时间必填
    "remark": "optional string", // 备注可不填
    "moreInfo": "require myrule" // 组件会调用上面设置的自定义规则来校验
}

如果我们传入的参数值如下

{
    "createDate": "2019-05-10", 
    "remark": "测试", 
    "moreInfo": "test"
}

那么校验结果会是 "moreInfo不符合自定义校验规则",上面完整的例子如下:

const paramChecker = require('js-param-checker');
paramChecker.setting({
    add: {
        myrule: (name, value) => {
            if(typeof value !== 'object'){
                return `${name}不符合自定义校验规则`;
            }else{
                return null;
            }
        }
    }
});
const error = paramChecker.check(
    {
       "createDate": "2019-05-10", 
       "remark": "测试", 
       "moreInfo": "test"
   }, 
   {
      "createDate": "require date", // 创建时间必填
      "remark": "optional string", // 备注可不填
      "moreInfo": "require myrule" // 组件会调用上面设置的自定义规则来校验
   }
);

console.log(`校验结果:${error?error.msg:'ok'}`); // 校验结果:moreInfo不符合自定义校验规则

上面如果要校验通过,moreInfo需要是一个json对象,如

{
    "createDate": "2019-05-10", 
    "remark": "测试", 
    "moreInfo": {
        "color": "red",
        "price": 100
    }
}

此时会输出 "校验结果:ok"

支持用户修改默认的校验名称

这个功能是为了能让用户可以修改本组件内置的格式名称,比如你可以把内置规则名"date"改名为"DATE","string"改为"str",那么上面的例子中,需要修改如下

paramChecker.setting({ //说明:paramChecker.setting是可以多次调用的,每次调用的结果会叠加
    rename: {
        string: 'str'
    }
});
{
   "createDate": "require date", // 创建时间必填
   "remark": "optional str", // 备注可不填
   "moreInfo": "require myrule" // 组件会调用上面设置的自定义规则来校验
}

支持用户重写默认的校验格式

有时候内置的校验格式并不适应实际的应用场景,比如内置的date的校验格式是YYYY-MM-DD,而实际是需要YYYY/MM/DD的格式,那么可以重写内置的校验格式,方式如下:

paramChecker.setting({
    override: {
        date: (name, value) => {
            const reg = /^(\d{4})\/(\d{2})\/(\d{2})$/;
            const matchs = value.match(reg);
            if(matchs === null || matchs.length === 0){
                return `${name}必须为YYYY/MM/DD格式,当前值:${value}`;;
            }
            return null;

        }
    }
});

支持对校验的格式进行扩展

上面的myrule自定义格式中,如果传入的不是json对象,会提示不符合自定义格式。而如果传入的是对象,则能校验通过。如果希望对这个规则进行扩展,比如校验对象的属性个数,那么可以使用如下方式扩展

paramChecker.setting({
    add: {
        myrule: (name, value, extra) => {//这里多出来的extra参数,就是用于扩展规则校验的,后面会说明如何传入这个参数
            if(typeof value !== 'object'){ //这里有点不严谨,数组也是对象,但是作为例子,大家知道意思就行
                return `${name}不符合自定义校验规则`;
            }else{
                if(Object.keys(value).length !== parseInt(extra)){
                    return `${name}不符合自定义校验规则`;
                }else{
                    return null;
                }
            }
        }
    }
});

接下来我们来约定,moreInfo必须是一个拥有三个属性的对象

const error = paramChecker.check(
    {
       "createDate": "2019-05-10", 
       "remark": "测试", 
       "moreInfo": {
           "color": "red",
           "price": 100
       }
   }, 
   {
      "createDate": "require date", // 创建时间必填
      "remark": "optional string", // 备注可不填
      "moreInfo": "require myrule(3)" // 这里通过在myrule后面加上小括号,小括号里面的值就是传入自定义规则的实现方法的extra参数
   }
);
console.log(error); //这里会打印出一个错误对象 {"msg":"moreInfo不符合自定义校验规则", "param":"moreInfo", "check":"require myrule(3)", "value":{"color":"red","price":100}}

支持异步方式校验

有时候参数是否符合要求需要调用后台接口去判断,比如有时候我们拿到的城市参数在db中是动态变化的,此时就需要异步去db获取这个动态的枚举值,本组件可通过异步的方式来校验参数值。
异步校验同样支持新增校验规则和重写原规则,新增规则的例子如下

const paramChecker = require('js-param-checker');

//fetchData模拟去后台获取城市的枚举值
const fetchData = () => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(['深圳', '广州', '上海'])
        }, 100);
    });
}

paramChecker.setting({
    add: {
        myrule: async (name, value) => { // 这里需要使用到async声明这是一个异步方法
            const data = await fetchData();
            if(data.indexOf(value)>=0){ // 判断value是否属于后台返回的数据中的一个
                return null;
            }else{
                return `${name}不符合自定义校验规则`;
            }
        }
    }
});
//接下来在使用方面也会稍有不同,异步方式需要调用 checkAsync 方法
paramChecker.checkAsync({
       "createDate": "2019-05-10", 
       "remark": "测试", 
       "moreInfo": "北京"
    }, 
    {
       "createDate": "require date", // 创建时间必填
       "remark": "optional string", // 备注可不填
       "moreInfo": "require myrule" // 这里会去后台db拉去数据校验
    }
).then((error) => {
    console.log(`校验结果:${error?error.msg:'ok'}`);
});

支持错误提示参数命名

有时候我们希望给到用户的是中文或者更加通熟易懂的名称,上面的例子中,

"createDate": "require date", // 创建时间必填

如果 createDate 格式错误

"createDate": "20190510", 

那么提示会如下
createDate必须为YYYY-MM-DD格式,当前值:20190510
我们可以设置如下

"createDate 产品创建时间": "require date", // 创建时间必填

那么提示会变成: "产品创建时间必须为YYYY-MM-DD格式,当前值:20190510"
以上这种提示方式是不是就变得更加友好呢? 另外,我们重命名的参数在规则方法中可以通过name参数取到,如

myrule: (name, value) => { // 这里的name就会变成 产品创建时间
    
}

复杂示例

// 下面直接模拟一个比较复杂的场景,假设我们需要校验一个userInfo对象的格式,这个对象嵌套了复杂的数据结构 // 读者可以把以下的例子拷贝到本地测试,修改字段的值,看看校验的提示

const paramChecker = require('js-param-checker');

const userInfo = {
    name: 'zzz',
    age: 18,
    sex: 'male',
    nation: '汉',
    description: '一枚好青年',
    birthday: '2020-01-01',
    contact: [
        13888888888,
        'zhen_zhen_zhang@163.com',
        {
            qq: ['88888', '999999']
        },
        {
            wechat: 'iloveyou'
        }
    ],
    company: {
        name: 'tencent',
        city: '深圳',
        homepage: 'https://www.tencent.com',
        groups: [
            {
                groupName: 'WXG',
                staffCount: 1,
            },
            {
                groupName: 'IEG',
                staffCount: 2,
            },
            {
                groupName: 'CDG',
                staffCount: 3,
            }
        ],
        products: [
            {
                productName: 'qq',
                productInfo: {
                    userCount: 4,
                    publishTime: '2019-01-01'
                },
            },
            {
                productName: 'wechat',
                productInfo: {
                    userCount: 5,
                    publishTime: '2020-01-01'
                },
            }
        ]
    }
};

const checkInfo = {
    "name": "require string(0,)",  // 名称长度必须大于0
    "age": "require uint",  // 年龄必须大于0
    "sex": "require enums(female,male)", // 性别必须为female和male其中之一
    "nation 民族": "require chinese", // 民族必须为汉字
    "description": "require string(0,)", // 个人描述长度必须大于0
    "birthday": "require date", // 生日格式必须为YYYY-MM-DD

    "contact": "require uarray", // 联系方式是个非空数组
    "contact[0]": "require phone", // 联系方式第一项必须为手机号码
    "contact[1]": "require email", // 联系方式第二项必须为邮箱
    "contact[2]": "require uobject", // 联系方式第三项必须为非空objecj对象
    "contact[2].qq": "require array", // 联系方式第三项的属性包含qq,且qq对应的值是数组(数组可为空)
    "contact[2].qq[]": "require string(4,)", // 联系方式qq的位数长度必须大于4
    "contact[3]": "require uobject", // 联系方式第四项必须为非空boject对象
    "contact[3].wechat": "require string(0,)", // 联系方式第四项的属性必须包含wechat,且wechat的长度必须大于0

    "company": "require uobject", // 公司必须是非空的object对象
    "company.name": "require string(0,)", // 公司名称长度必须大于0
    "company.city": "require enums(深圳,广州,北京,上海)", // 公司城市只能是 “深圳,广州,北京,上海” 中的一个
    "company.homepage": 'require url', // 公司主页
    "company.groups": "require uarray", // 公司的事业群是一个非空数组
    "company.groups[]": "require uobject", // 每个事业群是一个非空对象
    "company.groups[].groupName": "require upletter", // 事业群名称必须是大写字母组成
    "company.groups[].staffCount": "require uint", //事业群人数必须是正整数
    "company.products": "require uarray", // 公司生产的产品是一个非空数组
    "company.products[]": "require uobject", // 每个产品是一个非空对象
    "company.products[].productName": "require string(0,)", // 产品名称长度必须大于0
    "company.products[].productInfo": "require uobject", // 产品详情是一个非空对象
    "company.products[].productInfo.userCount": "require uint", // 产品详情的用户数必须是正整数
    "company.products[].productInfo.publishTime": "require date" // 产品详情的发布时间必须是YYYY-MM-DD格式
};

const error = paramChecker.check(userInfo, checkInfo);

console.log(`result: ${error?error.msg:'ok'}`);

其他依赖

1.1.9

5 years ago

1.1.8

5 years ago

1.1.6

5 years ago

1.1.5

5 years ago

1.1.4

5 years ago

1.1.3

5 years ago

1.1.2

5 years ago

1.1.1

5 years ago

1.0.1

5 years ago

1.0.0

5 years ago