RxJS error handling strategies in Angular
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 pageCatchErrorComponent
: Contains example on catching an error and handling it gracefullyRethrowErrorComponent
: Contains example on rethrowing an error caused by an http callRetryErrorComponent
: 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 retriesdelay
: how long to wait before attempt a retryresetOnSuccess
: 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.