Updated 22 March 2021
In this blog, we are going to talk about how we can handle api response either is success or failure in coroutines with Sealed class.
When I started using coroutines for calling the api, I used try/catch block to handle the exceptions. I had to write this try/catch block every single time when I called any api.
NOTE : To learn more about kotlin coroutines & suspend functions, please check following link : Call api with coroutine
I also got a situation where I needed to call my api again if I got any error in response. I needed a solution through which I can handle all the exception at single place and my api calling method only receives success data.
I found a solution through which I can handle api response at single place. And the solution is wrapping your response in Sealed class.
Sealed class represents set of options wherein value will be among these options only.
Sealed class in kotlin is just like enum class. But in Enum class, set of constant can have only one type or only single instance whereas subclass of sealed class can have multiple instance.
Enum class is data type which contains a set of constant.
For example :
1 2 3 4 |
enum class NetworkResponse { SUCCESS, FAIL } |
The value will be either SUCCESS or FAIL. It allows only single instance.
If you wanna know more about the failure reason, you can’t get it with enum class.
Sealed classes represent hierarchies. Child classes can be data class, object class, normal class or any other seal class as well.
Suppose, we are calling an api and we may receive 2 type of responses ->
NOTE: Here, I’m using retrofit for api calling.
Now, create a sealed class to handle these cases ->
1 2 3 4 |
sealed class ResultWrapper<out T> { data class Success<out T>(val value: T): ResultWrapper<T>() data class GenericError(val error: Exception? = null): ResultWrapper<Nothing>() } |
Here, ResultWrapper is sealed class name.
ResultWrapper<out T> ==> We can handle any type of model class response here.
Let’s take an example. Suppose, we wanna call login api to get customer data.
ApiInteface is retrofit api interface, which is responsible for calling the apis. getCustomerData is suspended function to call customer api. Here, CustomerResponse is my model class.
1 2 3 4 5 6 7 |
interface ApiInteface { @FormUrlEncoded @POST(CUSTOMER_API) suspend fun loginApi( @Field("username") username: String, @Field("password") password: String): CustomerResponse } |
As suspend functions are only called by either suspend function or in coroutine scope. Here, I’m using viewModelScope scope. I will receive response either ResultWrapper.Success type or ResultWrapper.GenericError.
If you wanna handle all exception commonly, then you can remove condition for ResultWrapper.GenericError.
1 2 3 4 5 6 7 8 9 10 11 |
viewModelScope.launch { val result = Repository.callApiLogin(apiInterface, "test", "testpassword") when (result) { is ResultWrapper.Success -> { result.value // get result as CustomerResponse model class } is ResultWrapper.GenericError -> { var exception : Exception? = result.error } } } |
1 2 3 4 5 6 7 |
object Repository { suspend fun callApiLogin(apiInterface: ApiInteface, username: String, password: String) : ResultWrapper<CustomerResponse>{ return CustomNetworkCall.safeApiCall() { apiInterface.loginApi(username, password) } } } |
I create an object class Repository and call it’s method within viewmodelscope to get api data.
CustomNetworkCall is my class where I handle api response.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
object CustomNetworkCall { suspend fun <T> safeApiCall(dispatcher: CoroutineDispatcher = Dispatchers.IO, apiCall: suspend () -> T): ResultWrapper<T> { return withContext(dispatcher) { try { var result = apiCall.invoke() ResultWrapper.Success(result) } catch (throwable: Exception) { // show toast message or alert which error message // call same api again apiCall.invoke() or safeApiCall() ResultWrapper.GenericError(throwable) } } } } |
In catch blog, you can handle exception commonly and also return ResultWrapper.GenericError to handle error viewmodelscope as well. If you wanna handle all exception commonly, then handle it in this catch block only.
To learn more about sealed class, please check following link : Sealed class
Hope, this blog will be helpful to you.
If you have more details or questions, you can reply to the received confirmation email.
Back to Home
Be the first to comment.