对于任何 api 来讲,输入参数的校验,是很是重要的一个步骤;不少框架和工具也都提供了输入参数验证功能;今天,咱们来学习其中一种,并尝试从零开始,建立一个
Javascript
版本的Laravel
风格参数验证器。javascript
Laravel
Laravel 是一个基于 PHP 实现的 web 框架,它提供了api参数验证功能,其中对于验证规则的组织很简洁:php
public function store(Request $request) {
$validatedData = $request->validate([
'title' => 'required|max:255',
'body' => 'required',
]);
// ...
}
复制代码
经过上面的 php
代码咱们看到,对于参数 title
,有两个验证规则,它们分别是:前端
required
这表明 title
参数必传,若是没有传递 title
参数,或 title
参数的值为:null
、空字符串、空数组、空对象,则验证不会经过。max:255
这表明参数做为字符串、数字或数组,上限必须小于或等于255
(对于字符串和数组来讲,则断定其 length
的值)以上验证规则,使用符号 |
分割,看起来很紧凑。java
咱们参照上面的这些内容,设计一个 JavaScript
版本的验证器。laravel
首先,咱们列出对于验证器的需求:git
输入参数列表
和 针对每一个输入参数的验证规则定义列表
required
、max
、min
中文
和 英文
, 默认返回 中文
错误信息验证规则详情:github
required
,参数值为:null、undefined、NaN、空字符串、空数组、空对象,则验证不经过max
,参数值类型若是是:数字,则值不能大于(能够等于) max:
后面指定的值;参数值类型若是是:字符串、数组,则长度不能大于(能够等于)max:
后面指定的值min
,参数值类型若是是:数字,则值不能小于(能够等于) min:
后面指定的值;参数值类型若是是:字符串、数组,则长度不能小于(能够等于)min:
后面指定的值接下来,咱们建立工程,并根据需求,设计好工程文件目录结构:web
mkdir validator && cd validator && yarn init
复制代码
而后安装咱们须要的代码检查工具(standard)、单元测试工具(jest)和 git hook 工具(husky):npm
yarn add -D standard jest husky
复制代码
安装完毕后,package.json
的内容以下:json
{
"name": "validator",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"devDependencies": {
"husky": "^3.0.5",
"jest": "^24.9.0",
"standard": "^14.3.0"
}
}
复制代码
咱们添加两个命令:
lint
用于启动代码检查test
用于启动单元测试:{
...
"scripts": {
"lint": "standard",
"test": "jest"
},
...
}
复制代码
并设定每次执行 git commit
前,自动运行 yarn lint
和 yarn test
:
{
...
"husky": {
"hooks": {
"pre-commit": "yarn lint && yarn test"
}
}
}
复制代码
咱们新建 jest.config.js
文件,并在其中指定单元测试覆盖率:
module.exports = {
'collectCoverage': true,
'coverageThreshold': {
'global': {
'branches': 100,
'functions': 100,
'lines': 100,
'statements': 100
}
}
}
复制代码
另外,由于在使用 jest
撰写单元测试时,会使用到两个全局变量:test
和 expect
因此,须要在 package.json
中将其添加到 standard
白名单:
{
...
"standard": {
"globals": [
"test",
"expect"
]
}
...
}
复制代码
最终,package.json
的内容以下:
{
"name": "validator",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"lint": "standard",
"test": "jest"
},
"devDependencies": {
"husky": "^3.0.5",
"jest": "^24.9.0",
"standard": "^14.3.0"
},
"husky": {
"hooks": {
"pre-commit": "yarn lint && yarn test"
}
},
"standard": {
"globals": [
"test",
"expect"
]
}
}
复制代码
回顾一下需求,咱们肯定有以下几个功能文件:
index.js
功能入口文件,提供 validator
最终的 api 接口rules.js
负责实现验证规则的细节language.js
负责实现全部语言版本的验证失败信息type.js
负责提供基本的类型校验功能index.test.js
负责实现单元测试除 index.js
外(建立工程时已经建立了此文件),咱们建好上述其余文件。
接下来,咱们新建两个文件夹:
lib
存放 rules.js
、type.js
、language.js
test
存放 index.test.js
最终,目录以下:
├── jest.config.js
├── lib
│ ├── language.js
│ ├── rules.js
│ └── type.js
├── package.json
├── test
│ └── index.test.js
└── yarn.lock
复制代码
到此,咱们已经有了初步的环境和目录结构,接下来,咱们撰写单元测试。
单元测试本质上是站在用户(使用者)的角度去验证功能行为,所以,在开始撰写单元测试以前,咱们先要肯定 validator
的 api:
咱们预期 validator
像以下这般使用:
const V = require('validator')
const params = { name:'hello world', age: 18 }
const schema = { name: 'string|required|max:10', age: 'number' }
const options = { language: 'en', deep: true }
const invalidList = V(params, schema, options)
// check invalidList ...
/* the invalidlist will be [ { paramName: 'name', actualValue: 'hello world', invalidMessage: 'name can not gt 10. hello world given.' } ] */
复制代码
上述代码表达了以下内容:
params
是输入参数对象,其中包含两个参数:name
和 age
,值分别为 hello world
和 18
schema
是针对输入参数对象所描述的具体验证规则,这里实际上要求 name
参数为字符串类型,且必须必传,且最大长度不能超过 10
(能够等于 10
),而 age
参数为数字类型options
做为 validator
的配置参数,决定验证失败信息使用中文仍是英文(默认为中文 zh
),以及是否返回全部验证失败的参数信息(默认只返回第一个验证失败的参数信息)invalidList
是一个数组,若是内容不为空,则其中包含了验证失败参数的信息,包括:参数名称(paramName
)、失败描述(invalidMessage
)、实际值(actualValue
)肯定了 api
以后,咱们来确认撰写测试用例的注意事项:
正
和 反
两个 case,其中,正
的 case 表明验证经过;反
的 case 表明验证失败中文
和 英文
两个 case接下来咱们设计测试用例,最终代码以下:
const V = require('../index.js')
test('invalid value of params or schema or both', () => {
expect(V({ name: 'jarone' })).toEqual([])
expect(V({ name: 'jarone' }, 0)).toEqual([])
expect(V({ name: 'jarone' }, false)).toEqual([])
expect(V({ name: 'jarone' }, '')).toEqual([])
expect(V({ name: 'jarone' }, 123)).toEqual([])
expect(V({ name: 'jarone' }, 'abc')).toEqual([])
expect(V({ name: 'jarone' }, [])).toEqual([])
expect(V({ name: 'jarone' }, {})).toEqual([])
expect(V({ name: 'jarone' }, () => {})).toEqual([])
expect(V({ name: 'jarone' }, Promise.resolve())).toEqual([])
expect(V({ name: 'jarone' }, new Error())).toEqual([])
expect(V({ name: 'jarone' }, new Date())).toEqual([])
expect(V(undefined, { name: 'max:10' })).toEqual([])
expect(V(0, { name: 'max:10' })).toEqual([])
expect(V(false, { name: 'max:10' })).toEqual([])
expect(V('', { name: 'max:10' })).toEqual([])
expect(V(123, { name: 'max:10' })).toEqual([])
expect(V('abc', { name: 'max:10' })).toEqual([])
expect(V([], { name: 'max:10' })).toEqual([])
expect(V({}, { name: 'max:10' })).toEqual([])
expect(V(() => {}, { name: 'max:10' })).toEqual([])
expect(V(Promise.resolve(), { name: 'max:10' })).toEqual([])
expect(V(new Error(), { name: 'max:10' })).toEqual([])
expect(V(new Date(), { name: 'max:10' })).toEqual([])
expect(V()).toEqual([])
expect(V(0, 0)).toEqual([])
expect(V(false, false)).toEqual([])
expect(V('', '')).toEqual([])
expect(V(123, 123)).toEqual([])
expect(V('abc', 'abc')).toEqual([])
expect(V([], [])).toEqual([])
expect(V({}, {})).toEqual([])
expect(V(() => {}, () => {})).toEqual([])
expect(V(Promise.resolve(), Promise.resolve())).toEqual([])
expect(V(new Error(), new Error())).toEqual([])
})
test('RULE: string', () => {
expect(V({ name: 'jarone' }, { name: 'string' })).toEqual([])
expect(V({ name: 1 }, { name: 'string' })).toEqual([{
paramName: 'name',
actualValue: 1,
invalidMessage: 'name 必须为字符串类型, 实际值为:1'
}])
expect(V({ name: 1 }, { name: 'string' }, { language: 'en' })).toEqual([{
paramName: 'name',
actualValue: 1,
invalidMessage: 'name is not string, 1 given.'
}])
})
test('RULE: numericString', () => {
expect(V({ age: '1' }, { age: 'numericString' })).toEqual([])
expect(V({ age: 'one' }, { age: 'numericString' })).toEqual([{
paramName: 'age',
actualValue: 'one',
invalidMessage: 'age 必须为数字, 实际值为:one'
}])
expect(V({ age: 'one' }, { age: 'numericString' }, { language: 'en' })).toEqual([{
paramName: 'age',
actualValue: 'one',
invalidMessage: 'age is not numeric string, one given.'
}])
})
test('RULE: boolean', () => {
expect(V({ ok: false }, { ok: 'boolean' })).toEqual([])
expect(V({ ok: 1 }, { ok: 'boolean' })).toEqual([{
paramName: 'ok',
actualValue: 1,
invalidMessage: 'ok 必须为布尔类型, 实际值为:1'
}])
expect(V({ ok: 1 }, { ok: 'boolean' }, { language: 'en' })).toEqual([{
paramName: 'ok',
actualValue: 1,
invalidMessage: 'ok is not boolean, 1 given.'
}])
})
test('RULE: array', () => {
expect(V({ records: [1, 2] }, { records: 'array' })).toEqual([])
expect(V({ records: 1 }, { records: 'array' })).toEqual([{
paramName: 'records',
actualValue: 1,
invalidMessage: 'records 必须为数组, 实际值为:1'
}])
expect(V({ records: 1 }, { records: 'array' }, { language: 'en' })).toEqual([{
paramName: 'records',
actualValue: 1,
invalidMessage: 'records is not array, 1 given.'
}])
})
test('RULE: required', () => {
expect(V({ name: 'jarone' }, { name: 'required' })).toEqual([])
expect(V({}, { name: 'required' })).toEqual([{
paramName: 'name',
actualValue: undefined,
invalidMessage: '必须传递 name, 且值不能为: null, undefined, NaN, 空字符串, 空数组, 空对象'
}])
expect(V({ name: null }, { name: 'required' })).toEqual([{
paramName: 'name',
actualValue: null,
invalidMessage: '必须传递 name, 且值不能为: null, undefined, NaN, 空字符串, 空数组, 空对象'
}])
expect(V({ name: '' }, { name: 'required' })).toEqual([{
paramName: 'name',
actualValue: '',
invalidMessage: '必须传递 name, 且值不能为: null, undefined, NaN, 空字符串, 空数组, 空对象'
}])
expect(V({ name: [] }, { name: 'required' })).toEqual([{
paramName: 'name',
actualValue: [],
invalidMessage: '必须传递 name, 且值不能为: null, undefined, NaN, 空字符串, 空数组, 空对象'
}])
expect(V({ name: {} }, { name: 'required' })).toEqual([{
paramName: 'name',
actualValue: {},
invalidMessage: '必须传递 name, 且值不能为: null, undefined, NaN, 空字符串, 空数组, 空对象'
}])
expect(V({ name: {} }, { name: 'required' }, { language: 'en' })).toEqual([{
paramName: 'name',
actualValue: {},
invalidMessage: 'Must pass name, and the value cannot be: null, undefined, NaN, empty string, empty array, empty object'
}])
})
test('RULE: max', () => {
expect(V({ name: 'jarone' }, { name: 'max:10' })).toEqual([])
expect(V({ name: 'hello world' }, { name: 'max:10' })).toEqual([{
paramName: 'name',
actualValue: 'hello world',
invalidMessage: 'name 的长度或大小不能大于 10. 实际值为:hello world'
}])
expect(V({ name: 'hello world' }, { name: 'max:10' }, { language: 'en' })).toEqual([{
paramName: 'name',
actualValue: 'hello world',
invalidMessage: 'name length or size cannot be greater than 10. actual value is: hello world'
}])
})
test('RULE: min', () => {
expect(V({ name: 'hello world' }, { name: 'min:10' })).toEqual([])
expect(V({ name: 'jarone' }, { name: 'min:10' })).toEqual([{
paramName: 'name',
actualValue: 'jarone',
invalidMessage: 'name 的长度或大小不能小于 10. 实际值为:jarone'
}])
expect(V({ name: 'jarone' }, { name: 'min:10' }, { language: 'en' })).toEqual([{
paramName: 'name',
actualValue: 'jarone',
invalidMessage: 'name length or size cannot be less than 10. actual value is: jarone'
}])
})
test('OPTIONS: deep', () => {
expect(V({ name: 'hello world', age: 18 }, { name: 'min:10', age: 'max:18' }, { deep: true })).toEqual([])
expect(V({ name: 'jarone', age: 28 }, { name: 'min:10', age: 'max:18' }, { deep: true })).toEqual([
{
paramName: 'name',
actualValue: 'jarone',
invalidMessage: 'name 的长度或大小不能小于 10. 实际值为:jarone'
},
{
paramName: 'age',
actualValue: 28,
invalidMessage: 'age 的长度或大小不能大于 18. 实际值为:28'
}
])
expect(V({ name: 'jarone', age: 28 }, { name: 'min:10', age: 'max:18' }, { deep: true, language: 'en' })).toEqual([
{
paramName: 'name',
actualValue: 'jarone',
invalidMessage: 'name length or size cannot be less than 10. actual value is: jarone'
},
{
paramName: 'age',
actualValue: 28,
invalidMessage: 'age length or size cannot be greater than 18. actual value is: 28'
}
])
})
test('extend rules', () => {
expect(
V(
{ name: 'jarone' },
{ name: 'isJarone' },
{
language: 'en',
extRules: { isJarone: (val) => val === 'jarone' },
extInvalidMessages: { isJarone: (paramName, val) => `${paramName} is not jarone, ${val} given.` }
}
)).toEqual([])
expect(
V(
{ name: 'luy' },
{ name: 'isJarone' },
{
language: 'en',
extRules: { isJarone: (val) => val === 'jarone' },
extInvalidMessages: { isJarone: (paramName, val) => `${paramName} is not jarone, ${val} given.` }
}
)).toEqual([{
paramName: 'name',
actualValue: 'luy',
invalidMessage: 'name is not jarone, luy given.'
}])
})
复制代码
lib/type.js
咱们须要一组函数来提供对于基本类型的判断,一个比较好的方式是使用那些通过时间考验的工具库
本文中咱们使用的类型判断功能并不太多,因此选择本身实现这些函数:
function _isType (arg, type) {
return Object.prototype.toString.call(arg) === `[object ${type}]`
}
module.exports = {
isString: arg => _isType(arg, 'String'),
isBoolean: arg => _isType(arg, 'Boolean'),
isArray: arg => _isType(arg, 'Array'),
isObject: arg => _isType(arg, 'Object'),
isNaN: arg => Number.isNaN(arg),
isNull: arg => _isType(arg, 'Null'),
isUndefined: arg => _isType(arg, 'Undefined'),
isNumericString: arg => _isType(+arg, 'Number') && !Number.isNaN(+arg)
}
复制代码
lib/language.js
按照需求,咱们须要支持 中文
和 英文
两种语言的验证失败信息
对于基础类型和 required
验证规则而言,咱们只须要传递参数名称和实际值,就能获得验证失败信息;对于 max
和 min
这两个规则,还须要传递边界值:
const invalidMsgEn = {
string: (paramName, actualValue) => `${paramName} is not string, ${actualValue} given.`,
numericString: (paramName, actualValue) => `${paramName} is not numeric string, ${actualValue} given.`,
boolean: (paramName, actualValue) => `${paramName} is not boolean, ${actualValue} given.`,
array: (paramName, actualValue) => `${paramName} is not array, ${actualValue} given.`,
required: (paramName, actualValue) => `Must pass ${paramName}, and the value cannot be: null, undefined, NaN, empty string, empty array, empty object`,
max: (paramName, actualValue, boundary) => `${paramName} length or size cannot be greater than ${boundary}. actual value is: ${actualValue}`,
min: (paramName, actualValue, boundary) => `${paramName} length or size cannot be less than ${boundary}. actual value is: ${actualValue}`
}
const invalidMsgZh = {
string: (paramName, actualValue) => `${paramName} 必须为字符串类型, 实际值为:${actualValue}`,
numericString: (paramName, actualValue) => `${paramName} 必须为数字, 实际值为:${actualValue}`,
boolean: (paramName, actualValue) => `${paramName} 必须为布尔类型, 实际值为:${actualValue}`,
array: (paramName, actualValue) => `${paramName} 必须为数组, 实际值为:${actualValue}`,
required: (paramName, actualValue) => `必须传递 ${paramName}, 且值不能为: null, undefined, NaN, 空字符串, 空数组, 空对象`,
max: (paramName, actualValue, boundary) => `${paramName} 的长度或大小不能大于 ${boundary}. 实际值为:${actualValue}`,
min: (paramName, actualValue, boundary) => `${paramName} 的长度或大小不能小于 ${boundary}. 实际值为:${actualValue}`
}
module.exports = {
zh: invalidMsgZh,
en: invalidMsgEn
}
复制代码
lib/rules.js
咱们约定:规则函数的返回值类型为布尔类型,true
表明验证经过,false
表明验证失败
接下来,咱们借助于前文已经实现的 lib/type.js
,建立如下4种类型验证规则:
const T = require('./type.js')
module.exports = {
string: T.isString,
numericString: T.isNumericString,
boolean: T.isBoolean,
array: T.isArray
}
复制代码
required
规则接下来,咱们实现 required
规则,回顾一下前文中关于 required
的详情描述
参数值为 null、undefined、NaN、空字符串、空数组、空对象,则验证不经过;不然,验证经过:
const T = require('./type.js')
const _isPassedRequired = val => {
if (T.isNaN(val) || T.isUndefined(val) || T.isNull(val)) return false
if ((T.isArray(val) || T.isObject(val) || T.isString(val)) && !Object.keys(val).length) return false
return true
}
module.exports = {
string: T.isString,
numericString: T.isNumericString,
bool: T.isBoolean,
array: T.isArray,
required: val => _isPassedRequired(val)
}
复制代码
max
和 min
规则对于 max
规则
参数值类型若是是:数字,则值不能大于(能够等于)max:
后面指定的值;
参数值类型若是是:字符串、数组,则长度不能大于(能够等于)max:
后面指定的值。
min
规则正好与 max
相反。
咱们对于相似 max
和 min
这种对比逻辑,简单作一下抽象,将对比操做符和对类型的处理,分别定义出来:
...
const operatorMapping = {
'>=': (val, boundary) => val >= boundary,
'<=': (val, boundary) => val <= boundary
}
// compare: Array、String、Number and Numeric String
const _compare = (val, boundary, operator) => (T.isString(val) || T.isArray(val))
? !operatorMapping[operator](val && val.length, boundary)
: !operatorMapping[operator](+val, boundary)
...
module.exports = {
...
max: (val, boundary) => _compare(val, boundary, '>='),
min: (val, boundary) => _compare(val, boundary, '<=')
}
复制代码
index.js
最后,咱们来实现入口文件 index.js
,它负责:
deep
的值,决定只返回第一个验证失败的参数信息仍是返回所有language
的值,决定在组装验证失败信息时,使用 中文
或 英文
extRules
和 extLanguages
的值,决定是否扩展验证规则和对应的信息文案入口文件 index.js
最终的代码以下:
const T = require('./lib/type.js')
const InvalidMessages = require('./lib/language.js')
const Rules = require('./lib/rules.js')
function validateSingleParamByMultipleRules (name, val, rulesString, allRules, allInvalidMsg, allParams) {
let result = ''
const rules = rulesString.split('|')
for (let i = 0, len = rules.length; i < len; i++) {
const rule = rules[i]
const idxOfSeparator = rule.indexOf(':')
let ruleName = rule
let ruleValue = ''
if (~idxOfSeparator) {
ruleValue = rule.substr(idxOfSeparator + 1)
ruleName = rule.substr(0, idxOfSeparator)
}
const fn = allInvalidMsg[ruleName + '']
if (!allRules[ruleName](val, ruleValue, allParams)) {
result = {
paramName: name,
actualValue: val,
invalidMessage: fn(name, val, ruleValue)
}
break
}
}
return result
}
function main (params, schema, options = {}) {
const invalidParams = []
if (!T.isObject(schema)) return invalidParams
if (!T.isObject(params)) params = {}
const needValidateParamNameList = Object.keys(schema)
if (!needValidateParamNameList.length) return invalidParams
const { language = 'zh', deep = false, extRules = {}, extInvalidMessages = {} } = options
const allRules = Object.assign({}, Rules, extRules)
const allInvalidMessages = Object.assign({}, InvalidMessages[language], extInvalidMessages)
for (let i = 0, len = needValidateParamNameList.length; i < len; i++) {
const name = needValidateParamNameList[i]
const val = params[name]
const rulesString = schema[name]
if (!name || !rulesString || (T.isUndefined(val) && !rulesString.includes('required'))) continue
const invalidInfo = validateSingleParamByMultipleRules(name, val, rulesString, allRules, allInvalidMessages, params)
if (invalidInfo) {
invalidParams.push(invalidInfo)
if (!deep) break
}
}
return invalidParams
}
module.exports = main
复制代码
最后,咱们再次运行单元测试 yarn test
, 结果以下:
yarn run v1.13.0
$ jest
PASS test/index.test.js
✓ invalid value of params or schema or both (9ms)
✓ RULE: string (1ms)
✓ RULE: numericString (1ms)
✓ RULE: boolean
✓ RULE: array (1ms)
✓ RULE: required (1ms)
✓ RULE: max (1ms)
✓ RULE: min (1ms)
✓ OPTIONS: deep
✓ extend rules (1ms)
---------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
---------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
validator | 100 | 100 | 100 | 100 | |
index.js | 100 | 100 | 100 | 100 | |
validator/lib | 100 | 100 | 100 | 100 | |
language.js | 100 | 100 | 100 | 100 | |
rules.js | 100 | 100 | 100 | 100 | |
type.js | 100 | 100 | 100 | 100 | |
---------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 10 passed, 10 total
Snapshots: 0 total
Time: 1.104s
Ran all test suites.
✨ Done in 1.97s.
复制代码
至此,咱们已经完成了 validator
的建立与研发工做
想查看完整代码的读者,能够访问在 GitHub 的代码仓库 validator
想在本身的工程中使用的读者,可使用 npm
安装 validator-simple
接下来,咱们在 NodeJS
工程中,实践一下 validator
新建一个工程,并安装 koa
、koa-bodyparser
和 validator-simple
:
mkdir demo && cd demo && yarn init
yarn add koa koa-bodyparser validator-simple
复制代码
新建 validator.js
文件,并输入以下内容:
const V = require('validator-simple')
const main = (params, schema) => {
const invalidMsg = V(params, schema)
if (invalidMsg && invalidMsg.length) {
let err = new Error(
'参数错误:' + invalidMsg[0].invalidMessage +
' 参数名称:' + invalidMsg[0].paramName +
' 参数值:' + invalidMsg[0].actualValue
)
err.code = 400
throw err
}
}
module.exports = main
复制代码
新建 app.js
文件,并输入以下内容:
const Koa = require('koa')
const app = new Koa()
const V = require('./validator.js')
app.use(require('koa-bodyparser')())
app.use(async (ctx, next) => {
try {
await next()
} catch (error) {
ctx.status = error.code || 500
ctx.body = error.message
}
})
app.use(async ctx => {
const params = ctx.request.body
const schema = {
name: 'required|string|min:3|max:10'
}
V(params, schema)
ctx.body = 'done'
})
app.listen({ port: 3000 }, () =>
console.log('🚀 Server ready at http://localhost:3000')
)
复制代码
启动服务,咱们在命令行请求这个服务,分别传递正确的 name
,和错误的 name
,返回以下:
➜ ~ curl -X POST http://localhost:3000 -H 'content-type: application/json' -d '{"name":"jarone"}'
done
➜ ~ curl -X POST http://localhost:3000 -H 'content-type: application/json' -d '{}'
参数错误:必须传递 name, 且值不能为: null, undefined, NaN, 空字符串, 空数组, 空对象 参数名称:name 参数值:undefined
➜ ~ curl -X POST http://localhost:3000 -H 'content-type: application/json' -d '{"name":1}'
参数错误:name 必须为字符串类型, 实际值为:1 参数名称:name 参数值:1
➜ ~ curl -X POST http://localhost:3000 -H 'content-type: application/json' -d '{"name":"a"}'
参数错误:name 的长度或大小不能小于 3. 实际值为:a 参数名称:name 参数值:a
➜ ~ curl -X POST http://localhost:3000 -H 'content-type: application/json' -d '{"name":"abcedfghijk"}'
参数错误:name 的长度或大小不能大于 10. 实际值为:abcedfghijk 参数名称:name 参数值:abcedfghijk
➜ ~ curl -X POST http://localhost:3000 -H 'content-type: application/json' -d '{"name":[]}'
参数错误:必须传递 name, 且值不能为: null, undefined, NaN, 空字符串, 空数组, 空对象 参数名称:name 参数值:
➜ ~ curl -X POST http://localhost:3000 -H 'content-type: application/json' -d '{"name":{}}'
参数错误:必须传递 name, 且值不能为: null, undefined, NaN, 空字符串, 空数组, 空对象 参数名称:name 参数值:[object Object]
复制代码
本文中,咱们只实现了几个基本的验证规则,在咱们实际的工做中,还会有更多的场景须要使用验证器。例如:
基于游标分页的参数中,通常会传递以下参数:
pageSize
表明每页展现的记录数next
表明当前页面最后一条记录的游标prev
表明当前页面第一条记录的游标一般,参数 next
和 prev
是互斥的,咱们彻底能够根据场景需求让验证器支持以下规则:
next
参数,则要求必须传递 prev
参数;反之亦然next
参数和 prev
参数,则验证不经过或默认只识别其中一个参数;不然验证经过在校验用户生日等日期表单值时,咱们但愿验证器支持校验日期参数,且能限制日期值的上限和下限:
日期参数值相似: 2019-01-01 13:30
限制日期类参数值的规则相似: date|gte:1900-01-01|lte:2020-12-31
...
最后,但愿这篇文章能帮助到您。
水滴前端团队招募伙伴,欢迎投递简历到邮箱:fed@shuidihuzhu.com