how to make a node http request pause execution until complete - node.js

I'm getting a JSON response from a service that I want to pass on to another function. When I put a breakpoint on the var parsedData... line and one on the return resp, the parsedData line gets hit first. How can I "wait" for the request to finish before moving on in the code?
var data = sendRequest(options);
var parsedData = parseData(commits);
var sendRequest = function (options) {
var resp = {}
var request = https.request(options, function (response) {
var body = '';
response.on("data", function (chunk) {
body += chunk.toString('utf8');
});
response.on("error", function(e){
console.log(e);
})
response.on("end", function () {
resp = JSON.parse(body);
return resp;
});
});
request.end();
}

add a callback argument to sendRequest
var data = sendRequest(options, function(){
var parsedData = parseData(commits);
});
var sendRequest = function (options, callback) {
var resp = {}
var request = https.request(options, function (response) {
var body = '';
response.on("data", function (chunk) {
body += chunk.toString('utf8');
});
response.on("error", function(e){
console.log(e);
})
response.on("end", function () {
resp = JSON.parse(body);
callback(resp);
});
});
request.end();
}

Related

Await function to finish calling another API

I am new to using async/await and having a couple issues.
I have the code below, which seems to not wait until the previous function is finished?
var url = require('url');
var path = require('path');
var https = require('https');
var request = require('request');
var url1 =
var url2 =
var url3 =
module.exports = async function (context, req) {
var call = await callUrl(context, url1);
context.log(call);
var call2 = await callUrl(context, url2);
context.log(call2);
var call3 = await callUrl(context, url3);
context.log(call3);
};
function callUrl (context, web) {
var requestUrl = url.parse(web);
const requestOptions = {
hostname: requestUrl.hostname,
path: requestUrl.path,
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
};
var request = https.request(requestOptions, function(res) {
var data = "";
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function () {
var jsonData = JSON.parse(data);
return jsonData;
});
}).on('error', function(error) {
context.log("request error:", error);
return context.done();
});
request.end();
}
I am trying to get call to happen, then when it is finished call2, then when that is finished call3.
Can someone pinpoint why this does not occur? Currently, it hits all 3 pretty much asap, and each context.log is undefined presumably because the endpoints don't return anything. Each url is another azure function app API I have created.
There is nothing I am requiring to return from each call to use, I simply want them to finish before moving on the the next function.
Your callUrl method, which you call with await, needs to be either async itself or return a Promise. Why? because the work it does is itself asynchronous.
Here's your function adapted to use a Promise and return its actual value via the resolve() callback.
function callUrl (context, web) {
var requestUrl = url.parse(web);
const requestOptions = {
hostname: requestUrl.hostname,
path: requestUrl.path,
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
};
return new Promise(function (resolve,reject) {
var request = https.request( requestOptions, function( res ) {
var data = "";
res.on( 'data', function( chunk ) {
data += chunk;
} );
res.on( 'end', function() {
var jsonData = JSON.parse( data );
resolve( jsonData );
} );
} )
.on( 'error', function( error ) {
reject(error);
} );
request.end();
});
}
Notice that you use a POST operation with no body. That's a little unconventional.

Deferred already resolved

Following is the node-js code used for HTTP requests. This code is giving "This deferred has already been resolved" error on production servers when I try to use requestPromise.resolve(str) in request end. Can someone please suggest what might be the error?
Libraries used : http and node-promise
var Promise = require('node-promise').Promise;
var requestPromise = new Promise();
callback = function (response) {
var str = '';
response.on('data', function (chunk) {
str += chunk;
});
response.on('end', function () {
if (!(response && response.statusCode >= 200 && response.statusCode < 300)) {
requestPromise.resolve(str);
return;
}
var resp;
try {
resp = JSON.parse(str);
} catch (ex) {
resp = str;
}
requestPromise.resolve(str);
});
});
var request = http.request(options, callback);
request.on('error', function (err) {
requestPromise.resolve(err);
});
request.write(postObject);
request.end();
I think you cannot use new Promise() (because it need resolver).
You can use this code:
new Promise(function(resolve, reject) {
callback = function (response) {
var str = '';
response.on('data', function (chunk) {
str += chunk;
});
response.on('end', function () {
if (!(response && response.statusCode >= 200 && response.statusCode < 300)) {
resolve(str);
return;
}
var resp;
try {
resp = JSON.parse(str);
} catch (ex) {
resp = str;
}
resolve(resp);
});
});
var request = http.request(options, callback);
request.on('error', function (err) {
reject(err);
});
request.write(postObject);
request.end();
});

Node.js http.get returning "undefined" in function

