REST-API-08-Parameters-Validation

express-validator

https://github.com/ctavan/express-validator

installtion

1
$ npm install express-validator

joi

https://github.com/hapijs/joi

Introduction

This is joi, joi allows you to create blueprints or schemas for JavaScript objects (an object that stores information) to ensure validation of key information.

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
const Joi = require('joi');
const schema = Joi.object().keys({
username: Joi.string().alphanum().min(3).max(30).required(),
password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),
access_token: [Joi.string(), Joi.number()],
birthyear: Joi.number().integer().min(1900).max(2013),
email: Joi.string().email()
}).with('username', 'birthyear').without('password', 'access_token');
// Return result.
const result = Joi.validate({ username: 'abc', birthyear: 1994 }, schema);
// result.error === null -> valid
// You can also pass a callback which will be called synchronously with the validation result.
Joi.validate({ username: 'abc', birthyear: 1994 }, schema, function (err, value) { }); // err === null -> valid

Install

1
$ npm install joi --save

本例采用joi,对 schema 的校验。

主要代码

helpers/routerHelpers.js
学完lesson11,发现一个问题 ,idSchema ,使用 param 做key,可以用来校验通用的id,在validateParam中做相应调整。
修改如下: ( 详情,参考 lesson11)

1
2
3
4
5
6
const result = Joi.validate({param: req['params'][name]},schema);
req.value['params'][name]= result.value.param;
//...
idSchema: Joi.object().keys({
param:Joi.string().regex(/^[0-9a-fA-F]{24}$/).required()
})

由于代码已经打了tag,不方便修改,旧代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//helpers/routerHelpers.js
const Joi = require('joi');
module.exports = {
validateParam:(schema,name) => {
return (req,res,next) => {
console.log('req.params',req.params);
const result = Joi.validate({param:req['params'][name]},schema);
if(result.error){
return res.status(400).json(result.error);
}else{
if(!req.value){
req.value = {};
}
if(!req.value['params']){
req.value['params'] = {};
}
req.value['params'][name] = result.value.param;
next();
}
}
},
/**
* req['params'][name] => req.params.userId
* name = 'UserId'
*/
schemas: {
idSchema: Joi.object().keys({
userId:Joi.string().regex(/^[0-9a-fA-F]{24}$/).required()
})
}
}

routers/users.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//routers/users.js
const express = require('express');
//const router = express.Router();
const router = require('express-promise-router')();
const userController = require('../controllers/users');
const { validateParam, schemas } = require('../helpers/routerHelpers');
router.route('/')
.get(userController.index)
.post(userController.newUser);
router.route('/:userId')
.get(validateParam(schemas.idSchema, 'userId'), userController.getUser)
.put(userController.replaceUser)
.patch(userController.updateUser);
router.route('/:userId/cars').get(userController.getUserCars)
.post(userController.newUserCar);
module.exports = router;

controllers/users.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
//controllers/users.js
const User = require('../models/user');
const Car = require('../models/car');
//const Joi = require('joi');
// const idSchema = Joi.object().keys({
// userId:Joi.string().regex(/^[0-9a-fA-F]{24}$/).required()
// });
module.exports = {
index: async (req, res, next) => {
const users = await User.find();
//throw new Error('Dummy error !');
res.status(200).json(users);
},
newUser: async (req, res, next) => {
const newUser = new User(req.body);
const user = await newUser.save();
res.status(200).json(user);
},
getUser: async (req, res, next) => {
// enforce that req.body must contain all the fields
//验证的一般用法
//const result = Joi.validate(req.params,idSchema);
const { userId } = req.params;
const users = await User.findById(userId);
res.status(200).json(users);
},
replaceUser: async (req, res, next) => {
// req.body may contain any number of fields
const { userId } = req.params;
const newUser = req.body;
const result = await User.findByIdAndUpdate(userId, newUser);
res.status(200).json({ success: true });
},
updateUser: async (req, res, next) => {
const { userId } = req.params;
const newUser = req.body;
const result = await User.findByIdAndUpdate(userId, newUser);
res.status(200).json({ success: true });
},
getUserCars: async (req, res, next) => {
//const result = Joi.validate(req.params,idSchema);
const { userId } = req.params;
const user = await User.findById(userId).populate('cars');
res.status(200).json(user.cars);
},
newUserCar: async (req, res, next) => {
const { userId } = req.params;
// Create a new car
const newCar = new Car(req.body);
// Get user
const user = await User.findById(userId);
// Assign user as a car's seller
newCar.seller = user;
// Save the car
await newCar.save();
// Add car to the user's selling array 'cars'
user.cars.push(newCar);
// Save the user
await user.save();
res.status(201).json(newCar);
}
}

代码

https://github.com/monk8/expressjs-rest-api-server/tree/lesson08

参考
https://www.bilibili.com/video/av11683622/#page=8