2

I'm currently fetching data from an API and I need to do multiple GET requests (using axios). After all those GET requests are completed, I return a resolved promise.

However, I need to do these GET requests automatically based on an array list:

    function do_api_get_requests() {

        return promise = new Promise(function(resolve, reject) {

          API_IDs = [0, 1, 2];

          axios.get('https://my.api.com/' + API_IDs[0])
          .then(data => {
            // Do something with data

            axios.get('https://my.api.com/' + API_IDs[1])
            .then(data => {
              // Do something with data

              axios.get('https://my.api.com/' + API_IDs[2])
              .then(data => {
                // Do something with data
                
                // Finished, resolve
                resolve("success");
                
              }


            }


          }

        }

    }

This works but the problem is API_IDs isn't always going to be the same array, it will change. So I'm not sure how to chain these requests automatically.

NeNaD
  • 18,172
  • 8
  • 47
  • 89
Ran Shorowitz
  • 307
  • 5
  • 11
  • 1
    Do the requests need to be made in sequence or can they be executed concurrently? – Phil Feb 16 '22 at 00:53
  • Avoid the [`Promise` constructor antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it)! – Bergi Feb 16 '22 at 01:58
  • Without `async`/`await`, use a recursive approach. Pass the api ids that you still need to visit as a parameter. – Bergi Feb 16 '22 at 01:59
  • FYI, people can help you better if you show real code including relevant processing of requests and how this is used by the caller, not pseudo-code. This applies to all questions here, not just this one. – jfriend00 Feb 16 '22 at 02:09

3 Answers3

4

Since you said it may be a variable length array and you show sequencing the requests, you can just loop through the array using async/await:

async function do_api_get_requests(API_IDS) {
    for (let id of API_IDS) {
        const data = await axios.get(`https://my.api.com/${id}`);
        // do something with data here
    }
    return "success";
}

And, since you said the list of API ids would be variable, I made it a parameter that you can pass into the function.


If you wanted to run all the API requests in parallel (which might be OK for a small array, but might be trouble for a large array) and you don't need to run them in a specific order, you can do this:

function do_api_get_requests(API_IDS) {
    return Promise.all(API_IDS.map(async (id) => {
        const data = await axios.get(`https://my.api.com/${id}`);
        // do something with data here for this request
    })).then(() => {
        // make resolved value be "success"
        return "success";
    });
}

Depending upon your circumstances, you could also use Promise.allSettled(). Since you don't show getting results back, it's not clear whether that would be useful or not.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • I would optimize that with `Promise.all()` so he does not wait for each response in order to continue. – NeNaD Feb 16 '22 at 01:00
  • 2
    @NeNaD - I've already added that as an option. Whether or not running them in parallel is a good idea is entirely dependent upon the situation. Sometimes subsequent results depend upon prior results. Sometimes, the array might be large and you don't actually want that many requests all running at the same time or all hitting the target server at once. Sometimes, you want the iteration to stop on the first one that fails rather than launch them all. It is highly situation-dependent. – jfriend00 Feb 16 '22 at 01:01
  • I agree with that. But based on the use case from the question, `Promise.all()` seams appropriate. :D – NeNaD Feb 16 '22 at 01:03
  • 1
    @NeNaD - The OP said ***"API_IDs isn't always going to be the same array"*** so hard to know what it will or won't be. Anyway, I've offered both choices. – jfriend00 Feb 16 '22 at 01:11
  • @NeNaD _"based on the use case from the question"_... the request should be run in sequence – Phil Feb 16 '22 at 01:44
  • I think it does not need to run in sequence. If you check the code itself, you will see that after data manipulation, next request is send based on the `API_IDs` array, and not based on previous result. That is why I think that `Promise.all()` is optimization. But as @jfriend00 said, both solutions are in the answers. :D – NeNaD Feb 16 '22 at 01:52
  • 1
    Problem with Promise.all() is that if any of those promises are rejected, it will atomatically reject the Promise.all(). If all requests are important, an alternative could be using Promise.allSettled() instead, that way its possible to run recursively upon any error. – guilfer Feb 16 '22 at 02:01
  • 1
    @guilfer - `Promise.allSettled()` is useful when you want to know which calls succeeded and which did not and get any successful results when some failed. The OP does not show any of that in their question. But, I've made reference to it as an option in the answer. – jfriend00 Feb 16 '22 at 02:08
  • This worked! Thank you. – Ran Shorowitz Feb 16 '22 at 03:11
2

You can use Promise.all() method to do all API requests at the same time, and resolve when all of them resolves.

function do_api_get_requests() {
  const API_IDs = [0, 1, 2];

  let promises = [];
  for (const id of API_IDS) {
    promises.push(axios.get(`https://my.api.com/${id}`));
  }

  return Promise.all(promises);
}
NeNaD
  • 18,172
  • 8
  • 47
  • 89
-1

If you use Bluebird.js (a better promise library, and faster than the in-built Promise), you can use Promise.each(), Promise.mapSeries(), or Promisme.reduce() to do what you want.

http://bluebirdjs.com

Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135