import { Container, interfaces as inversify_interfaces } from 'inversify' import { TYPE, interfaces as express_interfaces } from 'inversify-express-utils' import { METADATA_KEY } from './constants' import { VaildError } from './interfaces' import { getVaildMethodMetadata, getVaildControllerMetadata, getVaildModelMetadata } from './utils' let handler = { apply: function(target: Function, thisArgument: Object, argumentsList: any[]) { let methodParams = getVaildMethodMetadata(target); let [req, res, next] = [...argumentsList.slice(-3)]; try { // loop @Valid params for (const param of methodParams) { // get function argument value let origin = argumentsList[param.index]; let props = getVaildModelMetadata(param.type); for (const prop of props) { if (!prop.handle(origin[prop.name])) { throw new VaildError(prop.message); } } } return target.apply(thisArgument, argumentsList); } catch (ex) { if (ex instanceof VaildError) { res.status(400).json({ status: 400, message: ex.message }) return; } throw ex; } } } function rebuildServer(container: Container) { // get all controller let controllers = container.getAll(TYPE.Controller) // for loop controllers and inject proxy to each method for (const controller of controllers) { container.rebind(TYPE.Controller) .to(controller.constructor as any) .inSingletonScope() .whenTargetNamed(controller.constructor.name) .onActivation((ctx: inversify_interfaces.Context, controller: express_interfaces.Controller) => { let prop = controller.constructor.prototype // funcs => { create: [ { index: 0, type: [Function: ExampleModel] } ] } let funcs = getVaildControllerMetadata(controller.constructor); //Reflect.getMetadata(METADATA_KEY.controllerParameter, controller.constructor); for (const func in funcs) { Reflect.defineMetadata(METADATA_KEY.vaildMethod, funcs[func], prop[func]) // Define Proxy handle model vaild Reflect.defineProperty(prop, func, { value: new Proxy(prop[func], handler) }) } return controller; }); } } export { rebuildServer }