Skip to content
AgileLogics
5 min read

Making HTTP Requests

Prerequisites: Working with JSON

An API (Application Programming Interface) lets programs talk to each other; most web APIs work over HTTP. On the JVM, Kotlin can use Java's built-in HttpClient, and many projects use Ktor Client, which is coroutine-based and works in Kotlin Multiplatform.

With Java's HttpClient (no extra libraries)

import java.net.URI
import java.net.http.HttpClient
import java.net.http.HttpRequest
import java.net.http.HttpResponse
import java.time.Duration

fun main() {
    val client = HttpClient.newBuilder()
        .connectTimeout(Duration.ofSeconds(5))
        .build()

    val request = HttpRequest.newBuilder(URI("https://api.github.com/repos/JetBrains/kotlin"))
        .header("Accept", "application/json")
        .timeout(Duration.ofSeconds(10))
        .GET()
        .build()

    val response = client.send(request, HttpResponse.BodyHandlers.ofString())

    if (response.statusCode() == 200) {
        println(response.body().take(60))
    } else {
        println("Request failed: ${response.statusCode()}")
    }
}
{"id":3432266,"node_id":"MDEwOlJlcG9zaXRvcnkzNDMyMjY2","name
  • Always set timeouts, so a slow server can't hang your program.
  • Check the status code before using the body — a 404 or 500 is a normal response, not an exception.
  • Network failures (no connection, timeout) throw IOException subclasses; catch them where you can respond sensibly.

With Ktor Client

import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.engine.cio.CIO
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.client.request.get
import io.ktor.serialization.kotlinx.json.json
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json

@Serializable
data class Repo(
    @SerialName("full_name") val fullName: String,
    @SerialName("stargazers_count") val stars: Int,
)

suspend fun main() {
    val client = HttpClient(CIO) {
        install(ContentNegotiation) { json(Json { ignoreUnknownKeys = true }) }
    }
    val repo: Repo = client.get("https://api.github.com/repos/JetBrains/kotlin").body()
    println("${repo.fullName} has ${repo.stars} stars")
    client.close()
}
JetBrains/kotlin has 51234 stars

(The number will be different when you run it.) Ktor decodes the JSON straight into your class. suspend fun main and coroutines are explained in Level 3.

Common mistakes

  • Hard-coding API keys in source code. Read them from environment variables (System.getenv("API_KEY")) or a secrets store.
  • Making network calls on Android's main thread — the app freezes, and Android throws NetworkOnMainThreadException. Coroutines solve this.