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;
}
Related
Well, i'm visiting an array of urls making a request for each one, when one request ends the method executes the next. The array is something like this: [link1,link2,link3]. If i try to open first the link3 in browser i'll get an error (error 404) but opening the link1 and link2 first i'll have the desired response. In the browser works without problems, but isn't working in my code because i got "status:200" using the first two links, but a 404 with the third.
(If i open link2 and link2 in the browser the problem ends, but i want to do that not using the browser)
The code:
function websiteOpener(links_array, index, final) {
var methodStr = className + '::websiteOpener';
try {
log.info(methodStr + '>> Open the link: ' + links_array[index]);
var protocol;
var _host;
var rawhost;
if (links_array[index].match(/https:\/\/[^\/]+/)) {
rawhost = links_array[index].match(/https:\/\/[^\/]+/);
_host = rawhost[0].replace(/https:\/\//, '');
protocol = 'https:'
_path = links_array[index].replace(rawhost, '');
incremental = index + 1;
var options = {
host: _host,
path: _path,
method: 'GET',
headers: { 'Content-type': 'text/html' },
protocol: protocol,
agent: new https.Agent({
rejectUnauthorized: false,
})
}
} else {
incremental = index + 1;
var options =links_array[index];
}
if (incremental < final) {
if (links_array[index].match(/https:\/\/[^\/]+/)) {
var request = https.request(options, function (response) {
console.log(response.statusCode);
//if (response.statusCode === 200) {
var data;
response.on('data', (chunk) => {
data += chunk;
});
response.on('end', function () {
websiteOpener(links_array, incremental, final);
});
//}
});
request.end();
} else {
var request = http.request(options, function (response) {
//if (response.statusCode === 200) {
var data;
response.on('data', (chunk) => {
data += chunk;
});
response.on('end', function () {
websiteOpener(links_array, incremental, final);
});
//}
});
request.end();
}
} else {
options.headers = { 'Content-type': 'applcation/pdf' };
var request = https.request(options, function (response) {
console.log(response.statusCode);
//if (response.statusCode === 200) {
var data;
response.on('data', (chunk) => {
data += chunk;
});
response.on('end', function () {
log.info(methodStr + '>>link found ' + links_array[index]);
});
//}
});
request.end();
}
} catch (e) {
log.error(methodStr + ">> Server error: ", e);
reject({ statusCode: 500, flag: 'ERR_PROCESS' });
}
}
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();
});
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);
});
});
};
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();
}
I have a RESTish api on a node js server. When it receives a GET request, it is to call a function that will then be calling another server get function. The code looks like this:
var server = http.createServer(function(request, response) {
console.log("YEAHHH! ", request.method);
var string='';
// Inside a request handler method
if (request.method == "OPTIONS") {
console.log("options");
// Add headers to response and send
//response.writeHead(statusCode, responseHeaders);
response.writeHead(success,responseHeaders);
response.end();
}
if(request.method == "GET") {
string = soso();
}
console.log("*******", string);
response.writeHead(success,responseHeaders);
response.end(string);
});
soso() is the call to the other server. The issue is I want to send the response of the soso() function before its finished so all I'm getting is an empty string.
How do I get around this?
I'm sure this is a duplicate but can't quite find what I'm looking for. So, any help is appreciated.
EDIT
Code for the soso function:
var soso = function () {
console.log("this is being called");
var options = {...}
var req = https.get( options, function(res) {
var str = '';
res.on('data', function ( chunk ) {
str += chunk;
})
res.on('end', function () {
console.log ( "str is: ", str );
string = str;
})
req.end();
console.log(res.statusCode);
console.log(responseHeaders);
});
}
You can try something like this , I am not sure. I have not tested this. Pass the response object in soso function, then use response.end(string); after get request gets end.
var server = http.createServer(function(request, response) {
console.log("YEAHHH! ", request.method);
var string='';
// Inside a request handler method
if (request.method == "OPTIONS") {
console.log("options");
// Add headers to response and send
//response.writeHead(statusCode, responseHeaders);
response.writeHead(success,responseHeaders);
response.end();
}
if(request.method == "GET") {
string = soso(response); //send response object as argument
} else {
console.log("*******", string);
response.writeHead(success,responseHeaders);
response.end(string);
}
});
soso function
var soso = fuction(response){ // we pass the response object in soso function
console.log("this is being called");
var options = {...}
var req = https.get( options, function(res) {
var str = '';
res.on('data', function ( chunk ) {
str += chunk;
})
res.on('end', function () {
console.log ( "str is: ", str );
string = str;
})
req.end();
response.writeHead(success,responseHeaders);
response.end(string);
console.log(res.statusCode);
console.log(responseHeaders);
});
}