Exception Handling with NgRx Effects
Recently I’ve been working with NgRx and learning about how to use the effects and the store. I implemented NgRx in my weather app Goose Weather, and learned a great deal about both RxJs and state management with Redux.
I also recently went through the Pluralsight course “Angular NgRx: Getting Started” with Duncan Hunter and Deborah Kurata. This course gave a good introduction to the concepts behind NgRx, and highlights best practices. One of the big things that I learned from the course was proper ways to handle exceptions and handle errors with NgRx effects. I thought it was cool, and wanted to write about what I learned.
I’m going to walk through how I setup error handling with NgRx in Goose Weather. I’m first going to discuss handling errors with Observables, and then go into how I setup Goose Errors to handle errors in an effect.
With this walkthrough, I’m going to assume you’re already familiar with NgRx and Angular. If not, I recommend the NgRx Pluralsight course I mentioned as well as the documentation on the RxJs and NgRx sites.
Exception Handling with Obervables vs. Promises
In the world of Promises you would typically handle errors with something like the following:
This code is pretty straightforward. You make a call to something that generates a promise and then include a catch clause. This code is also cheating a little since it is wrapping an http client observable in a Promise. however, the use of catch is what I wanted to highlight here. If you wanted to use this method, you would listen for the response and handle it if it was an error like this:
So here, note that if an error is thrown in the method, it is caught and then rethrown wherever it is called. This passes the error from the method into whatever is calling it.
When working with observables, you have to capture errors that are returned from the stream. The same idea of catching and rethrowing errors occurs, but it is handled with operators like catchError and throwError like you see here:
When you use the catchError operator you are adding error handling to the observable itself. When an error occurs catchError will allow you to create a value to return to the stream that covers when an error occurs. Using throwError here creates an observable that is returned from this call that replaces the value that would have been returned on success.
Additionally, when you combine several observables with operators like mergeMap or switchMap you can handle rethrowing errors like this:
Here you see two service calls (1) getNoaaMetadata and (2) getNoaaWeeklyForecast being combined together for a single output. If an error is thrown in either one of these service calls the catchError will take the error that was thrown by the individual observables, and rethrow it back up to where it was called.
There are also multiple ways to handle errors with observables. I recommend reading through the Angular University article here for a more in depth walk through.
Handling Errors with NgRx Effects
Now that you have an idea of how observables handle errors, you can apply these same principles to error handling with NgRx.
My Goose Weather application only potentially has errors when it makes API calls for the weather forecast. When the user’s location is updated, an action is fired off to update the location information in the store. When the location information is updated, an effect fires off for the location action that calls the weather service that provides the weather forecast. This is where I applied my error handling with NgRx.
To start, the application makes a service call in an effect when the location is updated with a LoadLocations action like you see here:
When an error happens, the catchError operator is used, and then of returns an observable with aLocationsError action to update the store.
This is defined in the Locations Actions with the following:
The successful LoadLocations action takes in a null value for error. The LocationsError action takes in a null value for location and a value for error.
I have a condition for the error action in my Location Reducer as you see here:
When the action fires off of type LocationsError then the correct payload is returned to the store to indicate an error has occurred.
In order for components in Goose Weather to access the error data, I also created a selector for error here:
Finally, in order to show error messages to the user I subscribe to the error selector in the Goose Weather’s weather component with an observable like you see here:
Then I added an *ngIf to the weather component’s template with the async pipe to respond if an error message is returned here:
The final result is that when error’s occur they are shown as a message at the top of my application like you see here:
If you run the application with the Redux Devtools Chrome Extension then you also see the error value is correctly loaded into the store here as well:
This process shows you the power of using NgRx, and how easy it is to implement error handling with your Angular applications. In a larger application, you could imagine multiple components subscribing and responding to error events from the store. The implementation I’ve gone over here also highlights how you can handle errors when you’ve got multiple observables in Angular services. I hope you enjoyed the walkthrough, and this post helps you to better understand exception handling with NgRx effects.
Special thanks also to Tim Deschryver for his input on the correct ways to handle errors with effects!
Originally published at rhythmandbinary.com on March 4, 2019.