How to Make Sequential API Calls in JavaScript: Promises vs Observables

Calling Multiple APIs Sequentially in JavaScript

When working with APIs, it’s common to encounter situations where you need to make multiple API calls sequentially, with each call depending on the result of the previous one. This can be done using both Promises and Observables. In this blog, we will explore how to achieve this using both approaches.

Using Promises

Promises are a straightforward way to handle asynchronous operations in JavaScript. They provide a clean and readable way to chain asynchronous operations, ensuring that each operation completes before the next one begins.

Example with Promises

Let’s say we have three APIs to call sequentially, where each call depends on the result of the previous one:

  1. First API Call: Fetch a post by its ID.
  2. Second API Call: Fetch comments for the post using the post ID.
  3. Third API Call: Fetch albums for the user based on the comment’s user ID.

Here’s how you can achieve this using Promises:

// Function to make an API call and return a promise
const fetchApi1 = () => {
  return fetch('https://jsonplaceholder.typicode.com/posts/1')
    .then(response => response.json());
};

const fetchApi2 = (resultFromApi1) => {
  // Use the result from API 1 to call API 2
  return fetch(`https://jsonplaceholder.typicode.com/comments?postId=${resultFromApi1.id}`)
    .then(response => response.json());
};

const fetchApi3 = (resultFromApi2) => {
  // Use the result from API 2 to call API 3
  const commentId = resultFromApi2[0].id; // Assuming we use the first comment's id for API 3
  return fetch(`https://jsonplaceholder.typicode.com/albums?userId=${commentId}`)
    .then(response => response.json());
};

// Chaining promises
fetchApi1()
  .then(resultFromApi1 => {
    console.log('Result from API 1:', resultFromApi1);
    return fetchApi2(resultFromApi1);
  })
  .then(resultFromApi2 => {
    console.log('Result from API 2:', resultFromApi2);
    return fetchApi3(resultFromApi2);
  })
  .then(resultFromApi3 => {
    console.log('Result from API 3:', resultFromApi3);
  })
  .catch(error => {
    console.error('Error:', error);
  });
JavaScript

Using Observables

Observables, provided by libraries like RxJS, offer powerful operators to handle asynchronous data streams. We will explore two operators: switchMap and mergeMap.

Using switchMap Operator in RxJs Observable

switchMap is ideal for situations where each observable should be cancelled if a new value is emitted by the source observable. In the context of API calls, it ensures that each call is completed before starting the next one.

import { of } from 'rxjs';
import { ajax } from 'rxjs/ajax';
import { switchMap } from 'rxjs/operators';

// Function to make an API call and return an observable
const fetchApi1 = () => {
  return ajax.getJSON('https://jsonplaceholder.typicode.com/posts/1');
};

const fetchApi2 = (resultFromApi1) => {
  // Use the result from API 1 to call API 2
  return ajax.getJSON(`https://jsonplaceholder.typicode.com/comments?postId=${resultFromApi1.id}`);
};

const fetchApi3 = (resultFromApi2) => {
  // Use the result from API 2 to call API 3
  const commentId = resultFromApi2[0].id; // Assuming we use the first comment's id for API 3
  return ajax.getJSON(`https://jsonplaceholder.typicode.com/albums?userId=${commentId}`);
};

// Creating an observable chain
of(null).pipe(
  switchMap(() => fetchApi1()),
  switchMap(resultFromApi1 => {
    console.log('Result from API 1:', resultFromApi1);
    return fetchApi2(resultFromApi1);
  }),
  switchMap(resultFromApi2 => {
    console.log('Result from API 2:', resultFromApi2);
    return fetchApi3(resultFromApi2);
  })
).subscribe(
  resultFromApi3 => {
    console.log('Result from API 3:', resultFromApi3);
  },
  error => {
    console.error('Error:', error);
  }
);
JavaScript

Using mergeMap Operator in RXJS Observable

mergeMap is used for merging multiple observables into a single observable stream. When chaining sequential API calls, mergeMap can still be used effectively by ensuring each inner observable completes before starting the next one.

import { of } from 'rxjs';
import { ajax } from 'rxjs/ajax';
import { mergeMap } from 'rxjs/operators';

// Function to make an API call and return an observable
const fetchApi1 = () => {
  return ajax.getJSON('https://jsonplaceholder.typicode.com/posts/1');
};

const fetchApi2 = (resultFromApi1) => {
  // Use the result from API 1 to call API 2
  return ajax.getJSON(`https://jsonplaceholder.typicode.com/comments?postId=${resultFromApi1.id}`);
};

const fetchApi3 = (resultFromApi2) => {
  // Use the result from API 2 to call API 3
  const commentId = resultFromApi2[0].id; // Assuming we use the first comment's id for API 3
  return ajax.getJSON(`https://jsonplaceholder.typicode.com/albums?userId=${commentId}`);
};

// Creating an observable chain
of(null).pipe(
  mergeMap(() => fetchApi1()),
  mergeMap(resultFromApi1 => {
    console.log('Result from API 1:', resultFromApi1);
    return fetchApi2(resultFromApi1);
  }),
  mergeMap(resultFromApi2 => {
    console.log('Result from API 2:', resultFromApi2);
    return fetchApi3(resultFromApi2);
  })
).subscribe(
  resultFromApi3 => {
    console.log('Result from API 3:', resultFromApi3);
  },
  error => {
    console.error('Error:', error);
  }
);
JavaScript

Conclusion

Whether you choose Promises or Observables depends on your specific use case and preference. Promises are simpler and more straightforward for handling sequential asynchronous operations. Observables offer greater flexibility and powerful operators for complex asynchronous workflows.

By understanding both approaches, you can choose the one that best fits your needs and effectively handle sequential API calls in your applications.

Stay tuned for more updates and detailed walkthroughs in the upcoming weeks. You can find more information about web development Happy coding! 🎉

Leave a Reply

Your email address will not be published. Required fields are marked *