Skip to content

Commit

Permalink
ADD app-factory and response json middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
sciotta committed Nov 22, 2019
1 parent b5b3bf4 commit 32a0188
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 307 deletions.
112 changes: 112 additions & 0 deletions app-factory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
const restify = require('restify');
const SwaggerRestifyMw = require('swagger-restify-mw');
const morgan = require('morgan');
const bodyParser = require('body-parser');
const elasticApmNode = require('elastic-apm-node');

const { ResponseJsonMiddleware } = require('./middlewares/response-json-middleware');

let UnexpectedError;

const verifyIntegrityErrors = ({ integrityCheckers }) => {
const errors = integrityCheckers.map((checker) => {
try {
checker();
return null;
} catch (error) {
return error;
}
}).filter(error => error);
if (errors.length) {
throw new UnexpectedError(errors
.reduce((acc, error) => `${acc || ''}${error.message}\n`));
}
};

const injectSwaggerToApp = ({ app, appRoot, swaggerFile }) => new Promise((resolve, reject) => {
SwaggerRestifyMw.create({ appRoot, swaggerFile }, (err, swaggerRestify) => {
if (err) {
reject(err);
return;
}
swaggerRestify.register(app);
resolve();
});
});

const registerGracefulShutdown = ({ app, closeSequelize, logger }) => {
const gracefulShutdown = () => {
app.close();
closeSequelize()
.then(() => { process.exit(0); })
.catch((err) => {
logger.error(err);
process.exit(1);
});
};
process.on('SIGINT', gracefulShutdown);
};

const notifyProcessInitializedGracefully = () => {
// for more information see https://pm2.io/doc/en/runtime/best-practices/graceful-shutdown/
if (process.send) process.send('ready');
};

const setupElasticApm = ({ logger, elasticApmEnabled }) => {
logger.info(`ElasticSearch APM enabled: ${elasticApmEnabled || false}`);

if (elasticApmEnabled) {
logger.info(`Init ElasticSearch APM enabled: ${process.env.ES_APM_ENABLED}`);
elasticApmNode.start({
serviceName: process.env.APM_SERVICE_NAME || 'default',
serverUrl: process.env.APM_SERVICE_HOST,
});
}
};

module.exports.createApp = ({ integrityCheckers }) => {
verifyIntegrityErrors({ integrityCheckers });
return restify.createServer();
};

module.exports.injectMiddlewaresAndListen = async ({
app, isSentryEnabled, isDevelopment, isLogRequestEnabled, logger, raven,
closeSequelize, port, env, appRoot, swaggerFile, isElasticApmEnabled, isNewRelicApmEnabled,
requestTraceMiddleware, prometheusMiddleware, auditTrailMiddleware, unexpectedError,
}) => {
UnexpectedError = unexpectedError;

if (isSentryEnabled) {
app.use(raven.requestHandler());
}

if (isLogRequestEnabled) {
if (isDevelopment) {
app.use(morgan('dev'));
} else {
app.use(morgan('combined'));
}
}
logger.info(`NewRelic APM enabled: ${isNewRelicApmEnabled}`);
setupElasticApm({ logger, elasticApmEnabled: isElasticApmEnabled });

app.use(requestTraceMiddleware);
app.use(prometheusMiddleware.requestCounters);
app.use(prometheusMiddleware.responseCounters);
app.use(ResponseJsonMiddleware);
app.use(bodyParser.json({ limit: '50mb' }));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(restify.plugins.multipartBodyParser());
prometheusMiddleware.injectMetricsRoute(app);

await injectSwaggerToApp({ app, appRoot, swaggerFile });
app.on('after', auditTrailMiddleware);
app.listen(port);
logger.info(`API running on http://localhost:${port}`);
logger.info(`API running on ${env.toUpperCase()} mode.`);

notifyProcessInitializedGracefully();
registerGracefulShutdown({ app, closeSequelize, logger });

return app;
};
6 changes: 6 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const { createApp, injectMiddlewaresAndListen } = require('./app-factory');

module.exports = {
createApp,
injectMiddlewaresAndListen,
};
39 changes: 39 additions & 0 deletions middlewares/response-json-middleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
const { NotFoundError } = require('restify');

function ResponseJsonMiddleware(req, res, next) {
res.json = (json, statusCode = 200) => {
res.writeHead(statusCode, {
'Cache-Control': 'no-cache, no-store, must-revalidate',
Pragma: 'no-cache',
Expires: 0,
'Content-Type': 'application/json',
});
res.end(JSON.stringify(json));
};

res.action = (localNext, actionFunction) => actionFunction()
.then((obj) => {
if (obj === null) {
localNext(new NotFoundError());
} else {
res.json(obj);
}
})
.catch((err) => {
localNext(err);
});

res.xml = (xml, statusCode = 200) => {
res.writeHead(statusCode, {
'Cache-Control': 'no-cache, no-store, must-revalidate',
Pragma: 'no-cache',
Expires: 0,
'Content-Type': 'application/xml',
});
res.end(xml);
};

next();
}

module.exports = { ResponseJsonMiddleware };
Loading

0 comments on commit 32a0188

Please sign in to comment.