Removing duplicate error handling code Node.js - javascript

I have duplicated error handling code in my Node.js code, how can I make it better to get rid of duplicated code. I specifically want to ask error handling about this callback way, not the Promise way.
var request = require('request');
var URL = 'http://localhost:3000';
var getRanking = function get_rank(error, response, body) {
if (error) {
handleError(error);
} else {
if (response.statusCode != 200) {
handleError(response);
} else {
console.log('Response 1 ' + body);
request(URL + '/iso/country/' + JSON.parse(body).Country, getISO);
}
}
}
var getISO = function get_iso(error, response, body) {
if (error) {
handleError(error);
} else {
if (response.statusCode != 200) {
handleError(response)
} else {
console.log("Response 2 "+body);
request(URL+'/olympic/2016/medal/'+JSON.parse(body).iso,getMedalCount);
}
}
}
var getMedalCount = function get_medal_count(error, response, body) {
if (error) {
handleError(error);
} else {
if (response.statusCode != 200) {
handleError(response);
} else {
console.log("Response 3 " + body);
}
}
}
function handleError(err) {
console.log('Error ' + JSON.stringify(err))
}
request(URL+'/olympic/2016/ranking/4', getRanking);

Create a funciton handleResponse and write the response handling duplicated code in that funciton.
Call that function with required parameters as given,
var request = require('request');
var URL = 'http://localhost:3000';
var getRanking = function get_rank(error, response, body) {
handleResponse(error, response, body, 'getISO');
}
var getISO = function get_iso(error, response, body) {
handleResponse(error, response, body, 'getMedalCount');
}
var getMedalCount = function get_medal_count(error, response, body) {
handleResponse(error, response, body null);
}
function handleResponse(error, response, body, url) {
if (error) {
handleError(error);
} else {
if (response.statusCode != 200) {
handleError(response);
} else {
if(url == 'getISO')
{
request(URL + '/iso/country/' + JSON.parse(body).Country, getISO);
}
else if(url == 'getMedalCount')
{
request(URL+'/olympic/2016/medal/'+JSON.parse(body).iso,getMedalCount);
}
}
}
}
function handleError(err) {
console.log('Error ' + JSON.stringify(err))
}
request(URL+'/olympic/2016/ranking/4', getRanking);

You can try following code:
var request = require('request');
var URL = 'http://localhost:3000';
var getRanking = function get_rank(error, response, body) {
if (error) {
throw error;
}
if (response.statusCode != 200) {
throw new Error(response);
}
console.log('Response 1 ' + body);
request(URL + '/iso/country/' + JSON.parse(body).Country, getISO);
}
var getISO = function get_iso(error, response, body) {
if (error) {
throw error;
}
if (response.statusCode != 200) {
throw new Error(response);
}
console.log("Response 2 "+body);
request(URL+'/olympic/2016/medal/'+JSON.parse(body).iso,getMedalCount);
}
}
var getMedalCount = function get_medal_count(error, response, body) {
if (error) {
throw error;
}
if (response.statusCode != 200) {
throw new Error(response);
return;
}
console.log("Response 3 " + body);
}
try {
request(URL+'/olympic/2016/ranking/4', getRanking);
} catch(ex) {
console.log(ex);
}

Ok, as far as noone suggested such optimization, I will.
Instead of such block:
if (error) {
handleError(error);
} else {
if (response.statusCode != 200) {
handleError(response);
} else {
console.log("Response 3 " + body);
}
}
You can do this way:
if (error || response.statusCode != 200) handlerError(error || response);
else console.log("Response 3 " + body);

You can use following code to handle response.
var request = require('request');
var URL = "http://localhost:3000";
var getRanking = function get_rank (body) {
console.log("Response 1 " + body);
request(URL + '/iso/country/' + JSON.parse(body).Country, handleResponse.bind(null, getISO));
}
var getISO = function get_iso (body) {
console.log("Response 2 " + body);
request(URL + '/olympic/2016/medal/' + JSON.parse(body).iso, handleResponse.bind(null, getMedalCount));
}
var getMedalCount = function get_medal_count (body) {
console.log("Response 3 " + body);
}
function handleResponse (callback, error, response, body) {
console.log(error, response, body, callback)
if (error || response.statusCode != 200) {
console.log('Error ' + JSON.stringify(error))
}
else {
callback(body);
}
}
request(URL + '/olympic/2016/ranking/4', handleResponse.bind(null, getRanking));

