Thursday, December 18, 2014

Using Q promises with node.js http requests

This post is intended at providing a code snippet on how to use Q promises with node.js http requests.

I was introduced to the concept of promises and deferred when I found myself uncomfortable writing asynchronous functions within callbacks.

The code is not:
1. Maintanable
2. Readable
3. Intuitive

That is when I stumbled on JQuery Deffered and Promises. Once I got a hang of it I came across the Q Library that does pretty much the same thing with node.js.

I found it difficult to apply it to node.js http requests and after I gave it more time I got a hang of it.

The following gist demonstrates on how to wrap the the node.js http request with the q library.

In the gist we are attempting to invoke the Google News API using the node.js http requests.


//import the http library
var http = require('http'),
//npm install q before requiring it
Q = require('q');
//a js object with options
var googleNewsOptions = {
hostname: 'ajax.googleapis.com',
path: '/ajax/services/search/news?v=1.0&q=nodejs',
method: 'GET'
};
/**
* wrapper for http request object
* @param {Object} requestOptions
* @return Promise Object
*/
function promisedRequest(requestOptions) {
//create a deferred object from Q
var deferred = Q.defer();
var req = http.request(requestOptions, function(response) {
//set the response encoding to parse json string
response.setEncoding('utf8');
var responseData = '';
//append data to responseData variable on the 'data' event emission
response.on('data', function(data) {
responseData += data;
});
//listen to the 'end' event
response.on('end', function() {
//resolve the deferred object with the response
deferred.resolve(responseData);
});
});
//listen to the 'error' event
req.on('error', function(err) {
//if an error occurs reject the deferred
deferred.reject(err);
});
req.end();
//we are returning a promise object
//if we returned the deferred object
//deferred object reject and resolve could potentially be modified
//violating the expected behavior of this function
return deferred.promise;
};
//incoking the above function with the request options
promisedRequest(googleNewsOptions)
.then(function(newsResponse) { //callback invoked on deferred.resolve
console.log(JSON.stringify(newsResponse));
}, function(newsError) { //callback invoked on deferred.reject
console.log(newsError);
});