Android: Centralized Error Handling in Network Calls
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
- My API call is successful and the call is in
onResponse
- My response code is
200 OK
- 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.
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.
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.
ExampleApiResponseModel
model class
BaseApiResponseModel
Parent of response model classes
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
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.