Instructor: Any application that uses external services should be able to handle errors that may occur. Let's see what happens in this application if we deliberately cause an error.
If we go back to the epic and remove this filter, which is stopping empty values from causing an Ajax request, and go back to the browser...If we first do a successful search and then delete all the characters, you can see that we got an API error, invalid query params.
You can see the error down here. Everything has stopped. The app is now unresponsive. It doesn't matter that we actually faked the error. The point is that at this point, the application cannot handle a 400 error response from the API.
The first step to solving this is to model the data in the reducer. If we open up this bs reducer, just below fetch fulfilled, we'll add another case that can handle the failure. We'll say, "fetchFailed."
In that case, we set the status to failure. We add an object here, to the messages array, as a type of error and text being the payload. This will allow us to pass the error from the API response back into the store.
We need to create this fetchFailed constant. We'll need an action creator for it as well. We can just copy that and say, "fetchFailed." We'll be sending through a message. We'll do that. We'll change this to fetchFailed.
Now that we have this fetchFailed constant, we can go back to our reducer and import it here. Since we are populating this array with an error message upon failure, we need to go to the success case and ensure that we clear that message just by setting it back to an empty array.
Now we've modeled the data in terms of the Redux store. Now we just need to go and handle that error. Since the error is coming from this Ajax response, directly after the map, we can catch the error. We use the catchError operator that we can import from rxjs/operators. This will give us access to that error.
CatchError is interesting because not only does it give us access to this error here, it also allows us to return a new observable. This is just what we need because upon failure, we want to dispatch an action into the store that indicates that failure happened.
We can return of, which will be an observable of a single value in this case. We can use that action creator that we made, fetchFailed. We can pass along error.response.message. Now let's see what happens in the browser.
If we cause the error by typing some characters and then deleting them all again, you can see that we do indeed get this network response, but notice we don't get the error thrown in our application.
If we check the Redux DevTools, we'll actually see that here we set the status to pending, meaning the Ajax request began. Then we got a fetchFailed action. Because of the code we added in the reducer, you can see that it's updating the status to be in a failure and it's added a message to the messages array.
The last thing left to do is to display the message here for the user. If we go to the bs component, you can see that we are currently accessing all of the state from the bs reducer. That means that we can just use the messages from here. Just below this check for success here, we can add another one to check for failure.
If there was a failure, then we'll just output the text from the first message. Go back to the browser. Create the error again. Now you can see the error is displayed. It's no longer thrown here. The best part is that the app is still responsive, so we can begin searching again.