Skip to content

Instantly share code, notes, and snippets.

@mtpultz
Last active October 26, 2017 14:28
Show Gist options
  • Save mtpultz/45a28445a6e710008b9b92c82792122d to your computer and use it in GitHub Desktop.
Save mtpultz/45a28445a6e710008b9b92c82792122d to your computer and use it in GitHub Desktop.
Express-Validator v4 - Encapsulated Validations Example
const router: Router = express.Router();
// ... removed for brevity
/**
* Create a new example.
*/
router.post('/examples/:id',
exampleController.validate('create'),
exampleController.create
);
// ... removed for brevity
export { router as mineralRoutes };
import { Response, Request, NextFunction } from 'express';
import { ValidationChain, check } from 'express-validator/check';
import { BaseController } from './base.controller';
class ExampleController extends BaseController {
constructor() {
super();
// Bind scope to the public methods
this.create = this.create.bind(this);
}
// ... removed for brevity
/**
* Create a new example.
*
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
* @memberof ExampleController
*/
public async create(req: Request, res: Response, next: NextFunction) {
console.log('example:create');
this.successResponse(res);
// this.errorResponse(res);
}
/**
* Chain used to validate incoming request data.
*
* @readonly
* @private
* @memberof ExampleController
*/
protected get validationChain(): ValidationChain[] {
return {
create: [
check('example1', 'Example 1 is required.').exists(),
check('example2', 'Example 2 is required.').exists()
]
};
}
//... removed for brevity
}
export default new ExampleController;
export abstract class BaseController extends Validator {
/**
* Set the success response.
*
* @private
* @param {Response} res
* @param {User} user
* @memberof BaseController
*/
protected abstract successResponse(res: Response, options?: any): void;
/**
* Set the error response.
*
* @private
* @param {Response} res
* @param {User} user
* @memberof BaseController
*/
protected abstract errorResponse(res: Response, options?: any): void;
}
import { Response, Request, NextFunction, RequestHandler } from 'express';
import { ValidationChain, validationResult } from 'express-validator/check';
export abstract class Validator {
/**
* Resolve only a single error from the first field.
*
* @type {boolean}
* @memberof Validator
*/
public onlyFirstFieldAndError: boolean;
constructor() {
this.onlyFirstFieldAndError = true;
// Bind scope to the public methods used as middleware
this.validate = this.validate.bind(this);
}
/**
* Chain used to validate incoming request data.
*
* @readonly
* @private
* @memberof Validator
*/
protected abstract get validationChain(): { [key: string]: ValidationChain[] };
/**
* Validate request data middleware.
*
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
* @memberof Validator
*/
// public async validate(req: Request, res: Response, next: NextFunction) {
public validate(key: string): Array<ValidationChain | RequestHandler> {
return [
...this.validationChain[key],
this.validator()
];
}
/**
* Run validations on request data.
*
* @private
* @param {Request} req
* @param {Response} res
* @returns {Promise<any>}
* @memberof Validator
*/
protected validator(): RequestHandler {
return (req: Request, res: Response, next: NextFunction) => {
try {
// Run the validation chain
validationResult(req).throw();
next();
} catch (err) {
this.validatorErrorResponse(res, err);
}
};
}
/**
* Set the validation error response.
*
* @protected
* @param {Response} res
* @param {any} err
* @memberof Validator
*/
protected validatorErrorResponse(res: Response, err: any): void {
// Resolve the first validation error on each field, or all the validation
// errors on every field
const errorBag = (this.onlyFirstError) ? err.mapped() : err.array();
res.status(422).json(errorBag);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment