Reputation: 542
I am currently having an issue with figuring out how to wait for the request to finish before returning any data. I do not believe I can do this with a Callback and I have not been able to figure out a good way of using the EventEmitter to do it. The reason I cannot use a callback is because my flow currently works like this.
Request comes into server > Generate XML > Contact remote API for details to finish generating XML > Finish Generating XML > Return request to client
The code I currently have looks very similar to the code included below.
Web Server:
var xml = require('./XMLGenerator');
response.writeHead(200, {'Content-Type': 'text/xml'});
response.write(xml.generateXML());
response.end();
XML Generator:
function generateXML(){
// Code to generate XML
var API = require('./API');
var response = API.getItems("5");
for(var i = 1; i <= response.length; i++)
{
// more code to generate further XML using the API response
}
// Finish generating and return the XML
}
API Grabber:
function getItems(sort_by, amount) {
var request = require("request")
var url = "https://url.com/api/get_items.json?amount=" + amount;
request({
url: url,
json: true
}, function (error, response, body) {
console.log('we got here!');
if (!error && response.statusCode === 200) {
var items = body.data.items;
console.log(items);
return items;
} else {
console.log("Error connecting to the API: " + url);
return;
}
})
}
When running the code and testing directly it returns "undefined" meaning that the request has not been made yet. I just need to know a way to make the XML generator wait for the request to finish before continuing on with the generation. (there may be minor errors in the psudeo code I typed up as it is not an exact copy paste from the source, it does however work in this flow)
Am I just using bad practices, or is this the correct way that I should be attempting this?
EDIT: The problem is not loading the module/API file, that loads perfectly fine. The problem is that the request takes about 2 seconds to complete, and that node moves on before the request completes.
Upvotes: 9
Views: 39466
Reputation: 113964
You need to use callbacks. Change your API grabber to this:
function getItems(amount, callback) {
// some code...
request({
url: url,
json: true
}, function (error, response, body) {
// some code...
if (!error && response.statusCode === 200) {
// some code
callback(items); <-- pass items to the callback to "return" it
}
})
}
Then change the xml generator to also accept callbacks:
function generateXML(callback){
// Code to generate XML
var API = require('./API');
API.getItems("5",function(response){
for(var i = 1; i <= response.length; i++)
{
// more code to generate further XML using the API response
}
// Finish generating and return the XML
callback(xml_result); // <-- again, "return" the result via callback
});
}
Then in your server code do:
var xml = require('./XMLGenerator');
response.writeHead(200, {'Content-Type': 'text/xml'});
xml.generateXML(function(xmlstring){
response.write(xmlstring);
response.end();
});
Upvotes: 8
Reputation: 8488
Do these changes since request
is async, use callbacks.
API.getItems("5", function(rs){
var response = rs;
for(var i = 1; i <= response.length; i++)
{
// more code to generate further XML using the API response
}
// Finish generating and return the XML
}
});
...
function getItems(sort_by, amount, callback) {...
...
callback(items); //Instead of return items;
...
You cannot return
from an async
call, which is request
module in your case. In such cases you can either use promises or callbacks
. This is a solution with callback.
The actual problem of it returning undefined
is it doesnot wait for var response = API.getItems("5");
to execute completely and executes the next line and hence you get response
as undefined
. I hope you get the point.\
Also I hope
response.writeHead(200, {'Content-Type': 'text/xml'});
response.write(xml.generateXML());
response.end();
is somewhere inside some callback of an API or http.createServer
.
Upvotes: 3