Response object is not defined when passed in a function - node.js

I am using Facebook Graph NodeJS API to fetch user_posts. The response has pagination and therefore I need to loop over the response to fetch all the posts. I am using following route to fetch facebook posts and I am looping over pagination using get_user_statuses function:
var posts = "";
function get_user_statuses(response_posts, res) {
var link_regex = /https?:\/\/(?:www\.|(?!www))[^\s\.]+\.[^\s]{2,}|www\.[^\s]+\.[^\s]{2,}/g;
var isNextPageAvailable = true;
if ("paging" in response_posts) {
var nextPage = response_posts.paging.next;
isNextPageAvailable = true;
} else {
isNextPageAvailable = false;
}
for (var i = 0; i < response_posts.data.length; i++) {
var post = response_posts.data[i].message + " ";
if ("message" in response_posts.data[i]) {
posts += post.replace(link_regex, "");
}
}
if (nextPage !== undefined) {
request(nextPage, function (error, response, body) {
if (!error && response.statusCode === 200) {
get_user_statuses(JSON.parse(body));
} else {
console.log(error);
}
});
}
if (!isNextPageAvailable){
//Sending posts to facebook Modal
console.log(posts);
res.send(JSON.stringify({posts: posts})); //res is not defined here
}
}
router.post('/fbData', function (req, response, next) {
FB.setAccessToken(req.body.access_token);
FB.api('/me?fields=posts&posts.limit=1000', function (res) {
if (!res || res.error) {
if (!res) {
response.send(JSON.stringify({error: 'An error occurred. Please try again.'}))
}
response.send(JSON.stringify({error: response.error}));
return;
}
get_user_statuses(res.posts, response); //Passing response object here
});
});
The issue is that response object passed from express route is not defined in get_user_statuses function. Now I have two question:
Why is response object is not defined?
Is there better approach to achieve this arrangement?

res is not defined because you forgot to pass it in internal call. Change get_user_statuses(JSON.parse(body)); to get_user_statuses(JSON.parse(body), res); and it should work

