DEV Community

Mariusz Sołtysiak
Mariusz Sołtysiak

Posted on • Originally published at mariuszsoltysiak.hashnode.dev on

Error handling in Retrofit using NetworkResponseAdapter library

Im currently working with my team on a new project. One part of it is a gateway service that distributes calls between microservices and/or merges results. We've been looking for a good solution to properly make requests using coroutines. Another requirement was to handle properly responses from the API and that we wont need to handle manually all common error results or IO exceptions.

After looking for some options we found out Retrofit to be the perfect fit for our purpose. But it wasn't easy to find a proper solution to handle successful and failed responses. Id like to give you a simple example of how to configure Retrofit using the NetworkResponseAdapter library to properly and gracefully handle responses in your code with a simple extension function.

Lets define a simple Retrofit client interface with one method to get a list of categories:

https://gist.github.com/marrek13/f35fdd24eb18ecee90826f92b76c53da

The problem with this definition is that when there is an exception we will expose the network exception directly to our application layer. It is not a great solution and its better to throw instead some contextual exception connected with what the client is doing. To achieve this goal we defined our own exception:

https://gist.github.com/marrek13/e1405c25fe6ee70aa1afa380cbd70004

We added one line to the Retrofit builder

.addCallAdapterFactory(NetworkResponseAdapterFactory())

Enter fullscreen mode Exit fullscreen mode

Then the client was modified to use NetworkResponseAdapter:

https://gist.github.com/marrek13/fc3cc307bb8441c7e575c789e0b744c7

NetworkResponse is a sealed class whose result can be one of the classes below:

  • NetworkResponse.Success : an object containing the successful result with response data for any 2XX response

  • NetworkResponse.ServerError : an object which contains the response from the call that resulted in a non-2XX status

  • NetworkResponse.NetworkError : the result of a request that didn't result in a response

  • NetworkResponse.UnknownError : the result of a request that resulted in an error different from an IO or Server error

  • NetworkResponse.Error : object for any other possible response not covered by any of previous cases

As you noticed we need to provide the type arguments for deserialization: first for the Success response and the second for the ServerError response.

To achieve the goal which is easy handling of all exceptions/errors in the same manner we introduced an extension function to the NetworkResponse class:

https://gist.github.com/marrek13/467be212bd60c38b8883f65cca58b0b9

Having all of this together, we can easily call our API in the service without being worried about leaking the IOExceptions from the Retrofit client:

https://gist.github.com/marrek13/506fd4ed9d881a9ce9aab15db7a6f83f

And thats it. Adding the call() to all places where the client is used is the only downside of this solution. But in general, we consider it as the most elegant and easy-to-read and test solution.

Top comments (0)