May 23, 2023

Handling multiple HTTP requests in angular using rxjs

In the world of web application, there is always a requirement you might face to make multiple Http requests.

It can be parallel or sequential, But In angular application, Http requests are by default observable, so we have several ways to handle it. Like using

  • nested subscription
  • mergeMap or concatMap or switchMap
  • forkJoin
  • Converting Http observable to promise

consider a scenario, We have blog application, In which we want author details of particular post and as request we have post id only, So in this scenario

first, we need to fetch post details, where we will get author id

second, On the basis of author id we will fetch author details

we will be using free json api for fetching data

https://jsonplaceholder.typicode.com/

Nested subscription

Using nested subscriptions its easy, On each http response subscription we will call another http call

like below

import { Component, VERSION, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit  {

  constructor(private httpClient: HttpClient){
  }
  userDetails: any;
  ngOnInit(){
    this.httpClient.get('https://jsonplaceholder.typicode.com/posts/1')
    .subscribe((res: any)=>{
        const userId = res.userId
        this.httpClient
        .get('https://jsonplaceholder.typicode.com/users/'+userId)
        .subscribe(userDetails=>{
         console.log(userDetails)
        })
    })
  }
}

In the above example, as you can see, we are requesting a post with post id 1 and after getting a response using subscription we are requesting for author details.

Nested subscription is not always good, always remember If you use n number of subscriptions then you should unsubscribe all the subscription otherwise there is always chances of memory leakage.

Using mergeMap or concatMap or switchMap.

mergeMap, concatMap and switchMap high-end rxjs operators have their use cases, you will notice the difference between them when you large number of Http stream

for eg. implementing search functionality, in that might we need to call Http request number of times as user enters, then might be the case you need to find the best operator among them.

to know the difference between mergeMap, concatMap or switchMap, go through this post.

for our problem of getting author details, we can use any of the operators. we will use mergeMap operator

import { Component, VERSION, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { mergeMap } from 'rxjs/operators';
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit  {
  name = 'Angular ' + VERSION.major;
  constructor(private httpClient: HttpClient){
  }
  userDetails: any;
  ngOnInit(){
    this.httpClient.get('https://jsonplaceholder.typicode.com/posts/1')
    .pipe(mergeMap((res: any)=> this.httpClient
        .get('https://jsonplaceholder.typicode.com/users/'+res.userId)))
    .subscribe((authorDetails: any)=>{
        console.log(authorDetails)
    })
  }
}

mergeMap internally subscribe to the source observable and pass response data to the inner Http observable

So, if we have 3 to 4 or n number of sequential Http calls then we don’t need to subscribe every Http calls, mergeMap will take care of it.

you can find example here on stackBlitz

ForkJoin

forkJoin is very helpful rxjs operator when we need to deal with Http calls parallelly

It’s kind of the same functionality as Promise.all, where all calls happen simultaneously. After all, calls get resolved. It emits value

for eg. If you want all posts and authors at once. then making call parallelly is a better option

import { Component, VERSION, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { mergeMap } from 'rxjs/operators';
import { forkJoin } from 'rxjs';
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit  {
  name = 'Angular ' + VERSION.major; 
  constructor(private httpClient: HttpClient){
  }
  posts: any[];
  authors: any[];
  userDetails: any;
  ngOnInit(){
    console.log('abs')
    forkJoin(
      [this.httpClient
      .get('https://jsonplaceholder.typicode.com/posts'),
     this.httpClient.get('https://jsonplaceholder.typicode.com/users')
    ])
    .subscribe(res=>{
      console.log(res);
    },err=>{
      console.log('error',err)
      })
   
  }
}

Above, we have used forkJoin for getting posts and authors at once. forkJoin will emit data only when both the Http observable completed.

If any of it fail or both http observables fails then it will goto error block

please find example here on stackBlitz.

Converting HTTP observable to promise

If you convert Http observable to promise using the toPromse method, then we can use it as a normal promise.

it’s look like nested subscription, but there is no fear of memory leakage, once resolved then that’s it. No need to destroy it.

for eg.

import { Component, VERSION, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { mergeMap } from 'rxjs/operators';
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit  {
  name = 'Angular ' + VERSION.major;
  constructor(private httpClient: HttpClient){
  }
  userDetails: any;
  ngOnInit(){
    this.httpClient.get('https://jsonplaceholder.typicode.com/posts/1')
    .toPromise()
    .then((res: any)=>{
      this.httpClient
        .get('https://jsonplaceholder.typicode.com/users/'+res.userId)
        .toPromise()
        .then(authorDetails=>{
          console.log(authorDetails)
        })
    })
  
  }
}

find example here on stackBlitz

Conclusion:

It depends upon the condition which one to use at what time. But in case n number of Http calls you need to find the best way to handle it.