0.0.8 • Published 6 years ago
koa-expect v0.0.8
Expect - middleware for params validation
If ctx
contain params property then it will be validated else if ctx.method === 'GET'
then ctx.query
else ctx.request.body
Example
import Koa from 'koa';
const app = new Koa();
import expect from 'koa-expect';
app.use(async (ctx, next) => {
try {
await next();
} catch (err) {
ctx.status = err.status || 500;
ctx.body = err.message;
ctx.app.emit('error', err, ctx);
}
});
import bodyParser from 'koa-bodyparser';
app.use(bodyParser());
/* optional */
app.use((ctx, next) => {
ctx.params = { ...ctx.query, ...ctx.request.body };
return next();
});
/* -------- */
const inputSchema = {
email: {
type: String,
validate: (v) => /.+@.+\..+/i.test(v)
},
name: String,
password: {
type: String,
validate: (v) => v.length >= 5
},
password_confirmation: {
validate: (v, params) => v === params.password,
error: {
validate: 'password_confirmation not matches to password'
}
},
age: {
type: Number,
default: 10
},
country: {
type: String,
required: false
}
};
const outputSchema = {
email: {
type: String,
validate: (v) => /.+@.+\..+/i.test(v)
},
name: String,
age: {
type: Number,
default: 10
},
country: {
type: String,
required: false
}
};
import Router from 'koa-router';
const router = new Router();
router.post('/register', expect(inputSchema, outputSchema), (ctx) => {
ctx.body = 'ok';
});
app.use(router.routes());
app.listen(3000);
You can write like so:
{
age: Number
}
It is equivalent to
{
age: {
type: Number,
required: true
}
}
Type
- String
- Number
- Boolean
- Array
- Object
You can specify either only type:
{
name: String,
age: Number
}
or property type in schema object:
{
name: {
type: String,
},
age: {
type: Number,
}
}
Required and default
required === true
by default
Let's pretend that params do not contain age
- If
!required
then param will be skipped (in validation)
{
age: {
required: false,
type: Number
}
}
- If
default
value provided andrequired
then it will be in params
{
age: {
required: true,
default: 5 // => ctx.params.age === 5
},
size: {
default: (params) => params.age * 2 // => ctx.params.size === 10
}
}
- If
required === true
and field not specified then an error will happen
{
age: {
type: Number
}
}
- required may be a function
{
key: {
required: (params) => !params.index,
error: {
required: 'Params must contain either key or index'
}
}
}
In case above if params do not contain index then an error will happen
Validate
- function for param validation
validate(param, params)
{
color: {
type: String,
required: true,
validate: (val) => ['white', 'black'].includes(val)
},
password: {
type: String,
required: true,
validate: (val) => val.length > 5 && val.length < 30
},
password_confirmation: {
validate: (confirmation, params) => confirmation === params.password
}
}
Schema
If params contain an object and you want to check it then you can use schema
/* some helpful declarations */
const humanSchema = {
id: {
type: Number,
required: true
},
name: String,
};
const subjectSchema = {
title: String
};
const teacherSchema = {
...humanSchema,
subjects: {
type: Array,
item: subjectSchema
}
};
const studentSchema = {
...humanSchema,
subject: {
type: Object,
required: true,
schema: subjectSchema
},
mark: {
type: Number,
required: true,
validate: (v) => v > 0 && v <= 5
}
};
/* declarations end */
/* our schema */
const schema = {
student: {
type: Object,
required: true,
schema: studentSchema
},
teacher: {
type: Object,
required: true,
schema: teacherSchema
}
}
Item
If param is Array and you want to check each element then you can use item
{
matrix3D: { // [[[1, 2, 3], [4, 5, 6]], [[8, 9, 10], [11, 12, 13]]]
type: Array,
required: true,
validate: (v) => v.length,
item: {
type: Array,
required: true,
item: {
type: Array,
required: true,
validate: (v) => v > 0,
item: Number
}
}
},
order: { // ['age', 'name']
type: Array,
required: true,
item: String
}
}
ctx.params.matrix3D = [] // Bad request, matrix3D is invalid
ctx.params.matrix3D = [1] // Bad request, matrix3D[0] should be array, but found number
ctx.params.matrix3D = [[[1], 1]] //Bad request, matrix3D[0][1] should be array, but found number
ctx.params.matrix3D = [[[1], [1]]] // OK
Process
{
code: {
type: Array,
required: true,
validate: (val) => val.length === 2,
process: (val) => val.join('_')
}
}
ctx.params.code = ['element', 5] // => expect => ctx.params.code = 'element_5'
Custom errors
If validatorName
error happen then Error
with message error[validatorName]
(or standard message) will be thrown.
{
month: {
type: String,
required: true,
validate: (v) => ['September', 'October', 'November'].includes(v),
error: {
validate: 'Month must be one of autumn months',
required: 'Month is required',
type: 'Month must be a String'
}
}
}