Codementor Events

JavaScript: How to make API calls for each value in an array and get an array of results.

Published May 17, 2019Last updated Nov 12, 2019
JavaScript: How to make API calls for each value in an array and get an array of results.

Today I had to call an API with for a bunch of ids and get the results for each of those ids. Now the problem is, I need to collect the results from all of those API calls. And I did not want to use plain old for loop for this today.

So here’s how I did it. (Skip to the end for full code)

Promise

new Promise(executor)

The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value.

executor

A function that is passed with the arguments resolve and reject. The executor normally initiates some asynchronous work, and then, once that completes, either calls the resolve function to resolve the promise or else rejects it if an error occurred.

let requests = ids.map(id => {
   return new Promise((resolve, reject) => {
      request({
      uri: <API url>+'?id=' + id,
      method: 'GET'
      })
   })
})

So now each of our API calls is wrapped in a promise. That means requests is now an iterable containing promises.

Promise.all()

Promise.all() returns a single Promise that resolves when all of the promises passed as an iterable have resolved.
Now we pass the requests array to Promise.all().

Promise.all(requests)

Now, the bits and pieces are ready. But I hadn’t yet connected these two parts.

Promise.all() returns a pending promise when passed with an iterable containing promises. This returned promise is then resolved/rejected asynchronously (as soon as the stack is empty) when all the promises in the given iterable have resolved, or if any of the promises reject.
So that means there needs to be

  1. A way to resolve each of the promises in the iterable
  2. The code to be executed when the promise returned by Promise.all() has resolved

1. A way to resolve each of the promises in the iterable

The executor normally initiates some asynchronous work, and then, once that completes, either calls the resolve function to resolve the promise or else rejects it if an error occurred.
Request takes a callback which gets called when the API call has returned. In this callback, we first check for an error. If there’s no error, we call the resolve function passed to the executor function used to create the promise. Similarly, in case of an error, we call the reject function.

let requests = ids.map(id => {
return new Promise((resolve, reject) => {
      request({
            uri: <API url>+'?id=' + id,
            method: 'GET'
            })
         },
         (err, res, body) => {
            if (err) { reject(err) }
            resolve(body)
         })
      )
})

2. The code to be executed when the promise returned by Promise.all() has resolved

The promise returned by Promise.all() is resolved/rejected asynchronously (as soon as the stack is empty) when all the promises in the given iterable have resolved

Promise.all(requests)
.then(body => { 
   body.forEach(res => {
   if (res)
      productsToReturn.push(JSON.parse(res).productInfo)
   })
})

Here we receive the responses received from each of our API calls in an array. We manipulate each of the responses as per our requirements and push it into an array.

Here’s the full code

var productsToReturn = []
let requests = ids.map(id => {
   //create a promise for each API call
   return new Promise((resolve, reject) => {
      request({
         uri: <API url>+‘?id=' + id,
         method: ‘GET’
      },
      (err, res, body) => {
      if (err) { reject(err) }
      //call the resolve function which is passed to the executor                             //function passed to the promise
      resolve(body)
      })
   })
})
Promise.all(requests).then((body) => { 
//this gets called when all the promises have resolved/rejected.
   body.forEach(res => {
   if (res)
      productsToReturn.push(JSON.parse(res).productInfo)
   })
}).catch(err => console.log(err))
Discover and read more posts from Aditi Tipnis
get started
post commentsBe the first to share your opinion
Chen Osipov
5 years ago

Looks good, however, it’s not a good practice, cause you have a limit of open connections that’s is around 6 in modern browsers, a better approach is to bundle the items on the backend, and fetch all in one call…

Jamie Lewis
3 years ago

How about AWS Lambda? As far as I can tell, this is a great use case for it, however, I am still doing more research. If I could use this with HTTP API, not REST…
For the sake of context, I am doing something like this(in nodejs):
https://disqus.com/by/disqus_VwZInIk5Hd/

Show more replies