I solved my problem. I needed to create a function with a callback. In case anyone else is stuck at this kind of issue, this post helped me resolve it:
[How to recurse asynchronously over API callbacks in node.js?

Related

How can I save HTTP GET Response to a var using Express (nodejs)?

I am using Express in Nodejs in order to make a GET Call. As a response, I get the value that I need, but when I return the value from my function to the main I get undefined.
function getInfo()
{
var oauth = getoAuth();
request.get({
url:'myurl',
oauth:oauth,
qs:null,
json:true
},
function (e, r, data) {
body.data = data;
body.emit('update');
});
body.on('update', function () {
console.log(body.data.issues[0].key);
return (body.data.issues[0].key);
});
}
This key is what I need. When I print it in the console I get the correct value, but it doesn't return anything, because it is an async call. How can I return the value? Can I somehow wait for the value using express? I saw on stackoverflow that some people used this body.on('update'... solution, but it didn't work for me. It still saves nothing to a variable.
EDIT-> the response:
TESTING: undefined
THEKEY1
Saving the value at:
var myid= geInfo();
try this way :
function getInfo()
{
var oauth = getoAuth();
request.get({ url:'myurl', oauth:oauth, qs:null, json:true},
function (error, response, body) {
if(!error && response && response.statusCode==200){
console.log(body);
return body.data.issues[0].key;
}else{
return null;
}
});
}

Can't get past HTTP request in Node

So, here is the problem. I found how to do http request in Node.js, so that I could download and parse remote JSON file. It all works fine but nothing happens after that. I have a function and in that there is if condition that doesn't get executed. It simply cannot get past the http request. Is there something I am missing?
var remoteStamp;
if (typeof force == "undefined") {
var timeurl = "http://" + parsedconfig.weburl + "/timestamp.json";
request(timeurl, { json: true }, (err, res, body) => {
if (err) { return console.log(err); }
console.log(body.timestamp);
remoteStamp = body.timestamp;
});
}
if (remoteStamp < parsedconfig.timestamp || force == "local") {
//something should happen here, all the values check out - still nothing happens
}
you are using callback so all the code which you want to execute after request is completed should be inside the callback
var remoteStamp;
if (typeof force == "undefined") {
var timeurl = "http://" + parsedconfig.weburl + "/timestamp.json";
request(timeurl, { json: true }, (err, res, body) => {
if (err) { return console.log(err); }
console.log(body.timestamp);
remoteStamp = body.timestamp;
if (remoteStamp < parsedconfig.timestamp || force == "local") {
//something should happen here, all the values check out - still nothing happens
}
});
}
Or you can use request-promise library to do this in promises. https://github.com/request/request-promise
On how to use promises: https://developers.google.com/web/fundamentals/primers/promises

Gather POST data asynchronously

I've got a node.js-based webserver running at home and i'm trying to implement a login form.
So basically I need to access POSTed data (login/password). I found this :
How do you extract POST data in Node.js?
(req.on('data'...) & req.on('end'...))
But i need to do this asynchronously, can someone tell me how to do that ?
(I need this code to be blocking, not non-blocking)
EDIT: All my code is available on Github :
https://github.com/Fointard/NodeJs/tree/authentication
The problem lies here : https://github.com/Fointard/NodeJs/blob/authentication/js/reqHandlers/auth.js Lines 98 and 104, i'm relying on 'data' and 'end' envents but i'd like to do that asychronously so that checkID() (line 95) is able to return true or false.
You can't. HTTP Requests are I/O operations and will always be resolved asychronously. Your checkID function will never return a value. You need to add a second parameter (usually called callback) that will be called with true or false.
function checkID(req, callback) {
var body = '';
req.on('data', function (data) {
body += data;
if (body.length > 1e6)
req.connection.destroy();
});
req.on('end', function () {
var post = qs.parse(body);
if ('loginInputLogin' in post && 'loginInputPassword' in post) {
console.log('login : '+post['loginInputLogin']);
console.log('password : '+post['loginInputPassword']);
}
if (post['loginInputLogin'] === 'fointard' && post['loginInputPassword'] === 'f01n') {
console.log('ID confirmed');
callback(true);
}
callback(false);
});
}
And use it like so:
checkID(yourRequest, function(success) {
if(success) {
//login successfull
} else {
//login failed
}
})

Mongoose Async Call Issue with Find Query

I have var movieRecommendation which is being populated from data coming from Mongo DB. Issue is Mongoose Movie.findOne() call is asycn call which is not allowing me to get my final populated movieRecommendation which I need to send back as response.
exports.getRecommendation=function(req,res){
var movieRecommendation = [];
var id=req.params.id;
console.log('----- Get User Recommendation - ' + id);
var url = 'http://52.8.48.113:8080/recommender-server/recommender/v1/recommendations/'+id+'.do';
//make http get request
request({
url: url,
json: true
}, function (error, response, recommendations) {
// res.json(recommendations);
if (!error && response.statusCode === 200) {
recommendations.forEach(function(entry) {
**Movie.findOne({'id':parseInt(entry.itemId)},function(err, movieData){**
entry.movie = movieData;
movieRecommendation.push(entry);
//console.log('rec', movieRecommendation);
console.log(movieRecommendation.length);
});
});
}
console.log("====Final========"+movieRecommendation.length);
//Output = 0
});
res.json(movieRecommendation); // Here movieRecommendation is coming as black Array
};
Please let me know how I can get finally populated movieRecommendation var at end to make it available for response.
For this type of issues we can use Async library. To populate the data finally once all the operations done, we can use async.each collection from Async Library.
For example:
NOTE:Install Async by this command
npm install async to use async library
var async = require("async");
var recomenmendations = [{"data2" : "value2"} , {"data1" : "value2"}, {"data3" : "value3"}, {"data4" : "value4"} ]
var movieRecommendation = [];
async.each(recomenmendations,
function(recomenmendationItem, callback){
console.log("Here you can query the required data using current recomenmendations ITEM");
console.log(recomenmendationItem);
callback();
// Movie.find({'id':parseInt(recomenmendationItem.itemId)},function(err, movieData){
// recomenmendationItem.movie = movieData;
// movieRecommendation.push(entry);
// callback();
// });
},
function(err){
console.log("here you can send your resopnse");
console.log("This section will be executed once all the recomenmendations are processed");
//res.json(movieRecommendation)
}
);
You can query the mongoDB as shown with comment section. You should use callback() once all the operations performed for an iteration.
As I mentioned in one of my comments, use the callback passed to the iterator function and call it inside the Movie.findOne() callback. That way, async.each will know when each step has finished:
async.each(recomendations, function (recomendationItem, callback) {
Movie.findOne({'id':parseInt(entry.itemId)},function(err, movieData){
if (err) return callback(err); // if you have an error on you search, just pass it to the iterator callback
recommendationItem.movie = movieData;
movieRecommendation.push(recommendationItem);
callback();
});
}, function (error) {
if (error) return res.json ({ error: error }); // you should also check if an error ocurred
res.json(movieRecomendation);
});
Just to point out: you can also use async.eachSeries, that will just call the next step of your iteration when the previous one has returned (if that matters to you, but I think it's not your case though) and it has the same signature.
#Vivek Panday replace the following code inside your exports.getRecommendation function to get your expected output. We don't need to use the count variable if we use the callback function. And an important thing is we have to use callback(); once all the process done. I think you have not used callback function properly in The example you have worked out. Use the following code If there is any issue please let me know.
var async = require('async');
var request = require("request");
var movieRecommendation = [];
var id=req.params.id;
console.log('----- Get User Recommendation - ' + id);
var url = 'http://52.8.48.113:8080/recommender-server/recommender/v1/recommendations/'+id+'.do';
//make http get request
request({
url: url,
json: true
}, function (error, response, recommendations) {
if (!error && response.statusCode === 200) {
console.log('recommendation lenght '+ recommendations.length);
async.each(recommendations,
function(recommendationItem, callback){
Movie.findOne({'id':parseInt(recommendationItem.itemId)},function(err, movieData){
recommendationItem.movie = movieData;
movieRecommendation.push(recommendationItem);
//you have to use callback(); once all your process is done
callback();
});
},
function(err){
//you should use this function, this will be execute once all the process done
console.log(movieRecommendation);
console.log("finally callback");
res.json(movieRecommendation);
}
);
}
});
I have tried as per given suggestion above ..
var async = require("async");
var recomenmendations = [{"data2" : "value2"} , {"data1" : "value2"}, {"data3" : "value3"}, {"data4" : "value4"} ]
var movieRecommendation = [];
async.each(recomenmendations,
function(recomenmendationItem, callback){
console.log("Here you can query the required data using current recomenmendations ITEM");
console.log(recomenmendationItem);
// Movie.find({'id':parseInt(recomenmendationItem.itemId)},function(err, movieData){
recomenmendationItem.movie = movieData;
movieRecommendation.push(entry);
console.log("any data"); // line y
});
callback();
},
function(err){
console.log("here you can send your resopnse"); // line x
console.log("This section will be executed once all the
recomenmendations are processed");
//res.json(movieRecommendation)
}
);
But still face same issue line x is printing before line y ,which is making again same issue.
However I have tried something given below and achieved expected result .
exports.getRecommendation=function(req,res){
var movieRecommendation = [];
var id=req.params.id;
console.log('----- Get User Recommendation - ' + id);
var url = 'http://52.8.48.113:8080/recommender-server/recommender/v1/recommendations/'+id+'.do';
//make http get request
request({
url: url,
json: true
}, function (error, response, recommendations) {
// res.json(recommendations);
if (!error && response.statusCode === 200) {
console.log('recommendation lenght '+ recommendations.length);
// recommendations.forEach(function(entry) {
var count=0;
async.each(recommendations,function(recommendationItem){
// console.log(recommendationItem);
Movie.findOne({'id':parseInt(recommendationItem.itemId)},function(err, movieData){
recommendationItem.movie = movieData;
movieRecommendation.push(recommendationItem);
count ++;
console.log('final res length : ' + movieRecommendation.length);
console.log('final res length count : ' + count +' and item recomm lenght ' + recommendations.length );
if(count === recommendations.length){
console.log(' =====Final=====> here you can send your response =========' + movieRecommendation.length);
res.json(movieRecommendation);
}
});
// callback();
});
}
});
};
Still I am open for any feedback and suggestions.

Node.js - "data" event does not always fire for certain requests

I am implementing an IFTTT Action using Node.js. Node.js is version 0.10.29 running on Windows Server 2012 R2.
I am trying to read the body of a POST that is coming from IFTTT. The 'data' event is not firing. Only the 'readable' event is firing. No other events such as 'end' are firing.
However, if I simulate the same POST request using curl, from another server, this code works great.
Also, if I place Fiddler on my server in between IFTTT and my Node.js, it works great.
The request coming from IFTTT looks great in Fiddler, and when Fiddler "processes" it somehow, the Node.js code can read it.
What could be the issue?
var s = http.createServer(process_request);
s.listen(8080);
function process_request(req, res) {
req.parsed_url = url.parse(req.url, true);
var core_url = req.parsed_url.pathname;
if (core_url == '/ifttt/v1/status' && req.method.toLowerCase() == 'get') {
// do stuff required for their test
}
else if (core_url == '/ifttt/v1/test/setup' && req.method.toLowerCase() == 'post') {
// do stuff required for their test
}
else if (core_url == '/ifttt/v1/actions/my_action' && req.method.toLowerCase() == 'post') {
if (<the channel key matches>) {
var json_body = "";
req.on('readable',function () { console.log("In callback for readable ");});
req.on('end', function (data) { console.log("In callback for end: " + json_body); });
req.on('close', function (data) { console.log("In callback for close ");});
req.on('error', function (data) { console.log("In callback for error "); });
req.on('data',
function (chunkdata) {
console.log("In callback for data ");
if (chunkdata) {
if (typeof chunkdata == 'string') { json_body += chunkdata; }
else { console.log("data: No chunkdata "); }
}
};
)
}
} // action url
} // function process_request
Update: I rewrote this code using Express and the problem did not reappear.

Resources