Those kotlin handy extensions, Retrofit meet Kotlin and Result

Alejandro Moya
Oct 6, 2018 · 2 min read

Being an Android and iOS developer is crazy sometimes, you have to deal with the things each platform gives you, the differences, sometimes big, sometimes not, and sometimes they’re similar.

Since Swift and Kotlin appeared, they gave us a way to make these different worlds become closer, more alike, more functional?, more type-safe?, well, you know what i mean… 😝

I’ve used Alamofire in iOS projects many times, it’s so pleasant, the API is awesome, using Result to handle the responses, it makes the code look more readable, i wished this existed in Android but in JAVA everything was Interfaces used as Listeners and all that.

Now with Kotlin we can make that happen, in fact, i did it and will give you an extension that will make retrofit look more like Alamofire, cool isn’t it?

First let’s create a minimal version of Result, here’s the snippet 👇

sealed class Result<T> {
data class Success<T>(val call: Call<T>, val response: Response<T>): Result<T>()
data class Failure<T>(val call: Call<T>, val error: Throwable): Result<T>()
}

We are using a sealed class to have a “enum” that can handle the different results, we need to make it generic to pass the types that will come from retrofit. As you can see, each class/case has the parameters that come from the Callback interface.

Next we are going to create the extension that will allow us to use encode in a kotlin/alamofire/result way:

inline fun <reified T> Call<T>.enqueue(crossinline result: (Result<T>) -> Unit) {
enqueue(object: Callback<T> {
override fun onFailure(call: Call<T>, error: Throwable) {
result(Result.Failure(call, error))
}

override fun onResponse(call: Call<T>, response: Response<T>) {
result(Result.Success(call, response))
}
})
}

Here we create a new enqueue method that will receive a closure that has Result as the input, we call the original enqueue and then call the result closure sending the expected Result.

Now that we have these in place let’s use them together:

//let's say that we have a login method
val call = service.login(username, pass)
//we call the new enqueue
call.enqueue { result ->
when(result) {
is Result.Success -> {
//myData will have the type passed from the service method
val myData = result.response.body()
}
is Result.Failure -> {
Log.d("MyAndroidApp", result.error.toString())
}
}
}

As you can see we don’t need to do the object: Callback { ... and overrides and all that anymore, the types are respected!

Hope you find this extension useful, please let me know if you use it, also leave any comments if you believe i could improve it.

Alejandro Moya

Written by

Mobile developer, Father, geek, this is my first attempt at having a blog, be kind 😄

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade