kotlinintermediate
Ktor HTTP Client — GET, POST, and Auth
Make HTTP requests with Ktor client: GET, POST, headers, auth, retries, and JSON serialization.
kotlinPress ⌘/Ctrl + Shift + C to copy
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.engine.cio.*
import io.ktor.client.plugins.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.plugins.logging.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*
import io.ktor.serialization.kotlinx.json.*
import kotlinx.serialization.*
@Serializable
data class Post(val id: Int, val title: String, val body: String, val userId: Int)
@Serializable
data class CreatePost(val title: String, val body: String, val userId: Int)
class ApiClient : AutoCloseable {
private val client = HttpClient(CIO) {
// JSON serialization
install(ContentNegotiation) {
json(kotlinx.serialization.json.Json {
ignoreUnknownKeys = true
prettyPrint = true
})
}
// Logging
install(Logging) {
level = LogLevel.INFO
}
// Defaults
defaultRequest {
url("https://jsonplaceholder.typicode.com")
contentType(ContentType.Application.Json)
}
// Timeout
install(HttpTimeout) {
requestTimeoutMillis = 10_000
connectTimeoutMillis = 5_000
}
// Retry on failure
install(HttpRequestRetry) {
retryOnServerErrors(maxRetries = 3)
exponentialDelay()
}
}
// GET single
suspend fun getPost(id: Int): Post =
client.get("/posts/$id").body()
// GET list
suspend fun getPosts(limit: Int = 10): List<Post> =
client.get("/posts") {
parameter("_limit", limit)
}.body()
// POST
suspend fun createPost(post: CreatePost): Post =
client.post("/posts") {
setBody(post)
}.body()
// PUT
suspend fun updatePost(id: Int, post: CreatePost): Post =
client.put("/posts/$id") {
setBody(post)
}.body()
// DELETE
suspend fun deletePost(id: Int): HttpStatusCode =
client.delete("/posts/$id").status
// Auth header
suspend fun getProtected(token: String): String =
client.get("/posts/1") {
bearerAuth(token)
}.bodyAsText()
// Raw response
suspend fun getRaw(url: String): Pair<HttpStatusCode, String> {
val response: HttpResponse = client.get(url)
return response.status to response.bodyAsText()
}
override fun close() = client.close()
}
suspend fun main() {
ApiClient().use { api ->
// GET
val post = api.getPost(1)
println("Post: ${post.title}")
// GET list
val posts = api.getPosts(3)
posts.forEach { println(" ${it.id}: ${it.title}") }
// POST
val created = api.createPost(
CreatePost("New Post", "Content here", 1)
)
println("Created: ${created.id} - ${created.title}")
// DELETE
val status = api.deletePost(1)
println("Delete status: $status")
}
}Use Cases
- REST API consumption in Kotlin applications
- Microservice-to-microservice communication
- HTTP client with retry and timeout handling
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
kotlinintermediate
Ktor Server — Routing and Middleware
Build HTTP servers with Ktor: routing DSL, middleware plugins, content negotiation, and error handling.
Best for: REST API server with Ktor
#kotlin#ktor
kotlinintermediate
Ktor Server Routing and Middleware
Build HTTP APIs with Ktor: routing, content negotiation, authentication, and middleware plugins.
Best for: Building REST APIs with Kotlin-native framework
#kotlin#ktor
kotlinbeginner
Null Safety — Elvis, Safe Call, and let
Master Kotlin null safety: safe calls, Elvis operator, let/also scoping, and smart casts.
Best for: Safe navigation through nullable chains
#kotlin#null-safety
kotlinbeginner
Data Classes — Copy, Destructure, and Equals
Use data classes for immutable models: auto-generated equals, hashCode, copy, and destructuring.
Best for: Immutable domain models and DTOs
#kotlin#data-class