var exports = module.exports = {};
var http = require('http');
exports.get = function(key, app, vari) {
http.get('<url here>/?key='+key+'&app='+app+'&var='+vari+'&req=0', function (response) {
response.setEncoding('utf8');
response.on('data', function(body) {
console.log(body);
return body;
});
});
};
My code (seen above) will output the response to the console just fine, but when trying to use the function in an export, it returns 'undefined' no matter what. The responses it receives are one line and are in the content type of "application/json". What's up with it? (And no, it's not the "url here", I just removed the URL for privacy reasons. If it helps, I can provide it.)
exports.get = function(key, app, vari) {
return
http.get('<url here>/?key='+key+'&app='+app+'&var='+vari+'&req=0', function (response) {
response.setEncoding('utf8');
response.on('data', function(body) {
console.log(body);
return body;
});
});
};
reference,and you need to listen end event and return a promise instead, just like:
var exports = module.exports = {};
var http = require('http');
exports.get = function(key, app, vari) {
return new Promise(function(resolve) {
http.get('<url here>/? key='+key+'&app='+app+'&var='+vari+'&req=0', function (response) {
response.setEncoding('utf8');
var data = '';
response.on('data', function(chunk) {
console.log(chunk);
data += chunk;
});
response.on('end', function() {
resolve(JSON.parse(data));
});
});
})
}
I figured it out, I just needed to have a call for an answer.
var exports = module.exports = {};
var http = require('http');
exports.get = function(key, app, vari, answ) {
http.get('http://<url here>/?key='+key+'&app='+app+'&var='+vari+'&req=0', function (response) {
response.setEncoding('utf8');
response.on('data', function(body) {
answ(body);
});
});
};

Chaining GET request with a response Node.js

I am trying to perform a GET request to an API and return the data from the API response to the client. I think the client receives a response before the GET request to the API finishes. How can I change the code to ensure that the response from the API is passed on to the client?
if (request.method == 'POST' && request.url == '/locationdata') {
var body = '';
request.on('data', function (data) {
body += data;
});
request.on('end', function () {
var formattedLocation = body.replace(/[\[\]']+/g, '');
var urlAPI = 'https://api.darksky.net/forecast/166731d8eab28d33a26c5a51023eff4c/' + formattedLocation;
response.writeHead(200, { 'Content-Type': 'application/json' });
var apiData = '';
var apirequest = function () {
https.get(urlAPI, function (response) {
response.on('data', function (data) {
apiData += data;
});
response.on('end', function () {
console.log(apiData);
return apiData;
});
});
}
response.end(apirequest);
});
return;
}
You are ending the response to the client before you get all the data from the api. Moving the response.end() call up to the end of the api response should fix it:
if (request.method == 'POST' && request.url == '/locationdata') {
var body = '';
request.on('data', function (data) {
body += data;
});
request.on('end', function () {
var formattedLocation = body.replace(/[\[\]']+/g, '');
var urlAPI = 'https://api.darksky.net/forecast/166731d8eab28d33a26c5a51023eff4c/' + formattedLocation;
response.writeHead(200, { 'Content-Type': 'application/json' });
var apiData = '';
https.get(urlAPI, function (apiResponse) {
apiResponse.on('data', function (data) {
apiData += data;
});
apiResponse.on('end', function () {
console.log(apiData);
// send response to browser after we get all the data from the api
response.end(apiData);
});
});
// remove this because we moved it up
//response.end(apirequest);
});
return;
}

I am trying to read image from different server and write on response

function media(req,res){
console.log(req.query.image);
var collectionName = 'imageTable';
var selector = MongoHelper.idSelector(req.query.image);
MongoHelper.findOne(selector, collectionName, function(err, image) {
console.log(image.picture);
var url_parts = url.parse(image.picture);
var options = {host: url_parts.hostname, path: url_parts.pathname};
http.get(options).on('response', function (response) {
var body = '';
var i = 0;
response.on('data', function (chunk) {
i++;
body += chunk;
console.log('BODY Part: ' + i);
});
response.on('end', function () {
console.log('Finished');
res.writeHead(200,{'Content-Type':'image/JPEG'});
res.write(body);
res.end();
});
});
});
}
I am fetching image from different server. I have url of that image. And I am writing the response. But here response image is get corrupted. Any idea about how to write jpeg image in response?
function media(req,res){
console.log(req.query.image);
var collectionName = 'facebook';
var selector = MongoHelper.idSelector(req.query.image);
MongoHelper.findOne(selector, collectionName, function(err, image) {
var url_parts = url.parse(image.picture);
var options = {host: url_parts.hostname, path: url_parts.pathname};
http.get(options).on('response', function (response) {
res.writeHead(200,{'Content-Type':'image/JPEG'});
response.on('data', function (chunk) {
res.write(chunk);
});
response.on('end', function () {
res.end();
});
});
});
}
Here I got the solution. Instead of writing whole data at the end. Write it each time you get and end the response when you reach to the end of file. But still if anyone have better idea can write here.

Resources