Handling Multiple Web Service Responses in JavaScript

The Problem

Normally when handling web service data with JavaScript, you request that data via HTTP and whenever it is returned, you do some action. Whether that action is rendering a list of users or storing the results in your app for later use. But sometimes, you have multiple web services you want to operate on at the same time. This posts describes one clean way of doing this.

When to Use

First, a word of warning. If you do find yourself needing multiple web service responses at the same time, you should consider creating a service for the data you actually need. Scripting the manipulation of multiple data sources in the browser as soon as they are returned probably means you’re doing too much unnecessary work in the browser.

One valid reason for doing this is that you don’t control one or more of the data sources you are pulling. Another good reason is you’re demonstrating the use of those data sources with their original structure intact. Such as when I’m manipulating multiple GeoJSONs in a blog post 🙂

The Solution

The solution all centers on the Promise API which has had great browser support for years. If you’re unfamiliar, a Promise is an object that stands in for a value that may or may not be immediately available (such as a web service response). When the Promise “settles” (succeeds or fails), one of two callbacks are called: Promise.then(value) on success or Promise.catch(error) on failure. Promise.finally() is also called after you handle the Promise via .then() or .catch().

Luckily, the most popular libraries for performing Ajax requests all support Promises. I’ll be using axios for this example but your chosen Promise-based option should be just as easy to use in its place.

First, the standard way of handling a single HTTP request with axios:

axios.get(<url>)
  .then(response => {
    // Handle single response...
  })
  .catch(error => {
    // Handle the error...
  })

And handling multiple HTTP requests using axios and Promise.all():

let promise1 = axios.get(<url1>)
let promise2 = axios.get(<url2>)
let promise3 = axios.get(<url3>)

Promise.all([promise1, promise2, promise3])
  .then(responses => {
    // responses: [response1, response2, response3]
    // Handle multiple responses...
  })
  .catch(error => {
    console.log(error) // Error is from first promise that failed
  })

A Note on Errors

It’s important to make clear what happens when a web service does not resolve. If any of the requests fail (HTTP error, timeout, etc), the first one to do so will trigger the catch() callback. This makes sense though since by using Promise.all(), you are saying you need the successful response from all three Promises.

Further Reading