preface
Continue my self-built blog journey, Node build blog background, using KOA + mysql to achieve. This time do the validation of the request parameters 👉
Project source: github.com/Ray-daydayu…
The cause of
I have been using yAPI to simulate the interface, which provides the simulation of interface verification. Every time I request the verification parameter, I will be reminded that the request parameter type is wrong. When I wrote the API myself, I got a little confused. How does the background work? (at this time I use Java classmate smiled smile, you see, I write a type good 😜. … Keep smiling 😊)
Then I started searching for koA-related plugins. There were a lot of them, such as KOA-Parameter, KOA2-Validator, and koA-middle-Validator. Then I in line with my learning psychology, write a simple parameter verification (in fact, the level is limited, do not know how to combine with what I have, want to use my own encapsulation of the exception processing 🙃).
When it comes to parameter validation, one guy who seems to be famous is Joi, who uses it something like this (source code) 👇
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');
var input = {
username: 'zzbo'
}
var output = Joi.validate(input, schema);
//error: ValidationError: "value" must contain at least one of [isA, isB]
Copy the code
At the time, I was surprised to see it written like this. As a kid, I didn’t know anything about object orientation and chain calls, and it really hit me. Could I try to implement something similar? Once this idea was born, it could not be put out.
Principle and code implementation
Usage examples
First of all, the first use of finished products, the level is limited, only to achieve the sample 👇
// Define verification rules
let schema = {
page: new ParamCheck().isNumber().min(1).isRequired(),
pagesize: new ParamCheck().isNumber().min(1).isRequired(),
moreDetail: new ParamCheck().isBoolean().isRequired(),
tagId: new ParamCheck().isNumber().min(1),
categoryId: new ParamCheck().isNumber().min(1)}// Wait for the verification result, and throw an exception if it fails (combined with my previous exception handling)
await ParamCheck.check(params, schema, ctx)
Copy the code
I only considered validation of the passed object, and although new looked ugly, it fulfilled my requirements for the time being.
Thought analysis
The whole idea is to define a parameter verification class, and call the corresponding method to collect verification rules (I defined as the attribute rules of the instance) after initializing the instance. By defining a rule object, loop out each rule definition when calling class static methods, value it by key, and then check it against the rule set. There are two main tasks:
- Collection of rules
- Validation of validation rules
Collection of rules
I started by defining three types of rules according to my requirements: type rules, length rules, and must-have rules. Then there is the code implementation 👇
class paramCheck {
constructor() {
this.rules = {} // rule set type: indicates the type; Min and Max represent the upper and lower limits of length. IsRequired indicates whether it isRequired
}
// Validate static methods
static async check(params, schema, ctx) {
const keys = Object.keys(schema)
try {
// Loop out the rule set for verification
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
let rules = schema[key].rules // Get the rule set
rulesCheck(params, key, rules)// Call function verification
}
return
} catch (error) {
// Catch thrown errors
switch (error.name) {
case "paramNotComplete":
await PARAM_NOT_COMPLETE(ctx, error.message) // The exception handler defined earlier
break
case "paramTypeError":
await PARAM_TYPE_ERROR(ctx, error.message)
break
case "paramNotValid":
await PARAM_NOT_VALID(ctx, error.message)
break
default:
await FAIL(ctx, error.message)
break}}}// Type rules
isString() {
this.rules.type = "string" // Write type rules
return this // Return this chain call
}
isNumber() {
this.rules.type = "number"
return this
}
isBoolean() {
this.rules.type = "boolean"
return this
}
isObject() {
this.rules.type = Object // Object and array are treated specially
return this
}
isArray() {
this.rules.type = Array
return this
}
// Length rule
min(min) {
this.rules.min = min // Write the length rule
return this
}
max(max) {
this.rules.max = max
return this
}
// Whether it is necessary
isRequired() {
this.rules.isRequired = true
return this}}Copy the code
Validation of rules
Rules are validated in a certain order, whether must be > type rule > length rule, so must be validated in order. The code looks like this
function rulesCheck(params, key, rules) {
if(! requiredCheck()) {return false
}
typeCheck()
lengthCheck()
return true
function requiredCheck() {... }function typeCheck() {... }function lengthCheck() {... }}// Argument error class
class ParamError extends Error {
constructor(msg, name) {
super(msg)
this.name = name
}
}
Copy the code
- Whether must
function requiredCheck() {
// If the parameter is required, but no, an error is reported
if(rules.isRequired && ! params.hasOwnProperty(key)) {throw new ParamError('Request parameters${key}Missing `."paramNotComplete")}if(! rules.isRequired && ! params.hasOwnProperty(key)) {// The parameter is not required, but no further validation is required
return false
}
// All other cases need to be checked
return true
}
Copy the code
- Type checking
function typeCheck() {
if (rules.type) {
const type = rules.type
// Check type
if (
typeof params[key] === type ||
(typeoftype ! = ="string" && params[key] instanceof type)
) {
return
}
// Throw an error
throw new ParamError('Request parameters${key}Type error '."paramTypeError")}}Copy the code
- Type checking
function lengthCheck() {
const min = rules.min ? rules.min : 0
const max = rules.max ? rules.max : Infinity
const type = rules.type
let length = 0
// Check the length of arrays and strings
if (type === "string" || type === Array) {
length = params[key].length
}
// Check the size of the number
if (type === "number") {
length = params[key]
}
if (length < min || length > max) {
throw new ParamError('Request parameters${key}Length invalid '."paramNotValid")}}Copy the code
conclusion
A simple validation of the parameters has been done, which is rudimentary, but satisfies my needs. A novice, the code to write insufficient place, please forgive me 🙏