UNPKG

6.03 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const e = require("express");
4const onFinished = require("on-finished");
5const prometheus_extended_gauge_1 = require("prometheus-extended-gauge");
6const promBundle = require("express-prom-bundle");
7const xmlparser = require("express-xml-bodyparser");
8const BaseSingletonDefinition_1 = require("../ioc/objectdefinition/BaseSingletonDefinition");
9const NewrelicUtil_1 = require("../newrelic/NewrelicUtil");
10const LogManager_1 = require("../log/LogManager");
11const WebRoutingInspector_1 = require("./WebRoutingInspector");
12const HttpError_1 = require("./HttpError");
13const ContentNegotiationMiddleware_1 = require("./ContentNegotiationMiddleware");
14const logger = LogManager_1.LogManager.getLogger(__filename);
15const activeRequestsGauge = new prometheus_extended_gauge_1.ExtendedGauge({
16 max: true,
17 min: false,
18 average: true,
19 bucketSizeMillis: 1000,
20 numBuckets: 60,
21 help: 'Number of active http requests being processed',
22 name: 'http_active_requests',
23});
24class RouteRegisterUtil {
25 constructor() {
26 this.routesToRegister = [];
27 }
28 doRegister() {
29 this.routesToRegister.forEach((route) => {
30 logger.info(`Registering route from ${route.objectName}: ${route.verb.toUpperCase()} ${route.path} -> ${route.methodName}`);
31 this.express[route.verb](route.path, (req, res) => {
32 return this[route.instanceProperty][route.methodName](req, res);
33 });
34 });
35 }
36}
37exports.RouteRegisterUtil = RouteRegisterUtil;
38/**
39 * Client errors do not need to be sent to NewRelic so create clientErrorMiddleware
40 * to send response if the error is 4xx. clientErrorMiddleware needs to be registered
41 * before errorMiddleware.
42 * @param err
43 * @param req
44 * @param res
45 * @param next
46 */
47exports.clientErrorMiddleware = (err, req, res, next) => {
48 if (err instanceof HttpError_1.default && err.statusCode && err.statusCode >= 400 && err.statusCode < 500) {
49 res.status(err.getStatusCode()).send({ message: err.message });
50 }
51 else {
52 return next(err); // Give back to express to handle
53 }
54};
55exports.errorMiddleware = (err, req, res, next) => {
56 logger.error(err);
57 if (res.headersSent) {
58 return next(err); // Give back to express to handle
59 }
60 if (err instanceof HttpError_1.default && err.statusCode) {
61 if (err.statusCode >= 500) {
62 NewrelicUtil_1.NewrelicUtil.noticeError(err);
63 }
64 res.status(err.getStatusCode()).send({ message: err.message });
65 }
66 else {
67 NewrelicUtil_1.NewrelicUtil.noticeError(err);
68 res.status(500).end();
69 }
70};
71class WebPlugin {
72 // private expressProvider = () => new e();
73 constructor(options = {}) {
74 this.options = options;
75 this.name = 'WebPlugin';
76 }
77 willStart(app, pluginContext) {
78 const express = e();
79 express.set('trust proxy', true); // stop redirecting to http internally https://expressjs.com/en/guide/behind-proxies.html
80 pluginContext.set(WebPlugin.CONTEXT_APP_KEY, express);
81 const context = app.getContext();
82 express.use(promBundle({
83 includeMethod: true,
84 buckets: [0.003, 0.03, 0.1, 0.3, 0.5, 1.5, 10],
85 autoregister: false,
86 }));
87 // Add middleware for stats on active requests
88 express.use((req, res, next) => {
89 activeRequestsGauge.inc();
90 onFinished(res, () => activeRequestsGauge.dec());
91 next();
92 });
93 this.registerXmlBodyParser(express);
94 this.registerXmlContentNegotiationMiddleware(express, app.getConfig('app.xmlRoot', ''));
95 // move from didStart to willStart
96 express.use(e.json({ limit: app.getConfig('app.server.maxRequestSize', '10mb') }));
97 express.use(e.urlencoded({ extended: true, limit: app.getConfig('app.server.maxRequestSize', '10mb') }));
98 if (this.options && this.options.staticRoots) {
99 this.options.staticRoots.forEach((root) => {
100 express.use(e.static(root));
101 });
102 }
103 const definition = new BaseSingletonDefinition_1.BaseSingletonDefinition(RouteRegisterUtil);
104 definition.withLazyLoading(false);
105 definition.startFunction('doRegister');
106 definition.setPropertyByValue('express', express);
107 context.registerDefinition(definition);
108 context.addObjectDefinitionInspector(new WebRoutingInspector_1.WebRoutingInspector(definition));
109 }
110 didStart(app, pluginContext) {
111 const express = pluginContext.get(WebPlugin.CONTEXT_APP_KEY);
112 const port = app.getConfig('app.server.port', 10010);
113 express.use(exports.clientErrorMiddleware);
114 // Add error handling middleware as the final middleware.
115 express.use(exports.errorMiddleware);
116 // Start the server
117 const server = express.listen(port, () => {
118 app.logger.info(`Server started at http://localhost:${port}`);
119 });
120 pluginContext.set(WebPlugin.CONTEXT_SERVER_KEY, server);
121 }
122 didStop(app, pluginContext) {
123 const express = pluginContext.get(WebPlugin.CONTEXT_SERVER_KEY);
124 app.logger.info('Shutting down server');
125 if (express) {
126 express.close();
127 }
128 }
129 registerXmlBodyParser(express) {
130 if (this.options && this.options.xmlBodyParserOptions) {
131 express.use(xmlparser(this.options.xmlBodyParserOptions));
132 }
133 }
134 registerXmlContentNegotiationMiddleware(express, xmlRoot) {
135 const negoContentMiddleware = new ContentNegotiationMiddleware_1.ContentNegotiationMiddleware(xmlRoot);
136 const xmlMiddleware = negoContentMiddleware.getMiddleware();
137 if (xmlMiddleware) {
138 express.use(xmlMiddleware);
139 }
140 }
141}
142WebPlugin.CONTEXT_APP_KEY = 'WebPlugin/APP';
143WebPlugin.CONTEXT_SERVER_KEY = 'WebPlugin/SERVER';
144exports.default = WebPlugin;
145//# sourceMappingURL=WebPlugin.js.map
\No newline at end of file