Node http module - node.js

I am currently stumped with a problem, where the http.request() just fails/skips to make a request to a given url. I have the following setup
async.waterfall([
firstFunc,
secondFunc,
thirdFunc
], function last(err, result){});
The thirdFunc is where i am making a request and it looks like the following
function thirdFunc(payload, callback){
var responseFromCS = getData(payload);
callback(null, responseFromCS);
}
The getData function looks like the following
function getData(obj){
var curlttogetdata = csConstants.BasePath + csConstants.account_num;
var accountNum = obj.customer.accountnum;
var resData = null;
curlttogetdata = curlttogetdata.replace('${accntNum}', accountNum);
var getData = {
hostname: csURLHost,
path: curlttogetdata,
method:'GET',
headers: {
'X-consumer-id': csConstants.ConsumerIDHeader,
'Content-Type':'application/json'
}
};
var req = http.request(getData, function (res){
var body = '';
res.on('data', function getData(chunk){
body += chunk
});
res.on('end', function parseData(){
try {
resData = JSON.parse(body);
}catch(err){
resData = false;
}
});
});
req.on('error', function csResponseError(err){
resData = false;
});
req.end();
return resData;
}
Now upon debugging, once the debugger reaches http.request(...) it fails to step into callback or make the request and then steps right into req.end(). There is no error returned back. I have looked at my parameters in the getData object a number of times and everything looks fine. Even tested this with a curl and gives back the expected response.

one thing I see immediately is that you are returning resData as if it was a synchronous execution, meaning the httpRequest comes back after resData gets returned from your getData function, which will be null at that point
basically
when your program is executing
it does this
1 -makes http request,
2 -returns resData which is null (because the function executes until the end without stopping)
3 -the http request comes back and now resData has value but your function has already returned
what you need to do is pass a callback function
instead of
var responseFromCS = getData(payload);
you do getData(payload, function(responseFromCS){
//..... do something with the returned data
});

Ok so i believe i know the reasoning behind this. The 'http' node module is an async operation and the function getData that handles this, which is wrapped under thirdFunc in the async operation. I believe this operation gets executed before getData can respond.
So i moved the http.request() into thirdFunc and it works as expected.

Related

Get the result outside of the http call

In our project, we make a call to a REST web service with Node using HTTP request. We can see the result when we log it into the console. But we would like to store it or use it outside of the HTTP request. How can we achieve that?
var http = require('http');
var options = {
host: 'http:\\example.com',
port: 80,
path : '/site/status?tag=A7351&date=09JAN&name=LASTNAME',
method : 'GET'
};
var result;
http.request(options, function(res){
var body = '';
res.on('data', function (chunk) {
body += chunk;
});
res.on('end', function () {
result = JSON.parse(body);
console.log(result, "INSIDE"); //Shows the JSON result
});
}).end();
console.log(result, "OUTSIDE"); //Shows Undefined
The result is in this format:
{
error: 0,
statut: 'STATUTTTTT',
origine: 'PLACEEE',
destination: 'PARIS',
onwardDate: null
}
We need to be able to get the result outside of the HTTP call.
The issue is that you're making an asynchronous call, but not handling it correctly. Dialogflow's library requires that when you make an async call you return a Promise.
The easiest solution is for you to switch from using the request library to using the request-promise-native library and to return the Promise.
See other answers on Stack Overflow for examples and more information.

Cloudinary api - resolve promise

I want to write a function that returns a Boolean indicating whether an image with the specified public_id already exists in my Cloudinary space.
I can log the result to the console with the following code:
function isUploaded(public_id) {
cloudinary.api.resource(public_id, function(response){
console.log(response.hasOwnProperty('public_id'));
});
};
isUploaded('test');
However, I want to pass on the result, the Boolean, to another function. Using a return statement results in { state: 'pending' } being logged:
function isUploaded(public_id) {
return cloudinary.api.resource(public_id, function(response){
return response.hasOwnProperty('public_id');
});
};
console.log(isUploaded('test'));
This is has something to do with javascript Promises. I can't seem to restructure my code to make it work though. Any help would be much appreciated.
The problem is that cloudinary.api.resource runs asynchronously (which is why it requires a callback function).
You can make your isUploaded function return a Promise that resolves once that callback is called.
var cloudinary = require('cloudinary');
function isUploaded(public_id) {
return new Promise(function (resolve, reject) {
cloudinary.api.resource(public_id, function(response) {
var isUploaded = response.hasOwnProperty('public_id');
resolve(isUploaded);
});
});
};
isUploaded('test')
.then(function (result) {
console.log(result);
})
Note that api.resource() is rate limited (part of the Admin API) so this is not a "scalable" solution.
You can perform a HEAD request and get the statusCode of the response - 200 means the resource exists in your account, 404 otherwise.
For example -
var http = require('http')
var options = {method: 'HEAD', host:'res.cloudinary.com',path:'/<cloud_name>/image/upload/<yourimage.jpg>'}
var req = http.request(options, function(res) {console.log(res.statusCode);});
req.end();

NodeJS API makes nested http get request and return response

