Search code examples
angularrxjsangular7

How to make multiple API calls using ConcatMap with conditions


In Angular 7, I am trying to invoke two different API methods sequentially. If first one is successful then need to call second API method.

If first API response code is 500 internal server error then second API should not be invoked. Also I need to handle errors for each API calls.

I tried Promise, async and await approach but when I check in developer tools, could see second one is invoked even if first API does not return any response.

Can someone please help me to achieve this using concatmap or any other Angular approach.

public fetchandUpdate() {
    this.isSuccess= false;
    this.errorMessage = "";
    this.displayMessage = false;

     // First API call
      this.myService.getUserDetails(this.userid)
      .subscribe(
        (response) => {                           
          console.log('response received')
          this.userdetails= response;
        },
        (error) => {                              
          console.error('error caught in fetching user details')
          this.errorMessage = error;
          this.isSuccess= false;
        }
      )

    // Need to call this only if first API's response http status code is not 500
   if(firstAPIresponse.statuscode != 500)
   {
    this.myService.updateUserDetails(this.userdetails)
          .subscribe(
            (response) => {                           
              console.log('response received')
              this.isSuccess= true;
            },
            (error) => {                              
              console.error('error caught in updating user details')
              this.errorMessage = error;
              this.isSuccess= false;
            }
          )
      

     // This value should be updated only if above two is successful
      this.displayMessage=true;
    }
  }

Solution

  • You can use switchMap to accomplish this.

    // First API call
    this.myService.getUserDetails(this.userid).pipe(
      // Logging is a side effect, so use tap for that
      tap(res => console.log('First API success', res)),
      // Call the second if first succeeds
      switchMap(resultFromUserDetails => this.myService.updateUserDetails(this.userdetails).pipe(
        // Handle your error for second call, return of(val) if succeeds or throwError() if you can't handle it here
        catchError(err => { 
          console.log('Error for second API (you can use statusCode here)', err);
          return of(); 
        }),
        // Logging is a side effect, so use tap for that
        tap(res => console.log('Second API success', res)),
      )),
      
      // Handle your error for first call, return of(val) if succeeds or throwError() if you can't handle it here
      catchError(err => { 
        console.log('Error for first API (you can use statusCode here)', err);
        return of(); 
      }) 
    ).subscribe(
      // handle both successfull
      resultFromUpdateUserDetails => {
        console.log('Both APIs succeeded, result from 2) is returned', resultFromUpdateUserDetails);
      },
      // handle uncaught errors
      err => {
        console.log('Any error NOT handled in catchError() or if you returned a throwError() instead of of() inside your catchError(), err);
      } 
    )
    

    Update: You can, of course, do some logic inside your switchMap

    this.myService.getUserDetails(this.userid).pipe(
       switchMap(res => {
         // do something with res, or other logic here
    
         // make sure to return your new observable at the end
         return this.myService.updateUserDetails(this.userdetails);
       })
    );