ExpressJS - Using Q - node.js

For a certain route, I have the following code:
router.get('/:id', function(req, res) {
var db = req.db;
var matches = db.get('matches');
var id = req.params.id;
matches.find({id: id}, function(err, obj){
if(!err) {
if(obj.length === 0) {
var games = Q.fcall(GetGames()).then(function(g) {
console.log("async back");
res.send(g);
}
, function(error) {
res.send(error);
});
}
...
});
The function GetGames is defined as follows:
function GetGames() {
var url= "my-url";
request(url, function(error, response, body) {
if(!error) {
console.log("Returned with code "+ response.statusCode);
return new Q(body);
}
});
}
I'm using the request module to send a HTTP GET request to my URL with appropriate parameter, etc.
When I load /:id, I see "Returned with code 200" logged, but "async back" is not logged. I'm also not sure that the response is being sent.
Once GetGames returns something, I want to be able to use that returned object in the route for /:id. Where am I going wrong?

Since GetGames is an async function write it in node.js callback pattern:
function GetGames(callback) {
var url= "my-url";
request(url, function(error, response, body) {
if(!error) {
console.log("Returned with code "+ response.statusCode);
return callback(null,body)
}
return callback(error,body)
});
}
Then use Q.nfcall to call the above function and get back a promise:
Q.nfcall(GetGames).then(function(g) {
})
.catch()

Related

how to run a GET or POST method sequentially in node.js

here is the code of index.js file
var request = require('request');
var requestHandling = require('../routes/request_handling_functions');
router.get("/example1", function (req, res) {
var result =
requestHandling.requestMethodGet('http://localhost:8083/getUserInfo/865c2c25-
d9e7-412d-a064-326bd66c9e9c', res);
console.log("===RESULT=====");
console.log(result);
});
in above code I want that function requestMethodGet return the result into result variable then I manipulate the result according to my need then show to user and also I am console my return result.
but here is the problem with it because Node.js is asynchronous language so first it print the result then it call the function requestMethodGet that is so irritating.
Here is the code of requestMethodGet
requestMethodGet: function (url, res) {
//SET ALL THESE PARATMETER TO MAKE REQUEST
request.get({url: url}, function (e, r, body) {
var errorResult = module.exports.validateResponseeData(e);
console.log("====errorResult===in===Get==method====");
console.log(errorResult);
if (errorResult != "continue") {
console.log("===im in not continue");
return errorResult;
} else {
//LOGING THE RESPONSE BODY
log.info('body:', body);
var responseData = JSON.parse(body);
console.log("======RESPONSE=========DATA=====================");
console.log('error:', e);
console.log('statusCode:', r && r.statusCode);
console.log('body:', body);
console.log("====================================");
console.log(responseData);
return responseData;
}
});
}
I want that the router get method run the code in the sequence as the code write. but I search it everywhere I not found the any solution so come here to find my solution.
if any information is needed to solve this question then please inform me.
Try the following. It returns a promise from your requestMethodGet function and you then wait until that is resolved before logging the response. I suggest you read more on Promises to understand how this works.
requestMethodGet: function (url, res) {
return new Promise((resolve,reject) => {
//SET ALL THESE PARATMETER TO MAKE REQUEST
request.get({url: url}, function (e, r, body) {
var errorResult = module.exports.validateResponseeData(e);
console.log("====errorResult===in===Get==method====");
console.log(errorResult);
if (errorResult != "continue") {
console.log("===im in not continue");
reject(errorResult);
} else {
//LOGING THE RESPONSE BODY
log.info('body:', body);
var responseData = JSON.parse(body);
console.log("======RESPONSE=========DATA=====================");
console.log('error:', e);
console.log('statusCode:', r && r.statusCode);
console.log('body:', body);
console.log("====================================");
console.log(responseData);
resolve(responseData);
}
});
});
}
//INDEX.js
router.get("/example1", function (req, res) {
requestHandling.requestMethodGet('http://localhost:8083/getUserInfo/865c2c25-
d9e7-412d-a064-326bd66c9e9c', res).then((result) => {
console.log("===RESULT=====");
console.log(result);
}).catch((err) => {
console.log("===Error=====");
console.log(err);
});
});
you can use Promise or async/await

Error: Can't set headers after they are sent in loop multiple request

i'm beginner at nodejs, i got a problem when request multiple url in a loop then i render it.
Error: Can't set headers after they are sent.
at validateHeader (_http_outgoing.js:491:11)
at ServerResponse.setHeader (_http_outgoing.js:498:)
router.get('/', function(req, res, next) {
setInterval(function(){
request(url1,function (error,response,body) {
var data1 = JSON.parse(body);
request(url2+data1.access_token,function (error,response,body) {
var data_info = JSON.parse(body);
//error when it render
res.render('index', {data_info : data_info});
})
})
},5000);
});
That's not exactly a loop, I understand you mean that you call the same function repeteadly with setInterval().
Once you've sent your first response with res.render(), which finishes the response process for that request, subsequent attempts to use that res object fail.
If you want to send data to the client in 5 seconds interval you should probably either look into websockets or pass the setInterval() calls to the client so it polls your server each 5 seconds, in which case your server code could be changed to:
router.get('/', (req, res) => {
request(url1, (error, response, body) => {
const data1 = JSON.parse(body);
request(`${url2}${data1.access_token}`, (error, response, body) => {
const data_info = JSON.parse(body);
res.render('index', { data_info });
});
});
});
You can make use of Async Module
const async = require('async');
router.get('/', function (req, res, next) {
async.waterfall([
function(callback) {
request(url1, function (error,response,body) {
if(err) {
callback(err)
}else {
var data1 = JSON.parse(body);
callback(data1)
}
})
},
function(data1, callback) {
request(url2+data1.access_token, function(error,response,body) {
if(err) {
callback(err)
}else {
var data_info = JSON.parse(body);
callback(null, data_info)
}
})
}
], function(err, result) {
if(err) {
res.json({success: false, error: err, message: "Something went wrong.!"})
}else {
res.render('index', {
data_info : result
});
}
})
})

Express - Nodejs external rest api call

I want to make a backend call to an external api's and populate my page with the results. What is the best way to do this?
The "request.get" call is asynchronous, so I understand the code below is erroneous. However, I have written it in that fashion so that I can explain what I want to actually do.
Further, I may have 5-6 external api, is there a way to make this asynchronous for every api but synchronous get call?
This is how my current code looks like:
var express = require('express');
var request = require('request');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
var body = getRawApiResponse("someURL");
console.log("Index >" + body);
res.render('index', { title: 'Express', api: "some", body: body});
});
function getRawApiResponse(api){
request.get({
uri: api,
},
function(error, response, body){
if (!error && response.statusCode === 200) {
console.log("Index > Raw Api Response: " + body);
} else {
console.log(error);
}
});
}
You can wrap getRawApiResponse() in a promise
function getRawApiResponse(api){
return new Promise(function(resolve, reject){
request.get({
uri: api,
},
function(error, response, body){
if (!error && response.statusCode === 200) {
resolve(body)
} else {
reject(error)
}
});
});
}
which resolves on success and rejects in case of an error then you can chain it inside the get request like
router.get('/', function(req, res, next) {
getRawApiResponse("someURL")
.then(function(body){
res.render('index', { title: 'Express', api: "some", body: body});
})
.catch(err){
// do something
}
});
Look into Promises or async/await. You can use them to call your async apis and wait for the response making the call synchronous.
http://bluebirdjs.com/docs/getting-started.html
A Sample code of async/ await which u can modify for ur purpose is as below:
try{
let orderDetails = await MongoHelper.findOneByCriteria(MongoCollections.ORDER,searchCriteria);
}catch(err){
return err;
}
MongoHelper.findOneByCriteria = (collectionName, criteria) => {
return new Promise((resolve, reject) => {
db.collection(collectionName).find(criteria).toArray()
.then((results) => {
if (results.length > 0) {
resolve(results[0]);
} else {
resolve(null);
}
});
});
}
The best way is to use Promises to avoid callbacks hell. If you can use node.js v7.6 or higher, it could be much easier with async/await.
router.get('/', function(req, res, next) {
getRawApiResponse("someURL")
.then(body => {
console.log("Index >" + body);
res.render('index', { title: 'Express', api: "some", body: body});
});
});
function getRawApiResponse(uri) {
return new Promise((resolve, reject) => {
request.get({ uri }, (error, response, body) => {
if (err) {
reject(err);
}
resolve(body);
});
});
}
In the example about I use promisification to return a promise from getRawApiResponse, but there is already a module which do the same https://github.com/request/request-promise.

NodeJS Async - Continue execution for multiple http requests even if some fail

I am trying to make multiple HTTP requests and cumulate, display the results in NodeJS using the following code:
const async = require('async');
const request = require('request');
function httpGet(url, callback) {
const options = {
url : url,
json : true
};
request(options,
function(err, res, body) {
console.log("invoked")
callback(err, body);
}
).on('error', function(err) {
console.log(err)
});
}
const urls= [
"http://1.2.3.4:30500/status/health/summary",
"http://5.6.7.8:30505/status/health/summary"
];
async.map(urls, httpGet, function (err, res){
if (err)
console.log(err);
else
console.log(res);
});
The problem here is, if the first request(http://1.2.3.4:30500/status/health/summary) fails (like connection refused etc.), the second one does not go through. I know that I am making a silly mistake but cannot find it. Any help appreciated !
In async.map if one of the calls passes an error to its callback, the main callback (for the map function) is immediately called with the error(this is the problem in your case). In order not to terminate on the first error, don't call the callback with err param in your httpGet.
Use async each, it receives a list of arguments and a function, and calls the function with each element, make sure in your httpGet inside on error you call the callback, without the err, this will make rest of the calls to continue even if there was an error in some of the calls. This can work for map too but, I think the more suitable function for your case is async.each, instead of map, also you can limit the number of concurrent calls with eachLimit method.
Check https://caolan.github.io/async/docs.html#each
const async = require('async');
const request = require('request');
function httpGet(url, callback) {
const options = {
url : url,
json : true
};
request(options,
function(err, res, body) {
if (err){
console.log(err);
callback();
return;
}
console.log("invoked")
callback(null, body);
}
).on('error', function(err) {
console.log(err);
callback();
});
}
const urls= [
"http://1.2.3.4:30500/status/health/summary",
"http://5.6.7.8:30505/status/health/summary"
];
async.each(urls, httpGet, function (err, res) {
}, function (err, res) {
});
If you want async.map NOT to fail fast you could do it like this
const async = require('async');
const request = require('request');
function httpGet(url, callback) {
const options = {
url : url,
json : true
};
request(options,
function alwaysReportSuccess(err, res, body) {
callback(null, {
success: !err,
result: err ? err : body
});
}
).on('error', function(err) {
console.log(err)
});
}
const urls= [
"http://1.2.3.4:30500/status/health/summary",
"http://5.6.7.8:30505/status/health/summary"
];
async.map(urls, httpGet, function alwaysOk(_, res){
console.log(res); // will be an array with success flags and results
});

Unable to return body of request method in nodejs

I'm trying to get a JSON response via the request method and return the output so that i can store it in a variable when the function is called. when i log the response within the request method, it works fine. However when i return the output, it doesn't return.
var getAPIresponse = function(url) {
var request = require('request');
request(url, function(error, response, body) {
if(!error && response.statusCode == 200) {
console.log(body); // WORKS PERFECTLY
return body; // I Believe the issue is here
} else {
console.log("Error: "+ error);
}
});
};
router.get('/', function (req, res) {
var poolList = getAPIresponse("www.addAURL");
console.log(poolList); // DOESN'T WORK. REPORTS AS UNDEFINED
res.render('index', model); // THIS IS JUST SAYS HELLO WORLD
});
What your method actually does is run the following two lines
var request = require('request');
request(url, function(error, response, body) {
...and then fall out of the function right away at which point your calling code gets undefined back. The callback isn't called until the request is done, which may be much later.
To make it work, your function needs a callback too that is called when the function is actually complete, something like;
var getAPIresponse = function(url, cb) {
var request = require('request');
request(url, function(error, response, body) {
if(!error && response.statusCode == 200) {
console.log(body); // WORKS PERFECTLY
} else {
console.log("Error: "+ error);
}
cb(error, body);
});
};
router.get('/', function (req, res) {
var poolList = getAPIresponse("www.addAURL", function(err, poolList) {
// This is run in a callback once the request is done.
console.log(poolList);
res.render('index', model);
});
});
Another way would be to use promises which can clean up the code somewhat when the number of callbacks is getting out of hand.

Resources