I have a NodeJS API. The logic in the API needs to make an http get request to google.com, capture the response from google.com, and then return the html response to the original API call. My problem is capturing the http response from google asynchronously and returning it to the original API call.
// Entry point to /api/specialday
module.exports = function(apiReq, apiRes, apiNext) {
var options = {
host: 'www.google.com'
};
callback = function(googleRes) {
var str = '';
// another chunk of data has been recieved, so append it to `str`
googleRes.on('data', function (chunk) {
str += chunk;
});
// capture the google response and relay it to the original api call.
googleRes.on('end', function () {
apiRes.send(str);
});
}
http.request(options, callback).end();
}
The error I get here is Uncaught TypeError: Cannot read property 'send' of undefined. I understand why I'm getting the error (because apiRes is out of scope), I just can't figure out how to do it right. Any help much appreciated!
The reason you are seeing the above error is because the original response object apiRes is gone by the time you have received the response from the google API.
As far as I can tell you will have to bind() the apiRes twice (untested):
callback = function(googleRes) {
var str = '';
// another chunk of data has been recieved, so append it to `str`
googleRes.on('data', function (chunk) {
str += chunk;
});
// capture the google response and relay it to the original api call.
googleRes.on('end', function () {
apiRes.send(str);
}.bind(apiRes));
}.bind(apiRes)
A more modern solution would be to use promises for this task https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise
Promises, that's it! Thanks Michal. Below is a simplified version of my implementation.
// Entry point to /api/specialday
module.exports = function(apiReq, apiRes, apiNext) {
var p1 = new Promise(
// The resolver function is called with the ability to resolve or
// reject the promise
function(resolve, reject) {
var options = {
host: 'www.google.com'
};
callback = function(googleRes) {
var str = '';
// another chunk of data has been recieved, so append it to `str`
googleRes.on('data', function (chunk) {
str += chunk;
});
// capture the google response and relay it to the original api call.
googleRes.on('end', function () {
resolve(str);
});
}
http.request(options, callback).end();
)};
p1.then(function(googleHtml) {
apiRes.status(200).send(googleHtml);
}
}
Then I can run my app and call the api using Postman at http://localhost:8080/api/gains:
Directly pipe output with apiRes, sample using request :
var request = require("request");
// Entry point to /api/specialday
module.exports = function(apiReq, apiRes, apiNext) {
request.get('http://www.google.fr').pipe(apiRes);
});

how to use nodejs async module?

This is a different question and I am unable to get a solution for this, please do not mark it duplicate.
I cannot access variable op outside the function. Should I be using a async module of nodjes?
I have two console.logs. But only inside function log works.
I have tried other questions answers. Still it is not working
var http = require('http');
console.log("hi")
var options = {
host: 'api.usergrid.com',
path: '/siddharth1/sandbox/restaurants'
};
var op = []; //declaring outside function
var req = http.get(options, function(res) {
// Buffer the body entirely for processing as a whole.
var bodyChunks = [];
res.on('data', function(chunk) {
// You can process streamed parts here...
bodyChunks.push(chunk);
}).on('end', function() {
var body = Buffer.concat(bodyChunks);
// ...and/or process the entire body here.
var body2 = JSON.parse(body);
op = body2.entities.map(function(item) {
return item.name;
});
console.log(op); // only this works
})
});
req.on('error', function(e) {
console.log('ERROR: ' + e.message);
});
console.log("outside function " + op); //this doesnt work
console.log('Server listening on port 80');
Node.js instantiates the variable op as an empty array:
var op = []; //declaring outside function
It then calls the .get() function of the http module, and passes it options and a callback function.
var req = http.get(options, function(res) {
...
});
The code inside the callback function is not executed until an HTTP GET request is received by your application.
Node then continues, and executes the remainder of your code:
console.log("outside function " + op); //this doesnt work
The above line is executed and indeed, op is an empty array as you defined it to be an empty array - and nothing has yet modified 'op'.
The server then idles, waiting for any incoming HTTP requests.
Much later, you of course issue a HTTP GET request to your server. The callback function you registered gets called, and the code inside that function executes.
If I were you I would look into some fundamental tutorials on Node.js, specifically looking into it's non-blocking model. Good luck.
Note: Ryan Dahl's original node.js presentation is a rather long video and a little old, but perfectly explains the way Node.js works, and I highly recommend you give it a watch.

Not asynchronous function and Node.js the event loop, how this works?

I'm trying to understand the event loop in Node.js, and how event programming works. Given that my module exports a function that returns something in the callback of data event:
var http = require('http');
module.exports.send = function send(message) {
http.request({ hostname: 'google.com' }, function (res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
return chunk;
}
});
};
How this can work?
If I understand correctly, http.request is an asynchronous operation, that means:
A call to http.request is performed;
The program control returns to Node.js event loop immediately;
When the request finally returns something (the data event is emitted), maybe after minutes, send function returns the data. Not before.
Thus result should be undefined, but actually is not:
var send = require('mymodule').send;
var result = send({});
console.log(result);
The main thing to think about is what is calling the data callback. In this case, that function is called from a random place inside of Node, so when you return chunk;, you are returning that chunk to that part of Node, you are not returning it back to your own code, as that has already finished running.
If you want to actually get that data, you need to pass a callback of your own into send that will be triggered when data comes back.
module.exports.send = function send(message, callback) {
http.request({ hostname: 'google.com' }, function (res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
callback(chunk);
});
});
};
then called like this:
var mod = require('...');
mod.send('message data', function(result){
console.log(result);
});
Keep in mind that the data event can be emitted any number of times, so you will want to collect all of the chunk values and then call your callback once the end event fires.

Resources