Blog Infos
Author
Published
Topics
, ,
Published

Retrofit is every Android developer’s favourite library for making API calls and there is no doubt about it.

Then what is Ktor Client and why do we even need it when we already have an awesome library named Retrofit to do the same in minimal code? Let’s try to find answers of all these questions. In this article I will not only tell you why you should give Ktor-Client a shot, but also show you how to implement REST APIs in Ktor Clients.

What and Why?

Let’s check out first what Ktor-Client is.

In simple words, Ktor-Client, just like Retrofit can be used to make API calls, with functionalities such as adding headers, choosing from various serialization libraries and much more.

Now the next question arises, why?? Why do we need a new networking library when we already have Retrofit???

Retrofit is great when we want to use a networking library for our Android native apps. But how about we want to use something similar in other platforms as well? When I say other platforms, I bet Kotlin Multiplatform comes to your mind as one of the options as well. Kotlin Multiplatform is trending especially after Google launched a stable version of Jetpack Compose last year.

Ktor-Client can not only be used for networking in native Android specific applications, but also when we are working on multi-platform Kotlin projects, unlike Retrofit which is platform-specific. This knowledge of using Ktor-Client will not only help in developing for Android, but also developing multiplatform projects. Besides this, knowledge and familiarity with Ktor will also help us developing APIs as discussed in my previous article here

Ktor uses coroutines internally for asynchronous programming which makes our code very clean and minimal just like coroutines did with suspend functions. Moreover it is as easy to add headers, serialization, logging etc in our app, as it is with Retrofit.

With the popularity of Kotlin Multiplatform and it being adopted by various companies, especially startups, I am positive that it has a chance of replacing Retrofit in coming years. It is developed by JetBrains, so they will keep adding more and more features in coming time.

Enough talking and theory!! Let’s now jump straightaway to the coding part. We will be adding popular unsplash API in our project with authentication to our header. I will be using the MVVM architecture and skipping the UI and the ViewModel part as it is out of scope of this article. However, if you want to check the complete working code on GitHub, it can be found here.

How?

First of all, just like we do it with Retrofit, we will add an API Service interface, which will consist of function declarations. We will use only one API in our app, which will fetch the list of images from our app. ImageResponse here is the response data class.

interface ImageService {
suspend fun getImages(): ImageResponse
}
view raw ImageService.kt hosted with ❤ by GitHub

That’s it?? It’s same as Retrofit!! Where are the queries? Where is the url?? Where are the headers???

Let’s find out the answer and I will also discuss how these both differ internally the way they work.

If I were to use Retrofit, the syntax would be something similar to -:

