對於任何 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