Chain Http Requests


There are a couple of ways to chain http requests in Angular and TypeScript. We will check out two ways using switchMap and concatMap.

switchMap

import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { switchMap } from 'rxjs/operators';

@Component({
  selector: 'app-example',
  template: `
    <div *ngIf="data">
      <h2>Data:</h2>
      <pre>{{ data | json }}</pre>
    </div>
  `,
})
export class ExampleComponent implements OnInit {
  data: any; 

constructor(private http: HttpClient) {} 

ngOnInit() {
    this.getData().subscribe(result => {
      console.log(result);
      this.data = result;
    });
  } 

getData(): Observable<any> {
    return this.http.get<any>('api/first-endpoint').pipe(
      switchMap(firstResult => {
        return this.http.get<any>('api/second-endpoint').pipe(
          switchMap(secondResult => {
            return this.http.get<any>('api/third-endpoint').pipe(
              // You can continue chaining more requests if needed
              switchMap(thirdResult => {
                // Combine all results and return
                return [firstResult, secondResult, thirdResult];
              })
            );
          })
        );
      })
    );
  }
}

In this example:

  1. We import the necessary modules and operators.
  2. In the getData() method, we make the first HTTP request and then chain the subsequent requests using switchMap.
  3. Each subsequent request depends on the result of the previous request.
  4. Finally, in the last switchMap, we combine all the results into an array and return it.

concatMap

import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { concatMap } from 'rxjs/operators';

constructor(private http: HttpClient) { }

chainRequests(): Observable<any> {
    return this.http.get('https://jsonplaceholder.typicode.com/posts/1').pipe(
        concatMap(response1 => {
            console.log(response1);
            // Second GET request depends on first GET request
            return this.http.get('https://jsonplaceholder.typicode.com/posts/2');
        }),
        concatMap(response2 => {
            console.log(response2);
            // Third GET request depends on second GET request
            return this.http.get('https://jsonplaceholder.typicode.com/posts/3');
        })
    );
}

// Call the above function in your desired method.
exampleMethod(): void {
    this.chainRequests().subscribe(response3 => {
        console.log(response3);
    });
}

In this example, these are the steps:
Sends the first GET request (to https://jsonplaceholder.typicode.com/posts/1).
After the first request completes, sends the second GET request (to https://jsonplaceholder.typicode.com/posts/2).
Then when the second request concludes, sends the third GET request (to https://jsonplaceholder.typicode.com/posts/3).


Each subsequent request is contingent on the completion of the previous request. A failure in an early request in the chain will prevent the execution of the later requests.

 

Comparisson

concatMap and switchMap are both operators provided by RxJS for mapping values emitted by an observable to another observable, but they behave differently in terms of how they handle the inner observables and the order of emissions.

Here's the difference:

concatMap:

  • It maps each value to an inner observable and subscribes to them in order.
  • It maintains the order of emitted values from the inner observables.
  • It waits for each inner observable to complete before subscribing to the next one.
  • If a new value is emitted from the source observable before the current inner observable completes, concatMap queues it up and processes it after the current inner observable completes.

switchMap:

  • It maps each value to an inner observable and subscribes to it.
  • If a new value is emitted from the source observable before the current inner observable completes, switchMap unsubscribes from the previous inner observable and subscribes to the new one.
  • It doesn't maintain the order of emitted values if the inner observables complete out of order.
  • It's often used for scenarios like typeaheads or autocomplete inputs where you want to switch to the latest inner observable and disregard the previous ones.

In the context of chaining HTTP requests:

  • If you want to maintain the order of requests and ensure they are executed sequentially, concatMap is more suitable.
  • If you're only interested in the response from the latest request and want to cancel previous requests if a new one is emitted, switchMap is more appropriate.

No files yet, migration hasn't completed yet!