Skip to content
This repository was archived by the owner on Oct 18, 2021. It is now read-only.

Commit 68f6964

Browse files
committed
use servicelib init lib in app.js
1 parent 3ef6e7e commit 68f6964

File tree

3 files changed

+35
-503
lines changed

3 files changed

+35
-503
lines changed

app.js

Lines changed: 4 additions & 222 deletions
Original file line numberDiff line numberDiff line change
@@ -1,223 +1,7 @@
11
'use strict';
22

3-
const http = require('http');
4-
const BBPromise = require('bluebird');
53
const express = require('express');
6-
const compression = require('compression');
7-
const bodyParser = require('body-parser');
8-
const fs = BBPromise.promisifyAll(require('fs'));
9-
const sUtil = require('./lib/util');
10-
const apiUtil = require('./lib/api-util');
11-
const packageInfo = require('./package.json');
12-
const yaml = require('js-yaml');
13-
const addShutdown = require('http-shutdown');
14-
const path = require('path');
15-
16-
/**
17-
* Creates an express app and initialises it
18-
*
19-
* @param {Object} options the options to initialise the app with
20-
* @return {bluebird} the promise resolving to the app object
21-
*/
22-
function initApp(options) {
23-
24-
// the main application object
25-
const app = express();
26-
27-
// get the options and make them available in the app
28-
app.logger = options.logger; // the logging device
29-
app.metrics = options.metrics; // the metrics
30-
app.conf = options.config; // this app's config options
31-
app.info = packageInfo; // this app's package info
32-
33-
// ensure some sane defaults
34-
app.conf.port = app.conf.port || 8888;
35-
app.conf.interface = app.conf.interface || '0.0.0.0';
36-
// eslint-disable-next-line max-len
37-
app.conf.compression_level = app.conf.compression_level === undefined ? 3 : app.conf.compression_level;
38-
app.conf.cors = app.conf.cors === undefined ? '*' : app.conf.cors;
39-
if (app.conf.csp === undefined) {
40-
app.conf.csp = "default-src 'self'; object-src 'none'; media-src 'none'; img-src 'none'; style-src 'none'; base-uri 'self'; frame-ancestors 'self'";
41-
}
42-
43-
// set outgoing proxy
44-
if (app.conf.proxy) {
45-
process.env.HTTP_PROXY = app.conf.proxy;
46-
// if there is a list of domains which should
47-
// not be proxied, set it
48-
if (app.conf.no_proxy_list) {
49-
if (Array.isArray(app.conf.no_proxy_list)) {
50-
process.env.NO_PROXY = app.conf.no_proxy_list.join(',');
51-
} else {
52-
process.env.NO_PROXY = app.conf.no_proxy_list;
53-
}
54-
}
55-
}
56-
57-
// set up header whitelisting for logging
58-
if (!app.conf.log_header_whitelist) {
59-
app.conf.log_header_whitelist = [
60-
'cache-control', 'content-type', 'content-length', 'if-match',
61-
'user-agent', 'x-request-id'
62-
];
63-
}
64-
app.conf.log_header_whitelist = new RegExp(`^(?:${app.conf.log_header_whitelist.map((item) => {
65-
return item.trim();
66-
}).join('|')})$`, 'i');
67-
68-
// set up the request templates for the APIs
69-
apiUtil.setupApiTemplates(app);
70-
71-
// set up the spec
72-
if (!app.conf.spec) {
73-
app.conf.spec = `${__dirname}/spec.yaml`;
74-
}
75-
if (app.conf.spec.constructor !== Object) {
76-
try {
77-
app.conf.spec = yaml.safeLoad(fs.readFileSync(app.conf.spec));
78-
} catch (e) {
79-
app.logger.log('warn/spec', `Could not load the spec: ${e}`);
80-
app.conf.spec = {};
81-
}
82-
}
83-
if (!app.conf.spec.openapi) {
84-
app.conf.spec.openapi = '3.0.0';
85-
}
86-
if (!app.conf.spec.info) {
87-
app.conf.spec.info = {
88-
version: app.info.version,
89-
title: app.info.name,
90-
description: app.info.description
91-
};
92-
}
93-
app.conf.spec.info.version = app.info.version;
94-
if (!app.conf.spec.paths) {
95-
app.conf.spec.paths = {};
96-
}
97-
98-
// set the CORS and CSP headers
99-
app.all('*', (req, res, next) => {
100-
if (app.conf.cors !== false) {
101-
res.header('access-control-allow-origin', app.conf.cors);
102-
res.header('access-control-allow-headers', 'accept, x-requested-with, content-type');
103-
res.header('access-control-expose-headers', 'etag');
104-
}
105-
if (app.conf.csp !== false) {
106-
res.header('x-xss-protection', '1; mode=block');
107-
res.header('x-content-type-options', 'nosniff');
108-
res.header('x-frame-options', 'SAMEORIGIN');
109-
res.header('content-security-policy', app.conf.csp);
110-
}
111-
sUtil.initAndLogRequest(req, app);
112-
next();
113-
});
114-
115-
// set up the user agent header string to use for requests
116-
app.conf.user_agent = app.conf.user_agent || app.info.name;
117-
118-
// disable the X-Powered-By header
119-
app.set('x-powered-by', false);
120-
// disable the ETag header - users should provide them!
121-
app.set('etag', false);
122-
// enable compression
123-
app.use(compression({ level: app.conf.compression_level }));
124-
// use the JSON body parser
125-
app.use(bodyParser.json({ limit: app.conf.max_body_size || '100kb' }));
126-
// use the application/x-www-form-urlencoded parser
127-
app.use(bodyParser.urlencoded({ extended: true }));
128-
129-
return BBPromise.resolve(app);
130-
131-
}
132-
133-
/**
134-
* Loads all routes declared in routes/ into the app
135-
*
136-
* @param {Application} app the application object to load routes into
137-
* @param {string} dir routes folder
138-
* @return {bluebird} a promise resolving to the app object
139-
*/
140-
function loadRoutes(app, dir) {
141-
142-
// recursively load routes from .js files under routes/
143-
return fs.readdirAsync(dir).map((fname) => {
144-
return BBPromise.try(() => {
145-
const resolvedPath = path.resolve(dir, fname);
146-
const isDirectory = fs.statSync(resolvedPath).isDirectory();
147-
if (isDirectory) {
148-
loadRoutes(app, resolvedPath);
149-
} else if (/\.js$/.test(fname)) {
150-
// import the route file
151-
const route = require(`${dir}/${fname}`);
152-
return route(app);
153-
}
154-
}).then((route) => {
155-
if (route === undefined) {
156-
return undefined;
157-
}
158-
// check that the route exports the object we need
159-
if (route.constructor !== Object || !route.path || !route.router ||
160-
!(route.api_version || route.skip_domain)) {
161-
throw new TypeError(`routes/${fname} does not export the correct object!`);
162-
}
163-
// normalise the path to be used as the mount point
164-
if (route.path[0] !== '/') {
165-
route.path = `/${route.path}`;
166-
}
167-
if (route.path[route.path.length - 1] !== '/') {
168-
route.path = `${route.path}/`;
169-
}
170-
if (!route.skip_domain) {
171-
route.path = `/:domain/v${route.api_version}${route.path}`;
172-
}
173-
// wrap the route handlers with Promise.try() blocks
174-
sUtil.wrapRouteHandlers(route, app);
175-
// all good, use that route
176-
app.use(route.path, route.router);
177-
});
178-
}).then(() => {
179-
// catch errors
180-
sUtil.setErrorHandler(app);
181-
// route loading is now complete, return the app object
182-
return BBPromise.resolve(app);
183-
});
184-
185-
}
186-
187-
/**
188-
* Creates and start the service's web server
189-
*
190-
* @param {Application} app the app object to use in the service
191-
* @return {bluebird} a promise creating the web server
192-
*/
193-
function createServer(app) {
194-
195-
// return a promise which creates an HTTP server,
196-
// attaches the app to it, and starts accepting
197-
// incoming client requests
198-
let server;
199-
return new BBPromise((resolve) => {
200-
server = http.createServer(app).listen(
201-
app.conf.port,
202-
app.conf.interface,
203-
resolve
204-
);
205-
server = addShutdown(server);
206-
}).then(() => {
207-
app.logger.log('info',
208-
`Worker ${process.pid} listening on ${app.conf.interface || '*'}:${app.conf.port}`);
209-
210-
// Don't delay incomplete packets for 40ms (Linux default) on
211-
// pipelined HTTP sockets. We write in large chunks or buffers, so
212-
// lack of coalescing should not be an issue here.
213-
server.on('connection', (socket) => {
214-
socket.setNoDelay(true);
215-
});
216-
217-
return server;
218-
});
219-
220-
}
4+
const init = require('servicelib-node/init');
2215

2226
/**
2237
* The service's entry point. It takes over the configuration
@@ -229,13 +13,11 @@ function createServer(app) {
22913
* @return {bluebird} HTTP server
23014
*/
23115
module.exports = (options) => {
232-
233-
return initApp(options)
234-
.then((app) => loadRoutes(app, `${__dirname}/routes`))
16+
return init.initApp(options)
17+
.then((app) => init.loadRoutes(app, `${__dirname}/routes`))
23518
.then((app) => {
23619
// serve static files from static/
23720
app.use('/static', express.static(`${__dirname}/static`));
23821
return app;
239-
}).then(createServer);
240-
22+
}).then(init.createServer);
24123
};

0 commit comments

Comments
 (0)