interface ImageService {
@GET("/photos?page=1")
suspend fun getImages(): ImageResponse
}
object RetrofitBuilder {
private const val BASE_URL = "https://api.unsplash.com/"
private fun getRetrofit(): Retrofit {
return Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
val apiService: ApiService = getRetrofit().create(ApiService::class.java)
}

Retrofit uses reflections internally which creates these classes and objects required for http connection during runtime without knowing the names of the interfaces, fields, methods at compile time. If we dig more deeper, OkHttp is used by Retrofit which helps to communicate with sockets.

Let’s see how it goes in Ktor-Client and where do we specify our base url, endpoint, queries etc.

class ImageServiceImpl(
private val client: HttpClient
) : ImageService {
override suspend fun getImages(): ImageResponse {
return client.get {
headers {
append(HttpHeaders.Authorization, "Client-ID ${BuildConfig.CLIENT_ID}")
}
url(HttpRoutes.FETCH_IMAGES_URL)
}
}
}
object HttpRoutes {
private const val BASE_URL = "https://api.unsplash.com"
const val FETCH_IMAGES_URL = "${BASE_URL}/photos?page=1"
}

Job Offers

Job Offers

There are currently no vacancies.

OUR VIDEO RECOMMENDATION

, ,

Brick by Brick: Building Open Source libraries

So you have an idea, and you want to publish a library for it? But where do you start? Doing Open Source is a fine art which requires skill you don’t easily learn on schoolbooks.
Watch Video

Brick by Brick: Building Open Source libraries

Paolo Rotolo & Nicola Corti
Android Engineer & Kotlin GDE - Android
Nextome & React

Brick by Brick: Building Open Source libraries

Paolo Rotolo & Nic ...
Android Engineer & K ...
Nextome & React

Brick by Brick: Building Open Source libraries

Paolo Rotolo & N ...
Android Engineer & Kotlin ...
Nextome & React

Jobs

Ktor-Client does not use the reflection APIs or OkHttp, instead it uses an asynchronous client to perform HTTP requests named HttpClient which uses HttpResponsePipeline and HttpRequestPipeline, former to process all the responses sent by the server and latter for processing all the requests sent by the client.

Http.get specifies that we are making a GET request to our API, we can use Http.post to make a POST request. The lambda function is HttpRequestBuilder where we have specified our header, which in our case is Authorization and our url. Just to clarify HttpHeaders.Authorization is nothing but a string with value “Authorization” provided inbuilt by Ktor. In case you’re curious about other use cases of HttpRequestBuilder, we can specify request method, request body etc in it.

All looks till now good except one thing, where do we specify serialization options/libraries and logging options just like we did with in our RetrofitBuilder class? How does KtorClient serializes/deserializes the request/response? Don’t worry I got you covered.

Let’s get back to our ImagesService class and modify it to meet these requirements.

interface ImageService {
suspend fun getImages(): ImageResponse
companion object {
@ExperimentalSerializationApi fun create(): ImageService {
return ImageServiceImpl(
client = HttpClient(Android) {
install(Logging)
install(JsonFeature) {
serializer = GsonSerializer()
}
}
)
}
}
}

We have already discussed about HttpClient. “Android” here is an implementation of HttpClientEngineFactory interface. Let’s keep that out of scope of this article. Let’s discuss the lambda function. This is a HttpClientConfig class which in turn is a mutable configuration used by HttpClient. Let’s check out some code of HttpClient by Ktor Library to understand the role of HttpClientConfigclass better.

public class HttpClient(
public val engine: HttpClientEngine,
private val userConfig: HttpClientConfig<out HttpClientEngineConfig> = HttpClientConfig()
) : {
init {
with(userConfig) {
config.install(HttpRequestLifecycle)
config.install(BodyProgress)
if (useDefaultTransformers) {
config.install(HttpPlainText)
config.install("DefaultTransformers") { defaultTransformers() }
}
config.install(HttpSend)
if (followRedirects) {
config.install(HttpRedirect)
}
config += this
config.addDefaultResponseValidation()
config.install(this@HttpClient)
}
}
/**
* Returns a new [HttpClient] copying this client configuration,
* and additionally configured by the [block] parameter.
*/
public fun config(block: HttpClientConfig<*>.() -> Unit): HttpClient = HttpClient(
engine,
HttpClientConfig<HttpClientEngineConfig>().apply {
plusAssign(userConfig)
block()
},
manageEngine
)
}
view raw HttpClient.kt hosted with ❤ by GitHub

To make it clear, anything we add in the block of HttpClient class, just like we added our Logging and GsonConvertor libraries for logging and serialization/deserialization respectively, will be added to HttpClient and used while executing. This is just like adding up some default libraries like HttpSend, HttpRedirect etc with our custom block we specified with our ImageService interface.

Now the only thing left is how to call this from our repository??? Let’s check the code for that as well.

suspend fun fetchImages(): Result {
return withContext(Dispatchers.IO) {
try {
val result = ImageService.create().getImages()
Result.SuccessWithData(result)
} catch (exception: Exception) {
Result.Error(exception)
}
}
}
view raw ImagesRepo.kt hosted with ❤ by GitHub

We use a coroutine to call our method from ImagesService as this is an asynchronous operation. That’s it! Now we can use this method in our ViewModel and update UI accordingly. As mentioned earlier, I will keep that out of scope of this article, you can visit the Github repo with the complete working project here

Are you loving it already????? Yes, me too!! Let’s implement it in our projects already then?? Is it alright to completely replace Retrofit in our projects and replace it with KtorClient??? Let’s find an answer to this.

When?

As discussed earlier, Ktor-Client can not only be used for networking in native Android specific applications, but also when we are working on multi-platform Kotlin projects, unlike Retrofit which is platform-specific.

But it is worth to notice that Ktor is in very early stages and not used already in the industry at least as a replacement of Retrofit. It is good to use a new library to “experiment” or even use it in production for some easy-use cases. But there is limited community/published articles/documentation material available for KtorClient as compared to massive material and support available for Retrofit. So if you get stuck in a complex use case, it can be a hard time if using KtorClient.

What I feel is, it is completely fine to learn, experiment and implement KtorClient in Kotlin multiplatform projects which are pretty new and mostly used by startups, but it may not be worth replacing Retrofit with KtorClient in native production apps at this point of time. I am positive that more features, community and support will be available for Ktor and KtorClient in coming future very soon. But for now, I will go with retrofit for native android apps and ktor-client for multiplatform.

Ps-: All this is based on my personal opinion and preferences, things may change with time and opinions may vary from person to person. Do let me know in the comments your opinions and experience with Ktor-Client. The code for the project can be found here. Thanks for taking out the time to read this article.

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
Modern mobile applications are already quite serious enterprise projects that are developed by hundreds…
READ MORE
blog
This tutorial is the second part of the series. It’ll be focussed on developing…
READ MORE
blog
We recently faced a problem with our application getting updated and reaching slowly to…
READ MORE
blog
A few weeks ago I started with a simple question — how to work…
READ MORE

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.

Menu