I'm working on my first NodeJS / Express application with the async module. It's been an uphill battle for me learning node (and even JavaScript) as I go along so I'm sure there's a lot of room for improvement.
I've written a GET event handler for my REST API and I'd like to know:
- Where and how to decompose this into smaller methods
- Areas where I can improve / simplify the logic
- How I can make this more understandable
Most of my colleagues have never written JavaScript and do not understand async programming. I realize that they'll have to do a lot of their own homework to learn.. but I'm also trying my best to communicate intent as clearly as possible in the code with my method names and comments.
The challenge I've had is with async.map calls. I'm not too sure if it's a good idea to call other functions within the async.map callback function so right now, as you can see, I have a lot of logic within the callback.
router.get('/:widgetnum', function(req, res, next) {
var widgetnum = req.params.widgetnum;
var pairs = {};
if ( !valid_widget(widgetnum) ) {
res.status(400).send("Invalid Widget");
return;
} else {
var keys = {};
redis.hkeys("widget:" + widgetnum, function(err, data){
if (err) {
winston.log('error', 'router.get() query to redis.hkeys() failed with err: ' + err);
res.status(500).send("Failure while querying HKEYS");
return;
}
console.log(data.length);
if (data) {
if (debug) {winston.log('info', 'router.get() query to redis.hkeys() returned : ' + data); }
current = getCurrentUTC(); // returns something like [ 1158, 't' ]
//create pairs with hash name and widget number, in addition to the results from HKEYS
pairs = data.map(function(ts) {
return ['widget:'+widgetnum, ts];
});
}
if (data.length > 1) {
if (debug) { winston.log('info', 'router.get(widgetnum) multiple keys found in hash. calling iterator') };
async.map(pairs, hash_iterator, function (err, iterator_results) { //async.map returns array of items.
if (err) {
winston.log('error', 'router.get() query to redis.hkeys() failed with err: ' + err);
res.status(500).send("Failure while querying HKEYS");
return;
}
if (debug) { winston.log('info', 'router.get() results from multi tc iterator query are ' + iterator_results); }
var tc_uri = '';
var default_uri = '';
for (var i = 0; i < iterator_results.length; i++) {
if (iterator_results[i] !== null) {
var tmp = iterator_results[i].split("~");
if (tmp[0].indexOf("00:00:00_00:00:00") != -1) {
default_uri = tmp[1];
} else {
tc_uri = tmp[1];
}
}
}
if (tc_uri.length > 0 ) {
res.send(JSON.stringify(tc_uri));
return;
} else {
res.send(JSON.stringify(default_uri));
return;
}
});
} else if (data.length == 1) {
if (debug) { winston.log('info', 'router.get(widgetnum) only one key found. calling default iterator'); }
async.map(pairs, default_iterator, function (err, iterator_results) {
if (err) {
winston.log('error', 'router.get() failure while trying to HGET default tc: ' + err);
res.status(500).send("Unable to query database for default rule");
return;
}
if (debug) { winston.log('info', 'router.get() results from default iterator query are ' + iterator_results); }
var tmp = iterator_results[0].split("~");
res.send(JSON.stringify(tmp[1]));
return;
});
} else if (data.length == 0) {
if (debug) { winston.log('info', 'router.get() query to HKEYS for widget ' + widgetnum + ' returned nothing ' ); }
res.status(404).send("Unknown widget");
return;
}
});
}
});