Android: Centralized Error Handling in Network Calls

Mihodi Hasan Lushan
3 min readJul 21, 2020

--

A Typical REST communication between Android and Server

Working as an android developer, it feels very tiring, frustrating, and monotonous to write some boilerplate code again and again. I think, handling network calls is one of the major tasks of any android developers. Integrating REST-APIs using Retrofit is just fun though nowadays. I have been working professionally in android development for more than 3 years and I have often heard about REST API response’s error centralization to get rid of boilerplate codes. Recently, I started developing my product for a livestock marketplace named Bepari where I tried to implement this but, I haven’t found enough useful information on the internet about this. So I developed my own.

First, we need to know what is error centralization and why that is important?

Think precisely, what is the general steps that we follow whenever it comes to integrating a new RESTful API to android? I am considering you are working on a project that currently does not have any REST API calls. Conceptually, the first thing you will do is adding the retrofit Gradle dependencies. Then you will be creating your ApiClient using your own BASE_URL and timeout, SSL pinning, and other configurations. After that, you will be writing abstract methods in your interface with API request type(ex. GET, POST, PUT, etc), endpoint, and parameters. Voila, you are done with all your set up. You are able to make calls to your preferred APIs every time from your Activity, Fragment, or Model, you write something like this,

ApiClient.getClient().connectToServer("param1", "param2")
.enqueue(object : Callback<YourModelClass?> {
override fun onFailure(call: Call<YourModelClass?>, t: Throwable) {
//You Want To Show A Alert Of Failure
}

override fun onResponse(
call: Call<YourModelClass?>,
response: Response<YourModelClass?>
) {/*
if response code != 200 OK Show A Alert Of Failure
else
if business logic success
Your Implementations
else Show A Alert Of Failure */
}
})

check the above code block again precisely. On every API call, you need to override 2 methods on which mostly 3 cases are same and redundant and that is error handling depending on your response success or failure, depending on your response code and depending on your business logic’s status flag.

I want to separate this error handling layer and write my implementations if and only if

  1. My API call is successful and the call is in onResponse
  2. My response code is 200 OK
  3. My business logic status flag is successful

Let’s dive into the code now if your interest matches with my purpose.

  • ApiClient class

As I said earlier, just after adding the Gradle dependencies, we first need to know about the BASE_URL and set up our ApiClient class. I will not be changing anything on this part. In my case check the ApiClient. For simplicity, I won’t be creating any BuildVariant and won’t be following any design pattern too.

ApiClient.kt
  • ApiService interface

Then we need to request body and request type (GET, POST, PUT, DELETE etc) to write our ApiService (the interface that is going to be returned by retrofit client) Interface. I won’t be changing anything here too.

ApiService.kt

You will need to understand the response data model next here. Since we are trying to centralize the API response error handling part, we must have a unified response format in every API response. This is necessary since I will be adding an extra abstract layer before getting your API success implementation callback to handle errors automatically. Here I am attaching my preferred format.

ResponseFormat.json
  • ExampleApiResponseModel model class
ExampleApiResponse.kt
  • BaseApiResponseModel Parent of response model classes
BaseApiResponseModel.kt
  • MainActivity activity

Finally, I am invoking my ApiClient and implementing my getExampleString method.

ApiClient.getClient().getExampleString()
.enqueue(
object : CentralApiCallBack<ExampleApiResponseModel?>(
this
) {
override fun handleResponse(
call: Call<ExampleApiResponseModel?>?,
response: Response<ExampleApiResponseModel?>?
) {
Utils.showPopup(
this@MainActivity,
getString(R.string.success),
response?.body()?.data?.yourCustomData
)
}
})

Utils.showPopup() is invoked here which is not described, check out the full repo linked to the bottom of this article if needed.

Here, I am not using Callback<T> from the retrofit, instead, I have created an abstract class CentralApiCallBack that is actually providing the error handling abstraction layering part.

  • CentralApiCallBack helper class that handles the error
Where all magic happens

Full Source

Special thanks to MD.FAHIM HASNAT for his support to provide the API as needed for this article.

I am ready to write 100 new lines to ignore writing the same line twice.

--

--