Search code examples
javascriptangularrxjs6

How to keep observable chain going after http error in one observable


I've got a chain of observables. Here is the piece of code:

        //get dynamic tree 
      flatMap(res => this.dynamicReportId !== null ? this.reportService.getDynamicTree(this.dynamicReportId) : of({})),
      tap(res => this.dynamicTree = res),
        //get dynamic report 
      flatMap((res) => this.dynamicReportId !== null ? this.reportService.getDynamicReport(this.dynamicReportId) : of({})),

However when I got 500 API error from the first request(get dynamic tree), the chain stops and never enters the second flatMap(dynamic report).

Here is the function this.reportService.getDynamicTree():

 get(path: string, params: HttpParams = new HttpParams()): Observable<any> {
    return this.http.get(`${environment.apiBaseUrl}${path}`, {headers: this.setHeaders(true), params: params}).pipe(
      catchError(error => this.processError(path, error)),
      map((res: Response) => res));
  }

where this.processError returns observableThrowError(res);

What should I return in case of error to continue the chain? Or is the reason in other things?


Solution

  • In case of an error, an Observable completes, so if you want to return a new Observable after an error occurs, you have to use the catchError operator like this:

    //get dynamic tree 
    flatMap(res => this.dynamicReportId !== null ? this.reportService.getDynamicTree(this.dynamicReportId) : of({})),
    tap(res => this.dynamicTree = res),
    catchError(() => of({})),
    //get dynamic report 
    flatMap((res) => this.dynamicReportId !== null ? this.reportService.getDynamicReport(this.dynamicReportId) : of({})),
    

    The tap operator safely doesn't execute the callback and just forwards errors when they occur so that will assign this.dynamicTree only in case of a success.

    If you want to handle the error in the service instead of the component, you have to return something else than observableThrowError(res); from processError (for example of({})) but that will execute the tap callback and assign this.dynamicTree which is probably an unwanted behavior.