UNPKG

@namecheap/express-inversify

Version:

Some utilities for the development of express applications with Inversify

236 lines 10.5 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.InversifyExpressServer = void 0; const express = require("express"); const index_1 = require("./index"); const utils_1 = require("./utils"); const constants_1 = require("./constants"); const httpResponseMessage_1 = require("./httpResponseMessage"); class InversifyExpressServer { constructor(container, customRouter, routingConfig, customApp, authProvider, forceControllers = true) { this._container = container; this._forceControllers = forceControllers; this._router = customRouter || express.Router(); this._routingConfig = routingConfig || { rootPath: constants_1.DEFAULT_ROUTING_ROOT_PATH, }; this._app = customApp || express(); if (authProvider) { this._AuthProvider = authProvider; container.bind(constants_1.TYPE.AuthProvider) .to(this._AuthProvider); } } setConfig(fn) { this._configFn = fn; return this; } setErrorConfig(fn) { this._errorConfigFn = fn; return this; } build() { this._app.all('*', (req, res, next) => { (() => __awaiter(this, void 0, void 0, function* () { const httpContext = yield this._createHttpContext(req, res, next); Reflect.defineMetadata(constants_1.METADATA_KEY.httpContext, httpContext, req); next(); }))(); }); if (this._configFn) { this._configFn.apply(undefined, [this._app]); } this.registerControllers(); if (this._errorConfigFn) { this._errorConfigFn.apply(undefined, [this._app]); } return this._app; } registerControllers() { this._container.bind(constants_1.TYPE.HttpContext).toConstantValue({}); const constructors = (0, utils_1.getControllersFromMetadata)(); constructors.forEach(constructor => { const { name } = constructor; if (this._container.isBoundNamed(constants_1.TYPE.Controller, name)) { throw new Error((0, constants_1.DUPLICATED_CONTROLLER_NAME)(name)); } this._container.bind(constants_1.TYPE.Controller) .to(constructor) .whenTargetNamed(name); }); const controllers = (0, utils_1.getControllersFromContainer)(this._container, this._forceControllers); controllers.forEach((controller) => { const controllerMetadata = (0, utils_1.getControllerMetadata)(controller.constructor); const methodMetadata = (0, utils_1.getControllerMethodMetadata)(controller.constructor); const parameterMetadata = (0, utils_1.getControllerParameterMetadata)(controller.constructor); if (controllerMetadata && methodMetadata) { const controllerMiddleware = this.resolveMidleware(...controllerMetadata.middleware); methodMetadata.forEach((metadata) => { let paramList = []; if (parameterMetadata) { paramList = parameterMetadata[metadata.key] || []; } const handler = this.handlerFactory(controllerMetadata.target.name, metadata.key, paramList); const routeMiddleware = this.resolveMidleware(...metadata.middleware); this._router[metadata.method](`${controllerMetadata.path}${metadata.path}`, ...controllerMiddleware, ...routeMiddleware, handler); }); } }); this._app.use(this._routingConfig.rootPath, this._router); } resolveMidleware(...middleware) { return middleware.map(middlewareItem => { if (!this._container.isBound(middlewareItem)) { return middlewareItem; } const m = this._container.get(middlewareItem); if (m instanceof index_1.BaseMiddleware) { return (req, res, next) => { const httpContext = this._getHttpContext(req); const mReq = httpContext.container.get(middlewareItem); mReq.httpContext = httpContext; mReq.handler(req, res, next); }; } return m; }); } copyHeadersTo(headers, target) { for (const name of Object.keys(headers)) { const headerValue = headers[name]; target.append(name, typeof headerValue === 'number' ? headerValue.toString() : headerValue); } } handleHttpResponseMessage(message, res) { return __awaiter(this, void 0, void 0, function* () { this.copyHeadersTo(message.headers, res); if (message.content !== undefined) { this.copyHeadersTo(message.content.headers, res); res.status(message.statusCode) .send(yield message.content.readAsStringAsync()); } else { res.sendStatus(message.statusCode); } }); } handlerFactory(controllerName, key, parameterMetadata) { return (req, res, next) => __awaiter(this, void 0, void 0, function* () { try { const args = this.extractParameters(req, res, next, parameterMetadata); const httpContext = this._getHttpContext(req); httpContext.container.bind(constants_1.TYPE.HttpContext) .toConstantValue(httpContext); const value = yield httpContext.container.getNamed(constants_1.TYPE.Controller, controllerName)[key](...args); if (value instanceof httpResponseMessage_1.HttpResponseMessage) { yield this.handleHttpResponseMessage(value, res); } else if ((0, utils_1.instanceOfIHttpActionResult)(value)) { const httpResponseMessage = yield value.executeAsync(); yield this.handleHttpResponseMessage(httpResponseMessage, res); } else if (value instanceof Function) { value(); } else if (!res.headersSent) { if (value === undefined) { res.status(200); } res.send(value); } } catch (err) { next(err); } }); } _getHttpContext(req) { return Reflect.getMetadata(constants_1.METADATA_KEY.httpContext, req); } _createHttpContext(req, res, next) { return __awaiter(this, void 0, void 0, function* () { const principal = yield this._getCurrentUser(req, res, next); return { request: req, response: res, container: this._container.createChild(), user: principal, }; }); } _getCurrentUser(req, res, next) { return __awaiter(this, void 0, void 0, function* () { if (this._AuthProvider !== undefined) { const authProvider = this._container.get(constants_1.TYPE.AuthProvider); return authProvider.getUser(req, res, next); } return Promise.resolve({ details: null, isAuthenticated: () => Promise.resolve(false), isInRole: (role) => Promise.resolve(false), isResourceOwner: (resourceId) => Promise.resolve(false), }); }); } extractParameters(req, res, next, params) { const args = []; if (!params || !params.length) { return [req, res, next]; } params.forEach(({ type, index, parameterName, injectRoot, }) => { switch (type) { case constants_1.PARAMETER_TYPE.REQUEST: args[index] = req; break; case constants_1.PARAMETER_TYPE.NEXT: args[index] = next; break; case constants_1.PARAMETER_TYPE.PARAMS: args[index] = this.getParam(req, 'params', injectRoot, parameterName); break; case constants_1.PARAMETER_TYPE.QUERY: args[index] = this.getParam(req, 'query', injectRoot, parameterName); break; case constants_1.PARAMETER_TYPE.BODY: args[index] = req.body; break; case constants_1.PARAMETER_TYPE.HEADERS: args[index] = this.getParam(req, 'headers', injectRoot, parameterName); break; case constants_1.PARAMETER_TYPE.COOKIES: args[index] = this.getParam(req, 'cookies', injectRoot, parameterName); break; case constants_1.PARAMETER_TYPE.PRINCIPAL: args[index] = this._getPrincipal(req); break; default: args[index] = res; break; } }); args.push(req, res, next); return args; } getParam(source, paramType, injectRoot, name) { const key = paramType === 'headers' ? name === null || name === void 0 ? void 0 : name.toLowerCase() : name; const param = source[paramType]; if (injectRoot) { return param; } return (param && key) ? param[key] : undefined; } _getPrincipal(req) { return this._getHttpContext(req).user; } } exports.InversifyExpressServer = InversifyExpressServer; //# sourceMappingURL=server.js.map