HTTP client in Kotlin: making requests correctly
Modern development for Android and backend services in Kotlin rarely goes without interaction with remote APIs. Creating a reliable HTTP client is a basic task, and the stability of the entire application depends on its correct solution. In this article, we will analyze how to make HTTP requests in Kotlin using two most popular libraries: Ktor Client and OkHttp. You will learn how to send GET and POST requests, process JSON, handle errors, and write clean, maintainable code.
Why Ktor Client is the choice of a modern Kotlin developer
Ktor Client is an asynchronous HTTP client created specifically for Kotlin by the JetBrains team. It fully supports coroutines, which makes the code concise and safe. Unlike OkHttp, Ktor is initially designed with multiplatform support in mind: the same code works on Android, iOS, JVM, JS, and Native.
Installing dependencies
To work with Ktor Client, add the following dependencies to the build.gradle.kts file:
dependencies { // Base client implementation("io.ktor:ktor-client-core:2.3.7") // Engine for JVM (OkHttp or CIO) implementation("io.ktor:ktor-client-okhttp:2.3.7") // For JSON serialization implementation("io.ktor:ktor-client-content-negotiation:2.3.7") implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.7") // Kotlinx Serialization implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2")}Simple GET request
Let's create an HTTP client and execute a GET request to a test API (JSONPlaceholder):
import io.ktor.client.*import io.ktor.client.request.*import io.ktor.client.statement.*import kotlinx.coroutines.runBlocking
suspend fun fetchUser(userId: Int): String { val client = HttpClient { // Basic configuration engine { // OkHttp engine settings } } val response: HttpResponse = client.get("https://jsonplaceholder.typicode.com/users/$userId") return response.bodyAsText()}
fun main() = runBlocking { val userData = fetchUser(1) println(userData)}Note: fetchUser is a suspend function. This allows it to be called from a coroutine without blocking the thread.
POST request with JSON body
To send data in JSON format, let's connect the ContentNegotiation plugin and define a data class:
import io.ktor.client.*import io.ktor.client.call.*import io.ktor.client.plugins.contentnegotiation.*import io.ktor.client.request.*import io.ktor.http.*import io.ktor.serialization.kotlinx.json.*import kotlinx.serialization.Serializableimport kotlinx.serialization.json.Json
@Serializabledata class Post(val userId: Int, val id: Int? = null, val title: String, val body: String)
suspend fun createPost(post: Post): Post { val client = HttpClient { install(ContentNegotiation) { json(Json { ignoreUnknownKeys = true prettyPrint = true }) } } val response: Post = client.post("https://jsonplaceholder.typicode.com/posts") { contentType(ContentType.Application.Json) setBody(post) }.body() client.close() return response}
fun main() = runBlocking { val newPost = Post(userId = 1, title = "Ktor Client", body = "Works great!") val createdPost = createPost(newPost) println(createdPost)}Key point: the ContentNegotiation plugin automatically serializes the object to JSON and deserializes the response back into the data class.
OkHttp — a proven standard for Android
OkHttp remains the de facto standard for network requests in Android development. It is fast, reliable, and supports p