Error handling: Make your Exceptions nicer

David Bilík
Ackee
Published in
3 min readJun 28, 2018

--

Error handling is hard and every developer I know doesn’t like to do it. It’s almost always the last thing to be done in a new project. You have to handle different kinds of errors — from no network connectivity, to servers being down, to user-made validation errors (either local or server-side) all of which lead to a cumbersome correcting process for all parts of the app. I would like to show you our approach to this.

Our setup is a common one — for the API layer we use Retrofit with OkHttp client and the data is read reactively via RxJava2. The architecture of our apps is MVVM (but it doesn’t matter so much since this can be applied even for MVP). Our ViewModel holds an instance of some Repository and this repository is responsible for calling Retrofit API — simple enough.

Example of Error Handling

Let’s model our example on a simple login request — email, password … nothing more.

Imagine a situation where we have some server that returns a 401 status code on invalid credentials, a 400 on validation errors and a 200 with a user object when all goes smoothly. 400 requests have error bodies with additional info of which field has what validation error, like:

And now we want to handle all possible errors that can happen when making a request to this api.

So, here’s how some general first-thought error handling for a Login screen could look:

Phew, that was a lot of code. A lot of ugly code. First, to clarify some things — In this scenario it looks as though the Repository layer is useless but in the real world, it contains more logic and as we will see, it will be useful for us too.

So, the error handling is not very nice .. and imagine having to do this to every api request in all places in the app. ugh ..

Other than it not being very nice, it’s also not clean — the logic behind error processing, error body format, and all other possible situations that can arise from this request, does not in any way belong to View layer. Where does it belong? ViewModel? Nope. ViewModel is just a link between Model (business logic) and View. In our case, Model is Repository so that’s the piece that should contain this logic. So let’s make it a little nicer.

First let’s introduce some more classes representing possible errors 🤓:

and now let’s move the code from the View to Model:

We are using the operator onErrorResumeNext from RxJava that maps errors to different streams. We just map it again to error stream but with mapped Retrofit Exceptions to our domain exceptions. Now the error handling in view model looks a lot nicer:

Beautiful. Some of the stuff can be generalized with a little help from Kotlin extensions.

First, the error mapping in Repository still needs to be done for every request so we can extract the common part elsewhere

Let’s create an extension called mapApiExceptions on Single that will do the common stuff:

It accepts an optional mapper function from HttpException to other Exceptions. If this function is null or if it returns null, map the results to GeneralServerException.

Now our repository code changes to:

View layer can also be optimized, GeneralServerException, NoInternetException and UnexpectedException will probably be handled the same in all places, so abstract it:

If we compare our original code to the current one, one has to smile at how beautiful it is. It’s pretty easy to process another api request in a different part of the app.

Another improvement that can be done is to map exceptions to our domain exceptions automatically in a OkHttp Interceptor/Retrofit CallAdapter, but that’s a topic for a different blog 🙃.

Disclaimer: The code in this blogpost can be taken as a pseudocode, there are a lot of not implemented methods that were not crucial for this blog to be mentioned.

--

--

David Bilík
Ackee

I am lead Android developer @ Ackee. I make sure that everyone is happy.