Created
November 18, 2024 02:05
-
-
Save renmu123/de7d51addcb51358d12b2c368498fb8c to your computer and use it in GitHub Desktop.
koa validator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import originValidators from "validator"; | |
import { Context, Next } from "koa"; | |
type ValidatorFunction = (value: any, args?: any) => boolean; | |
interface CustomValidators { | |
[key: string]: ValidatorFunction; | |
} | |
const customValidators: CustomValidators = { | |
isString: (value) => { | |
return typeof value === "string"; | |
}, | |
isArray: (value) => { | |
return Array.isArray(value); | |
}, | |
isObject: (value) => { | |
return typeof value === "object"; | |
}, | |
isNumber: (value) => { | |
return typeof value === "number"; | |
}, | |
isInt: (value) => { | |
return Number.isInteger(value); | |
}, | |
}; | |
const validators = { ...originValidators, ...customValidators }; | |
interface ValidationRule { | |
method: string; | |
args?: any; | |
message: string; | |
} | |
class ValidationChain { | |
ctx: Context; | |
chain: ValidationRule[]; | |
fieldType: string; | |
field: string; | |
constructor() { | |
this.chain = []; | |
this.fieldType = ""; | |
this.field = ""; | |
} | |
validate(value: any): { field: string; message: string }[] { | |
const field = this.field; | |
const errors: { field: string; message: string }[] = []; | |
for (const rule of this.chain) { | |
const methodName = rule.method; | |
let newValue = value; | |
if (!customValidators[methodName]) { | |
newValue = value + ""; | |
} | |
const validateMethod = validators[methodName]; | |
if (!validateMethod(newValue, rule.args)) { | |
errors.push({ field: field, message: rule.message }); | |
break; | |
} | |
} | |
return errors; | |
} | |
body(field: string): this { | |
this.field = field; | |
this.fieldType = "body"; | |
return this; | |
} | |
query(field: string): this { | |
this.field = field; | |
this.fieldType = "query"; | |
return this; | |
} | |
add(method: string, args: any, message: string): this { | |
this.chain.push({ method, args, message }); | |
return this; | |
} | |
isInt({ opts, message }: { opts?: any; message?: string } = {}): this { | |
this.add("isInt", opts, message ?? "Invalid integer"); | |
return this; | |
} | |
isNumber({ message }: { message?: string } = {}): this { | |
this.add("isNumber", {}, message ?? "Invalid number"); | |
return this; | |
} | |
isString({ message }: { message?: string } = {}): this { | |
this.add("isString", {}, message ?? "Invalid string"); | |
return this; | |
} | |
isArray({ message }: { message?: string } = {}): this { | |
this.add("isArray", {}, message ?? "Invalid array"); | |
return this; | |
} | |
isObject({ message }: { message?: string } = {}): this { | |
this.add("isObject", {}, message ?? "Invalid object"); | |
return this; | |
} | |
} | |
const validate = (schema: ValidationChain[]) => { | |
return async (ctx: Context, next: Next) => { | |
const body = ctx.request.body; | |
const query = ctx.request.query; | |
const errors: { field: string; message: string }[] = []; | |
for (const chain of schema) { | |
const field = chain.field; | |
const data = chain.fieldType === "body" ? body : query; | |
console.log("data", data, field); | |
errors.push(...chain.validate(data[field])); | |
} | |
if (errors.length > 0) { | |
ctx.status = 400; | |
ctx.body = { | |
errors: errors, | |
}; | |
console.log("errors", errors); | |
} else { | |
await next(); | |
} | |
}; | |
}; | |
function body(field: string): ValidationChain { | |
const chain = new ValidationChain(); | |
chain.body(field); | |
return chain; | |
} | |
function query(field: string): ValidationChain { | |
const chain = new ValidationChain(); | |
chain.query(field); | |
return chain; | |
} | |
export { validate, body, query }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment