joule
Version:
Node implementation of Mule for creating REST services
178 lines (139 loc) • 5.36 kB
JavaScript
var cmndr = require('commander');
cmndr
.option('-c, --configFile <configFile>', 'Specify the config file to use')
.parse(process.argv);
var fs = require('fs');
var path = require('path');
var events = require('events');
// express and middleware
var express = require('express');
//var morgan = require('morgan');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
var cookieParser = require('cookie-parser');
var compression = require('compression');
var appConfig = initConfig();
var functionFactory = require('./functionFactory')(appConfig);
var i = 0,
j = 0,
k = 0;
for (i in appConfig.apps) {
// NOTE: We should use let in these for-loops instead of var with ES6
var connector = appConfig.apps[i];
var app = createExpressApplication(connector);
for (j in connector.routes) {
var route = connector.routes[j];
var customErrorHandler = null;
// We work backwards through the components so we're able to tell each function which callback to call next.
// So we start with the sendResponse handler, which is the last function in the chain.
var func = functionFactory.getSendResponseHandler();
// Loop backwards through the components, building the callback chain.
var numComponents = route.components.length;
for (k = numComponents - 1; k >= 0; k--) {
var component = route.components[k];
var obj = functionFactory.getComponentFunction(component, func);
// If the user has supplied their own error handler, store it here. Else, set func to the returned function.
if (obj.type === 'customErrorHandler') {
customErrorHandler = obj.func;
} else {
func = obj.func;
}
}
// Now that we've built the callback chain, get the route handler, and attach it to the app.
var routeHandler = functionFactory.getRouteHandler(func, customErrorHandler);
route.method = route.method || 'get';
eval('app.' + route.method.toLowerCase() + '(route.path, routeHandler)');
console.log('Registered route: ' + route.path);
}
}
function initConfig () {
var configFile = cmndr.configFile;
var config = {};
try {
console.log('Loading config file: ' + configFile);
config = JSON.parse(fs.readFileSync(configFile, {encoding: 'utf8'}));
} catch (err) {
console.error('No config file found at: ' + configFile);
}
return config;
}
/**
* Create the app and start the listener
*/
function createExpressApplication (connector) {
console.log('Starting app on ' + connector.host + ':' + connector.port);
var app = express();
app.set('host', connector.host);
app.set('port', connector.port);
app.set('eventEmitter', new events.EventEmitter());
app.use(compression());
//app.use(morgan());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(methodOverride());
app.use(cookieParser());
app.disable('x-powered-by');
// set up some things we need for the app
app.use(enhanceRequest);
app.use(requestLogger);
app.listen(connector.port, function() {
console.log('App listening on ' + connector.host + ':' + connector.port);
});
return app;
}
/*
* Enhance the request and response objects with a few things.
*/
function enhanceRequest (req, res, next) {
// Create a space for joule-specific stuff
res.locals._joule = {};
res.locals._joule.vars = {};
res.setVariable = function (name, value) {
res.locals._joule.vars[name] = value;
};
res.getVariable = function (name) {
return res.locals._joule.vars[name];
};
res.setPayload = function (payload) {
res.locals._joule.payload = payload;
};
res.getPayload = function () {
return res.locals._joule.payload;
};
res.setError = function (err) {
res.locals._joule.deferred.reject(err);
}
// Get the passed-in params (for either GET, POST or route params), and make them available via req.getParam() and req.getParams()
var params = {};
if (req.method === 'POST') {
params = req.body;
} else if (req.method === 'GET') {
params = req.query;
}
req.getParam = function (name) {
return params[name] || req.params[name];
};
req.getParams = function () {
// add everything from req.params to params
for (var name in req.params) {
if (!params[name]) {
params[name] = req.params[name];
}
}
return params;
};
next();
}
/*
* Log start and end of all requests
*/
function requestLogger (req, res, next) {
var start = new Date();
console.log(req.method + ' ' + req.url + '; IP: ' + req.connection.remoteAddress + '; User-agent: ' + req.headers['user-agent']);
res.on('finish', function () {
var duration = new Date() - start;
console.log(req.method + ' ' + req.url + '; IP: ' + req.connection.remoteAddress + '; Execution time: ' + duration + ' ms');
});
next();
}
;