UNPKG

inceptum

Version:

hipages take on the foundational library for enterprise-grade apps written in NodeJS

135 lines 5.12 kB
"use strict"; // tslint:disable:prefer-function-over-method Object.defineProperty(exports, "__esModule", { value: true }); const NewrelicUtil_1 = require("../newrelic/NewrelicUtil"); const optionParsingRegExp = /^\s*([^\s]*)\s*\((.*)\)/; const optionParsingRegExp2 = /[a-zA-Z0-9?:@_-]+/g; const SWAGGER_CONTROLLER_PROPERTY = 'x-inceptum-controller'; const SWAGGER_OPERATION_PROPERTY = 'x-inceptum-operation'; const newrelic = NewrelicUtil_1.NewrelicUtil.getNewrelicIfAvailable(); function assert(predicate, message) { if (!predicate) { throw new Error(message); } } const getControllerName = (req) => req.swagger.operation[SWAGGER_CONTROLLER_PROPERTY] ? req.swagger.operation[SWAGGER_CONTROLLER_PROPERTY] : req.swagger.path[SWAGGER_CONTROLLER_PROPERTY]; const getOperationName = (req) => req.swagger.operation[SWAGGER_OPERATION_PROPERTY] ? req.swagger.operation[SWAGGER_OPERATION_PROPERTY] : req.method.toLowerCase(); class SwaggerRouterMiddleware { constructor(context) { this.context = context; this.handlerCache = new Map(); } hasController(req) { if (!req || !req.swagger) { return false; } if (req.swagger.operation && req.swagger.operation[SWAGGER_CONTROLLER_PROPERTY]) { return true; } if (req.swagger.path && req.swagger.path[SWAGGER_CONTROLLER_PROPERTY]) { return true; } return false; } async register(expressApp) { expressApp.use(async (req, res, next) => { if (newrelic && req.swagger && req.swagger.apiPath) { // NR adds a `/` at the start of the path for us. const basePath = req.swagger.swaggerObject.basePath.substring(1); newrelic.setTransactionName(`${basePath}${req.swagger.apiPath}`); } try { if (this.hasController(req)) { const handler = await this.getControllerHandler(req); assert(handler, `Could not find handler for ${getControllerName(req)}#${getOperationName(req)}. Make sure there is a matching class/method registered on the context.`); try { const resp = await handler(req, res); assert(res.headersSent, `${getControllerName(req)}#${getOperationName(req)} was called but didn't handle the request. Make sure you always handle the request by calling an appopriate method on "res"`); } catch (error) { next(error); // Send to express error handler } } else { next(); // Not handled, continue up the middleware chain } } catch (e) { next(e); // Send to express error handler } }); } /** * @private * @param controllerName * @returns {*} */ getControllerObjectPromise(controllerName) { return this.context.getObjectByName(controllerName); } /** * @private * @param req * @returns Function */ async getControllerHandler(req) { const controllerName = getControllerName(req); const operationId = getOperationName(req); const key = `${controllerName}_${operationId}`; if (this.handlerCache.has(key)) { return this.handlerCache.get(key); } const controller = await this.getControllerObjectPromise(controllerName); if (controller) { const handler = this.createControllerArgHandler(controller, operationId); if (handler) { this.handlerCache.set(key, handler); return handler; } } } /** * @private * @param controller * @param operationId * @returns {function(*=, *=)|null} */ createControllerArgHandler(controller, operationId) { let functionName; let params = []; if (operationId.indexOf('(') < 0) { functionName = operationId.trim(); } else { const matches = operationId.match(optionParsingRegExp); functionName = matches[1]; if (matches[2].trim().length > 0) { params = matches[2].match(optionParsingRegExp2); } } if (!controller[functionName]) { return; } const paramFunctions = []; params.forEach((param) => { if (param === 'null') { paramFunctions.push(() => null); } else { paramFunctions.push((req) => req.swagger.params[param].value); } }); paramFunctions.push((req) => req); paramFunctions.push((req, res) => res); return (req, res) => { const args = paramFunctions.map((f) => f(req, res)); return controller[functionName](...args); }; } } exports.default = SwaggerRouterMiddleware; //# sourceMappingURL=SwaggerRouterMiddleware.js.map