The simpliest way to shorten your code would probably be the following :
function handleError(err, res) {
if(err){
console.log('Error '+JSON.stringify(err));
return false;
} else if(res.statusCode != 200) {
console.log('Error '+JSON.stringify(res));
return false;
} else {
return true;
}
}
// and then, use it in your functions like that :
var getRanking = function get_rank(error,response,body) {
if (handleError(err, res)) { // if there is no error, do your stuff
console.log("Response 1 "+body);
request(URL+'/iso/country/'+JSON.parse(body).Country,getISO);
}
}
But I think that's not very appropriate to JS, because JS can be used as a functional programming language (which is better) and this approach looks more procedural (like C language).
So, in my opinion, the below solution would be proper :
function handleError(successFunc) {
return function (error, response, body) {
if (error) {
throw new Error(error);
} else if(response.statusCode != 200) {
throw new Error(response);
} else {
successFunc(response);
}
}
}
// then, just pass your successFunc to your error handler :
var getRanking = function (response) {
// do your success stuff.
}
try {
request(URL+'/olympic/2016/ranking/4', handleError(getRanking));
} catch (e) {
// catch your error here
}
If your request is a success, getRanking will be executed, if this is a failure, the error will be logged and thrown.
With this solution, you can pass any function to your error handler and it will be used if the request succeed, if the request fails, the error handler will throw an error and then, you will be able to catch it.
Hope it helps,
Best regards

Related

HttpRequest Node.js "Cannot set property 'UNSENT' of undefined"

I have a problem, when I try to run a simple http request I always get an error message.
Cannot set property 'UNSENT' of undefined
var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
var xhr = new XMLHttpRequest();
XMLHttpRequest('https://example.firebaseio.com/.json',
function (error, response, body) {
if (!error && response.statusCode === 200) {
console.log(body);
}
}
);
How do I fix this problem?
I suggest you use the standard built-in NodeJS methods:
This code:
var http = require('http');
http.get('http://nodejs.org/dist/index.json', (res) => {
const statusCode = res.statusCode;
const contentType = res.headers['content-type'];
let error;
if (statusCode !== 200) {
error = new Error(`Request Failed.\n` +
`Status Code: ${statusCode}`);
} else if (!/^application\/json/.test(contentType)) {
error = new Error(`Invalid content-type.\n` +
`Expected application/json but received ${contentType}`);
}
if (error) {
console.log(error.message);
// consume response data to free up memory
res.resume();
return;
}
res.setEncoding('utf8');
let rawData = '';
res.on('data', (chunk) => rawData += chunk);
res.on('end', () => {
try {
let parsedData = JSON.parse(rawData);
console.log(parsedData);
} catch (e) {
console.log(e.message);
}
});
}).on('error', (e) => {
console.log(`Got error: ${e.message}`);
});
is taken from here
This will work.
var req = new XMLHttpRequest()
req.open('GET',url)
req.onload = function(){
if(req.status==200){
console.log(req.responseText)
}
else{
console.log(req.statusText)
}
}
req.onerror = function()
{
console.log('Network Error')
}
req.send()
})

Node Async - Working async method returns undefined inside async.parallel

Basically I have a method fetching values from an API and works, but inside async.parallel the results listed are all undefined.
Here's the method:
function getNumberOfSharesFromFacebookApi(url ,callback) {
request(facebookApiUrl + url + '&format=json', function (error, response, body) {
let res = 0;
if (!error && response.statusCode == 200) {
try {
res = JSON.parse(body)[0]['total_count'];
} catch(err) { }
}
callback(res);
});
}
Here's the async call:
async.parallel ([
callback => {
getNumberOfSharesFromFacebookApi(urlsToTest[0], callback);
},
callback => {
getNumberOfSharesFromFacebookApi(urlsToTest[1], callback);
},
callback => {
getNumberOfSharesFromFacebookApi(urlsToTest[2], callback);
},
callback => {
getNumberOfSharesFromFacebookApi(urlsToTest[3], callback);
}
],
(err, results) => {
console.log(results);
});
on your request function, place your response as the 2nd argument of the callback. request uses node style callbacks wherein the 1st argument is an error.
function getNumberOfSharesFromFacebookApi(url ,callback) {
request(facebookApiUrl + url + '&format=json', function (error, response, body) {
if(error) return callback(error); //callback on error
let res = 0;
if (!error && response.statusCode == 200) {
try {
res = JSON.parse(body)[0]['total_count'];
} catch(err) { }
}
callback(null, res);
});
}

Chaining multiple request using bluebird

