UNPKG

4.07 kBJavaScriptView Raw
1'use strict';
2
3// Setup of a convenient Express starting point for web applications.
4// Also sets up some call perf metrics collection.
5
6const { wrap } = require('underscore');
7
8const express = require('abacus-express');
9const eureka = require('abacus-eureka');
10const hystrix = require('abacus-hystrix');
11const oauth = require('abacus-oauth');
12const perf = require('abacus-perf');
13const metrics = require('abacus-metrics');
14const router = require('abacus-router');
15const vcapenv = require('abacus-vcapenv');
16
17const { OK: STATUS_OK, INTERNAL_SERVER_ERROR: STATUS_INTERNAL_SERVER_ERROR } = require('http-status-codes');
18
19// Setup debug log
20const debug = require('abacus-debug')('abacus-webapp');
21
22const defaultSecurity = () => process.env.SECURED === 'true';
23const secured = () => process.env.HEALTHCHECK_SECURED === 'false' ? false : defaultSecurity();
24
25const healthCheckScopes = 'abacus.system.read';
26const metricsAuthorizationScopes = ['abacus.system.read'];
27
28const defaultHealthCheck = (req, res) => {
29 debug(`Entering ${secured ? 'secured' : ''} healthcheck`);
30 const h = perf.healthy();
31 debug('Returning app health %s', h);
32 res.status(h ? STATUS_OK : STATUS_INTERNAL_SERVER_ERROR).send({
33 healthy: h
34 });
35};
36
37const createMetricsRoute = () => {
38 const route = router();
39 if (secured())
40 route.use(oauth.authorizer(process.env.JWTKEY, process.env.JWTALGO, metricsAuthorizationScopes));
41 route.use(metrics.createMiddleware(metrics.defaultCollection));
42 return route;
43};
44
45const appName = vcapenv.appname();
46
47// Configure an Express-based Web app
48const webapp = () => {
49 debug('Setting up %s environment', appName);
50 process.env.TZ = 'UTC';
51 if (!process.env.VCAP_APPLICATION) {
52 process.env.PORT = process.env.PORT || process.env.npm_package_config_port;
53 process.env.APPS = 1;
54 process.env.APP_NAME = appName;
55 process.env.APP_INDEX = 0;
56 process.env.INSTANCES = 1;
57 process.env.INSTANCE_INDEX = 0;
58 }
59
60 debug('Creating %s', appName);
61 const app = express();
62 app.use(vcapenv.headers());
63 app.use('/v1/metrics', createMetricsRoute());
64
65 let healthCheckMiddlware = defaultHealthCheck;
66
67 /**
68 * Specifies the healthcheck middleware to use for the healthcheck endpoint.
69 * If no middleware is specified or this method is not called, a default one will be used.
70 *
71 * @param {object} middleware middleware object to serve healthcheck calls
72 * @returns {undefined}
73 */
74 app.useHealthCheck = (middleware) => {
75 if (middleware) healthCheckMiddlware = middleware;
76 else healthCheckMiddlware = defaultHealthCheck;
77 };
78
79 // Monkey patch the app listen function to register some of our middleware after the app's middleware
80 /* eslint complexity: [1, 7] */
81 app.listen = wrap(app.listen, (listen, opt, cb) => {
82 if (secured()) {
83 app.use(
84 '/hystrix.stream',
85 oauth.basicStrategy(process.env.API, hystrix.scopes, process.env.JWTKEY, process.env.JWTALGO)
86 );
87
88 app.use(
89 '/healthcheck',
90 oauth.basicStrategy(process.env.API, healthCheckScopes, process.env.JWTKEY, process.env.JWTALGO)
91 );
92 }
93
94 app.use('/hystrix.stream', hystrix.stream());
95 app.get('/healthcheck', healthCheckMiddlware);
96
97 // Call the original app listen function
98 debug('Application %s listening', appName);
99 const server = listen.call(app, opt, cb);
100
101 // Optionally register the app instance in a Eureka registry
102 if (eureka())
103 eureka.register(eureka(), appName, vcapenv.iport() || server.address().port, vcapenv.iaddress(), (err, val) => {
104 if (err) debug('Couldn\'t register app %s in Eureka registry, %o', appName, err);
105 else debug('Registered app %s in Eureka registry', appName);
106 });
107
108 if (process.env.CONNECTION_TIMEOUT) {
109 const connectionTimeout = parseInt(process.env.CONNECTION_TIMEOUT);
110 debug('Setting %s connection timeout to %d', appName, connectionTimeout);
111 server.setTimeout(connectionTimeout);
112 }
113
114 return server;
115 });
116
117 debug('%s started', appName);
118 return app;
119};
120
121module.exports = webapp;