1

I am working on a project where I need to make multiple requests to a third party API and then send back an array of the data recieved to the client. Obviously the requests to the to the third party API are async, and if I put the res.json immediately after the request loop, the data will be empty. Do I need to wrap the request in a promise? Here is my code:

const historicalForecast = (req, res, next) => {
  console.log(req.body);
  // GET COORDS FROM GOOGLE API BY LOCATION INPUT BY USER
  let googleUrl = `https://maps.googleapis.com/maps/api/geocode/json?address=${req.body.input}&key=${googleKey}`;
  request(googleUrl, function(error, response, body){
    if(error){
      console.log(error);
      next();
    }
    let data = JSON.parse(response.body);
    //IF MORE THAN ONE RESULT FROM GEOLOCATION QUERY
    //ADD DATES REQUESTED INTO RESPONSE AND
    //SEND LIST OF LOCATIONS BACK SO USER CAN CHOOSE
    if(data.results.length > 1){
      response.body.startDate = req.body.startDate;
      response.body.endDate = req.body.endDate;
      res.json(JSON.parse(response.body));

    //IF ONE RESULT, GET DATA IN BATCHES
    }else if(data.results.length === 1) {
      let coords = data.results[0].geometry.location;
      const OneDay = 86400;
      let timeFrame = Math.abs(req.body.startDate - req.body.endDate);
      let numberOfDays = timeFrame/OneDay;
      console.log(numberOfDays);
      let results = [];

      for(let i = 0; i < numberOfDays; i++){
        let currentDay = Number(req.body.startDate) + (i*OneDay);
        let urlWeather = `https://api.forecast.io/forecast/${weatherKey}/${coords.lat},${coords.lng},${currentDay}`;
        request(urlWeather, function(error, response, body){
          if(error){
            console.log(error);
            next();
          }
          results.push(JSON.parse(response.body));
          res.send(results);
        });
      }
    }
  });
};
Atache
  • 169
  • 1
  • 13
  • 2
    You will want to use a promisified version of `request` and then use `Promise.all()` to know when all your requests are done. This question has likely been asked many times before so there are probably many other answers here that describe this. – jfriend00 Jul 08 '16 at 19:00
  • 1
    Here's the general structure for using promises to know when multiple async operations are done: http://stackoverflow.com/questions/32799672/node-js-how-to-set-a-variable-outside-the-current-scope/32799727#32799727 – jfriend00 Jul 08 '16 at 19:02
  • Thank you for your advice. @jfriend00 – Atache Jul 08 '16 at 19:11

1 Answers1

1

As per @jfriend00's suggestion I looked at:

Node.JS How to set a variable outside the current scope

And used one of the many options provided there. My solution is in the post above. Will be bookmarking that post for future reference.

I replaced all the code in the else if statement with:

  let coords = data.results[0].geometry.location;
  const OneDay = 86400;
  let timeFrame = Math.abs(req.body.startDate - req.body.endDate);
  let numberOfDays = timeFrame/OneDay;


  const makeMultipleQueries = (url) => {
    return new Promise(function(resolve, reject) {
      request(url, function(error, response, body){
        if(error){
          reject(error);
        }
        resolve(response.body);
      });
  });
};

let promises = [];
for (let i = 0; i < numberOfDays; i++) {
  let currentDay = Number(req.body.startDate) + (i*OneDay);
  let url = `https://api.forecast.io/forecast/${weatherKey}/${coords.lat},${coords.lng},${currentDay}`;
  promises.push(makeMultipleQueries(url));
}
Promise.all(promises).then(function(results) {
    res.json(results);
}, function(err) {
    next(err);
});
Community
  • 1
  • 1
Atache
  • 169
  • 1
  • 13
  • 1
    The proper way to use stack overflow is to put your actual coded answer in your answer and remove it from your question. Unlike some other sites, questions should be only questions and answers should be only answers here. So, please take your solution out of your question and put it in your answer here. You can then "accept" your own answer to the question (once a certain amount of time has passed) to indicate to the community that your question has now been answered. You could also upvote the linked answer that showed you the way. – jfriend00 Jul 08 '16 at 21:56