RxJS error handling strategies in Angular

18-03-2023
source code

Introduction

In this article I will go through various methods you can use to handle errors in RxJS with Angular

Background

Handling errors when using RxJS in Angular can take various forms. Sometimes you want to handle the error gracefully, rethrow the error or simply attempt a retry. Although RxJS can be used in non http calls scenarios this article will focus on handling error when using RxJS for http calls in Angular

Sample App

The sample app was created using Angular cli. It contains 4 components:

  • HomeComponent: home page
  • CatchErrorComponent: Contains example on catching an error and handling it gracefully
  • RethrowErrorComponent: Contains example on rethrowing an error caused by an http call
  • RetryErrorComponent: Contains example on retrying a call that caused an error

The app contains a search input box that takes in a user id and search for it. If the user is found then the result is showing otherwise a message is showing depending on the strategy that is being used to handle the error.

JSON server

I have used json-server to create a simple api that takes in http calls. The data for the api is stored in server/data.json file.

Running the app

You need to run the ui and server in two separate commands as follows. From the source directory issue the following commands:

# to run UI
npm run start
# To run server
npm run server

Catch Error strategy

In this strategy you simply catch the error and handle it gracefully. The code below explains this strategy.

searchHandle() {
    this.httpClient.get(`http://localhost:3000/users/${this.userIdSearch.value}`)
        .pipe(
            catchError(err => {
                this.userSearchResult = `No user found for id ${this.userIdSearch.value}`
                return of({})
            })
        )
        .subscribe((x: any) => {
            if (x && x.id) {
                this.userSearchResult = `user id: ${x.id}; username: ${x.username}; country: ${x.country}`;
            }
        });
}

searchHandle is the function used to search for users. catchError operator kicks in when an error occur (To force an error send an id that is greater than 3).userSearchResult will hold the result, in this case it will a message rather than user details. catchError also returns an empty object so the subscribe (next) method can get a meaningful result rather an error.

Rethrow error strategy

In this strategy you rethrow the error and let the calling chain handles it. The code below explain this strategy in more details

searchHandle() {
    this.httpClient.get(`http://localhost:3000/users/${this.userIdSearch.value}`)
        .pipe(
            catchError(err => {
                this.userSearchResult = `No user found for id ${this.userIdSearch.value}`;
                return throwError(() => err)
            })
        )
        .subscribe((x: any) => {
            this.userSearchResult = `user id: ${x.id}; username: ${x.username}; country: ${x.country}`;
        });
}

throwError method with throw the error as an observable. As you can see we are not handling it further. This error will show in the browser console. What is interesting here is that the subscribe method (next) will not be called because there was an error and since we don't have error handing function then it will propagate to the default error handler in Angular.

Retry strategy

Using the retry operator you can specify how many times you want the call to be retried if an error is thrown. See code below for an example.

searchHandle() {
    this.httpClient.get(`http://localhost:3000/users/${this.userIdSearch.value}`)
        .pipe(
            retry({count: 2, delay: 200, resetOnSuccess: true})
        )
        .subscribe({
            next: (x: any) => this.userSearchResult = `user id: ${x.id}; username: ${x.username}; country: ${x.country}`,
            error: (error) => this.userSearchResult = error.error.message
        });
}

The retry operator takes in a config with the following properties:

  • count: number of retries
  • delay: how long to wait before attempt a retry
  • resetOnSuccess: reset the count on success

Here after attempting all retries we will endup in error function provided that the retry was unsuccessful. Note that in this example we are reading the error message sent by the server.

Summary

In this article I explained the various strategies that you can use to handle errors in RxJS with Angular.