I'm trying to convert my existing code using BlueBird, please suggest a best option to chain multiple request. Error happening in each callback needs to be redirected to rendered with different error.
request(option1, function (error, response, body) {
if (!error && response.statusCode == 200) {
var data= JSON.parse(body);
if(data.valid){
if(data.expired){
next();
} else {
request(option2, function (error2, response2, body2) {
var data2= JSON.parse(body2);
if(data2.valid) {
request(option3, function (error3, response3, body3) {
next();
})
} else {
res.json({error:'Error1'});
}
})
}
} else {
res.json({error:'Error2'});
}
} else {
res.json({error:'Error3'});
}
})
This is pretty straightforward, also note your current code doesn't handle errors in the second and third requests and this does:
var request = require("request-promise"); // request - converted to bluebird
request(option1).then(data=> {
if(!data.valid) throw Error("Error3");
if(data.expired) return;
return request(option2).then(JSON.parse);
}).then(data2 => {
if(!data2) return; // didn't need to fetch additional data
if(!data2.valid) throw Error("Error2");
return request(option3);
}).then(() => {
next();
}, e => {
res.json(error: e.message);
// better log this.
});
var rp = require('request-promise');
function handleError(err) {
res.json({
error: err.message
});
}
function parse(data) {
if (data) {
return JSON.parse(data);
}
}
rp(option1)
.then(parse)
.then(function (data) {
if (!data || !data.valid) {
throw Error('Error2');
}
if (data.expired) {
return;
}
return option2;
})
.then(rp)
.then(parse)
.then(function (data2) {
if (!data2 || !data2.valid) {
throw Error('Error1');
}
return option3;
})
.then(rp)
.then(parse)
.then(function () {
next();
})
.catch(handleError);
You don't need to manually check for statusCode but if you need to do so, first you have to add resolveWithFullResponse attribute to your option1 object, which allows you to receive the response object:
function checkStatusCode(response) {
if (response.statusCode !== 200) {
throw Error('Error3');
}
return response.body;
}
// add resolveWithFullResponse attribute to option1
option1.resolveWithFullResponse = true;
rp(option1)
.then(checkStatusCode)
.then(parse)
//...

Node JS: Request Loop Until Status Code 200

I currently have working code that does a request and checks if it receives a successful status code of 200. I would like to grow on this and loop it where it will keep sending requests until the status code is 200. I tried using a while loop but was not receiving the correct results. Thanks for the help!
request('http://0.0.0.0:9200', function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log('success');
do(something);
}
else {
console.log('fail');
}
});
Would be something like:
let retry = (function() {
let count = 0;
return function(max, timeout, next) {
request('http://0.0.0.0:9200', function (error, response, body) {
if (error || response.statusCode !== 200) {
console.log('fail');
if (count++ < max) {
return setTimeout(function() {
retry(max, timeout, next);
}, timeout);
} else {
return next(new Error('max retries reached'));
}
}
console.log('success');
next(null, body);
});
}
})();
retry(20, 1000, function(err, body) {
do(something);
});
You can set a max number of retries and a timeout between retries. So that you do not introduce an infinite loop, and you do not deliver the final punch to an overloaded request target ^^
I wanted a little more intuitive answer including promises. I build on top of miggs answer within a try/catch the code below with promises and axios.
Based on a simple example of recursive functions
const throwNumbers = (count = 0) => {
console.log(count);
if (count++ < 10) {
throwNumbers(count);
} else {
console.log('max reached');
};
};
You can put anything else on the try part and handle error codes in the catch part. You have to set a max number of retries, which is 10 in my case.
let getResponse = async(count = 0) => {
try {
const axiosResponse = await axios.get(someURL, {
params: {
parameter1: parameter1,
},
});
return axiosResponse;
} catch (error) {
if (error || error.status != 200) {
console.error('failed, retry');
if (count++ < 10) {
return getResponse(count);
} else {
throw new Error('max retries reached');
};
} else {
throw error;
};
};
};
You would call the function with the following and handle the body or whatever with the response value.
let response = await getResponse();
console.log('This is the response:', response);
Has no timeout but works for me.

How to recurse asynchronously over API callbacks in node.js?

An API call returns the next 'page' of results. How do I recurse over that result callback elegantly?
Here is an example of where I need to do this:
var url = 'https://graph.facebook.com/me/?fields=posts&since=' + moment(postFromDate).format('YYYY-MM-DD') + '&access_token=' + User.accessToken;
request.get({
url: url,
json: true
}, function (error, response, body) {
if (!error && response.statusCode == 200) {
_.each(body.posts.data, function (post) {
User.posts.push(post); //push some result
});
if (body.pagination.next) { // if set, this is the next URL to query
//?????????
}
} else {
console.log(error);
throw error;
}
});
I would suggest wrapping the call in a function and just keep calling it until necessary.
I would also add a callback to know when the process has finished.
function getFacebookData(url, callback) {
request.get({
url: url,
json: true
}, function (error, response, body) {
if (!error && response.statusCode == 200) {
_.each(body.posts.data, function (post) {
User.posts.push(post); //push some result
});
if (body.pagination.next) { // if set, this is the next URL to query
getFacebookData(body.pagination.next, callback);
} else {
callback(); //Call when we are finished
}
} else {
console.log(error);
throw error;
}
});
}
var url = 'https://graph.facebook.com/me/?fields=posts&since=' +
moment(postFromDate).format('YYYY-MM-DD') + '&access_token=' + User.accessToken;
getFacebookData(url, function () {
console.log('We are done');
});

Categories

Resources