2

I am building a NodeJS server using Express4. I use this server as a middleman between frontend angular app and 3rd party API. I created a certain path that my frontend app requests and I wish on that path to call the API multiple times and merge all of the responses and then send the resulting response. I am not sure how to do this as I need to wait until each API call is finished. Example code:

app.post('/SomePath', function(req, res) {
  var merged = [];
  for (var i in req.body.object) {
    // APIObject.sendRequest uses superagent module to handle requests and responses
    APIObject.sendRequest(req.body.object[i], function(err, result) {
      merged.push(result);
    });
  }
  // After all is done send result
  res.send(merged);
});

As you can see Im calling the API within a loop depending on how many APIObject.sendRequest I received within request.

How can I send a response after all is done and the API responses are merged?

Thank you.

StrikoMirko
  • 415
  • 4
  • 17
  • The problem is that `APIObject.sendRequest` is asynchronous so the `for` loop ends before the actual requests are completed? – Neta Nov 04 '15 at 16:54
  • Well there are loads of problems here and that is one of them. Is there some other way to do this? – StrikoMirko Nov 04 '15 at 16:57

2 Answers2

2

Check out this answer, it uses the Async module to make a few requests at the same time and then invokes a callback when they are all finished.

As per @sean's answer, I believe each would fit better than map.

It would then look something like this:

var async = require('async');
async.each(req.body.object, function(item, callback) {
  APIObject.sendRequest(item, function(err, result)) {
    if (err)
      callback(err);
    else
    {
      merged.push(result);
      callback();
    }
  }
}, function(err) {
     if (err)
       res.sendStatus(500); //Example
     else
       res.send(merged);
});
Community
  • 1
  • 1
Neta
  • 871
  • 5
  • 14
  • 30
  • Wow man this is just crazy, It worked like straight away :D! Nice one. Thnx. You just have a little syntax error near }, function(err) {, APIObject has a bracket open which you must close. Thnx again this async module rocks! – StrikoMirko Nov 04 '15 at 17:57
0

First of all, you can't do an async method in a loop, that's not correct.

You can use the async module's map function.

app.post('/SomePath', function(req, res) {
  async.map(req.body.object, APIObject.sendRequest, function(err, result) {
    if(err) {
      res.status(500).send('Something broke!');
      return;
    }
    res.send(result);
  });
});
Neta
  • 871
  • 5
  • 14
  • 30
Sean
  • 2,990
  • 1
  • 21
  • 31
  • Not entirely correct as `map` is used to change the values of the array. `each` would suit better. – Neta Nov 04 '15 at 17:08
  • @Neta I don't know waht you mean? why you think map is used to change the values of the array? – Sean Nov 04 '15 at 17:11
  • map is used to transform the data from one category to another category, map is not supposed to changed the original value of the array. – Sean Nov 04 '15 at 17:12
  • From the [documentation](https://github.com/caolan/async#map): `Produces a new array of values by mapping each value in arr through the iterator function.` It goes through each value in the original array, passing in to the `iterator` and changing said value's value. At the end it returns the new array. – Neta Nov 04 '15 at 17:15
  • have you try to use map?, map is used to transfer an array of A to an array of B, in this case transfer an array of id to and array of Object. – Sean Nov 04 '15 at 17:24
  • 1
    The argument's vain. We need to know what's the value of `req.body.object`. Let him try both codes and see if they work. – Neta Nov 04 '15 at 17:27