HttpClient

expect fun HttpClient(block: HttpClientConfig<*>.() -> Unit = {}): HttpClient

A multiplatform asynchronous HTTP client that allows you to make requests, handle responses, and extend its functionality with plugins such as authentication, JSON serialization, and more.

Creating a client

To create a new client, you can call:

val client = HttpClient()

You can create as many clients as you need.

If you no longer need the client, please consider closing it to release resources:

client.close()

To learn more on how to create and configure an HttpClient, see Creating and configuring a client.

Making API Requests

For every HTTP method (GET, POST, PUT, etc.), there is a corresponding function:

val response: HttpResponse = client.get("https://ktor.io/")
val body = response.bodyAsText()

For more details, see Making HTTP requests.

Query Parameters

Add query parameters to your request using the parameter function:

val response = client.get("https://google.com/search") {
url {
parameter("q", "REST API with Ktor")
}
}

For more information, refer to Passing request parameters.

Adding Headers

Include headers in your request using the headers builder or the header function:

val response = client.get("https://httpbin.org/bearer") {
headers {
append("Authorization", "Bearer your_token_here")
append("Accept", "application/json")
}
}

To learn more, see Adding headers to a request.

JSON Serialization

Add dependencies:

  • io.ktor:ktor-client-content-negotiation:3.+

  • io.ktor:ktor-serialization-kotlinx-json:3.+ Add Gradle plugin:

plugins {
kotlin("plugin.serialization")
}

Send and receive JSON data by installing the ContentNegotiation plugin with kotlinx.serialization:

val client = HttpClient {
install(ContentNegotiation) {
json()
}
}

@Serializable
data class MyRequestType(val someData: String)

@Serializable
data class MyResponseType(val someResponseData: String)

val response: MyResponseType = client.post("https://api.example.com/data") {
contentType(ContentType.Application.Json)
setBody(MyRequestType(someData = "value"))
}.body()

For Maven configuration and other details, see Serializing JSON data.

Submitting Forms

Submit form data using FormDataContent or the submitForm function:

// Using FormDataContent
val response = client.post("https://example.com/submit") {
setBody(FormDataContent(Parameters.build {
append("username", "user")
append("password", "pass")
}))
}

// Using submitForm
val response = client.submitForm(
url = "https://example.com/submit",
formParameters = Parameters.build {
append("username", "user")
append("password", "pass")
}
)

For more information, see Submitting form parameters.

Handling Authentication

Add dependency: io.ktor:ktor-client-auth:3.+

Use the Auth plugin to handle various authentication schemes like Basic or Bearer token authentication:

val client = HttpClient {
install(Auth) {
bearer {
loadTokens {
BearerTokens(accessToken = "your_access_token", refreshToken = "your_refresh_token")
}
}
}
}

val response = client.get("https://api.example.com/protected")

For more details, refer to Client authentication.

Setting Timeouts and Retries

Configure timeouts and implement retry logic for your requests:

val client = HttpClient {
install(HttpTimeout) {
requestTimeoutMillis = 10000
connectTimeoutMillis = 5000
socketTimeoutMillis = 15000
}
}

For the request timeout:

client.get("") {
timeout {
requestTimeoutMillis = 1000
}
}

For more information, see the Timeout documentation.

Handling Cookies

Manage cookies automatically by installing the HttpCookies plugin:

val client = HttpClient {
install(HttpCookies) {
storage = AcceptAllCookiesStorage()
}
}

// Accessing cookies
val cookies: List<Cookie> = client.cookies("https://example.com")

For more information, see the Cookies documentation.

Uploading Files

Upload files using multipart/form-data requests:

client.submitFormWithBinaryData(
url = "https://example.com/upload",
formData = formData {
append("description", "File upload example")
append("file", {
File("path/to/file.txt").readChannel()
})
}
)

For more details, see [Uploading data](https://ktor.io/docs/client-requests.html#upload_file).

# Using WebSockets

Communicate over WebSockets using the `webSocket` function:
```kotlin
client.webSocket("wss://echo.websocket.org") {
send(Frame.Text("Hello, WebSocket!"))
val frame = incoming.receive()
if (frame is Frame.Text) {
println("Received: ${frame.readText()}")
}
}

To learn more, see Client WebSockets.

Error Handling

Handle exceptions and HTTP error responses gracefully: val client = HttpClient { HttpResponseValidator { validateResponse { response -> val statusCode = response.status.value when (statusCode) { in 300..399 -> error("Redirects are not allowed") } } } }

For more information, see Error handling.

Configuring SSL/TLS

Customize SSL/TLS settings for secure connections is engine-specific. Please refer to the following page for the details: Client SSL/TLS.

Using Proxies

Route requests through an HTTP or SOCKS proxy:

val client = HttpClient() {
engine {
proxy = ProxyBuilder.http("http://proxy.example.com:8080")
// For a SOCKS proxy:
// proxy = ProxyBuilder.socks(host = "proxy.example.com", port = 1080)
}
}

For more details, see Using a proxy.

Streaming Data

Stream large data efficiently without loading it entirely into memory.

Stream request:

val response = client.post("https://example.com/upload") {
setBody(object: OutgoingContent.WriteChannelContent() {
override suspend fun writeTo(channel: ByteWriteChannel) {
repeat(1000) {
channel.writeString("Hello!")
}
}
})
}

Stream response:

client.prepareGet("https://example.com/largefile.zip").execute { response ->
val channel: ByteReadChannel = response.bodyAsChannel()

while (!channel.exhausted()) {
val chunk = channel.readBuffer()
// ...
}
}

Learn more at Streaming data.

Using SSE

Server-Sent Events (SSE) is a technology that allows a server to continuously push events to a client over an HTTP connection. It's particularly useful in cases where the server needs to send event-based updates without requiring the client to repeatedly poll the server.

Install the plugin:

val client = HttpClient(CIO) {
install(SSE)
}
client.sse(host = "0.0.0.0", port = 8080, path = "/events") {
while (true) {
for (event in incoming) {
println("Event from server:")
println(event)
}
}
}

For more information, see Using SSE.

Customizing a client with plugins

To extend out-of-the-box functionality, you can install plugins for a Ktor client:

val client = HttpClient {
install(ContentNegotiation) {
json()
}
}

There are many plugins available out of the box, and you can write your own. See Create custom client plugins to learn more.

Service Loader and Default Engine

On JVM, calling HttpClient() without specifying an engine uses a service loader mechanism to determine the appropriate default engine. This can introduce a performance overhead, especially on slower devices, such as Android.

Performance Note: If you are targeting platforms where initialization speed is critical, consider explicitly specifying an engine to avoid the service loader lookup.

Example with manual engine specification:

val client = HttpClient(Apache) // Explicitly uses Apache engine, bypassing service loader

By directly setting the engine (e.g., Apache, OkHttp), you can optimize startup performance by preventing the default service loader mechanism.


A multiplatform asynchronous HTTP client that allows you to make requests, handle responses, and extend its functionality with plugins such as authentication, JSON serialization, and more.

Creating a client

To create a new client, you can call:

val client = HttpClient()

You can create as many clients as you need.

If you no longer need the client, please consider closing it to release resources:

client.close()

To learn more on how to create and configure an HttpClient see the tutorial page: Creating and configuring a client.

Making API Requests

For every HTTP method (GET, POST, PUT, etc.), there is a corresponding function:

val response: HttpResponse = client.get("https://ktor.io/")
val body = response.bodyAsText()

See Making HTTP requests for more details.

Query Parameters

Add query parameters to your request using the parameter function:

val response = client.get("https://google.com/search") {
url {
parameter("q", "REST API with Ktor")
}
}

For more information, refer to Passing request parameters.

Adding Headers

Include headers in your request using the headers builder or the header function:

val response = client.get("https://httpbin.org/bearer") {
headers {
append("Authorization", "Bearer your_token_here")
append("Accept", "application/json")
}
}

Learn more at Adding headers to a request.

JSON Serialization

Add dependencies:

  • io.ktor:ktor-client-content-negotiation:3.+

  • io.ktor:ktor-serialization-kotlinx-json:3.+ Add Gradle plugin:

plugins {
kotlin("plugin.serialization")
}

Send and receive JSON data by installing the ContentNegotiation plugin with kotlinx.serialization:

val client = HttpClient {
install(ContentNegotiation) {
json()
}
}

@Serializable
data class MyRequestType(val someData: String)

@Serializable
data class MyResponseType(val someResponseData: String)

val response: MyResponseType = client.post("https://api.example.com/data") {
contentType(ContentType.Application.Json)
setBody(MyRequestType(someData = "value"))
}.body()

See Serializing JSON data for maven configuration and other details.

Submitting Forms

Submit form data using FormDataContent or the submitForm function:

// Using FormDataContent
val response = client.post("https://example.com/submit") {
setBody(FormDataContent(Parameters.build {
append("username", "user")
append("password", "pass")
}))
}

// Or using submitForm
val response = client.submitForm(
url = "https://example.com/submit",
formParameters = Parameters.build {
append("username", "user")
append("password", "pass")
}
)

More information is available at Submitting form parameters.

Handling Authentication

Add dependency: io.ktor:ktor-client-auth:3.+

Use the Auth plugin to handle various authentication schemes like Basic or Bearer token authentication:

val client = HttpClient {
install(Auth) {
bearer {
loadTokens {
BearerTokens(accessToken = "your_access_token", refreshToken = "your_refresh_token")
}
}
}
}

val response = client.get("https://api.example.com/protected")

Refer to Client authentication for more details.

Setting Timeouts and Retries

Configure timeouts and implement retry logic for your requests:

val client = HttpClient {
install(HttpTimeout) {
requestTimeoutMillis = 10000
connectTimeoutMillis = 5000
socketTimeoutMillis = 15000
}
}

For the request timeout:

client.get("") {
timeout {
requestTimeoutMillis = 1000
}
}

See Timeout for more information.

Handling Cookies

Manage cookies automatically by installing the HttpCookies plugin:

val client = HttpClient {
install(HttpCookies) {
storage = AcceptAllCookiesStorage()
}
}

// Accessing cookies
val cookies: List<Cookie> = client.cookies("https://example.com")

Learn more at Cookies.

Uploading Files

Upload files using multipart/form-data requests:

client.submitFormWithBinaryData(
url = "https://example.com/upload",
formData = formData {
append("description", "File upload example")
append("file", {
File("path/to/file.txt").readChannel()
})
}
)

See [Uploading data](https://ktor.io/docs/client-requests.html#upload_file) for details.

# Using WebSockets

Communicate over WebSockets using the `webSocket` function:
```kotlin
client.webSocket("wss://echo.websocket.org") {
send(Frame.Text("Hello, WebSocket!"))
val frame = incoming.receive()
if (frame is Frame.Text) {
println("Received: ${frame.readText()}")
}
}

Learn more at Client WebSockets.

Error Handling

Handle exceptions and HTTP error responses gracefully: val client = HttpClient { HttpResponseValidator { validateResponse { response -> val statusCode = response.status.value when (statusCode) { in 300..399 -> error("Redirects are not allowed") } } } }

See Error handling for more information.

Configuring SSL/TLS

Customize SSL/TLS settings for secure connections is engine-specific. Please refer to the following page for the details: Client SSL/TLS.

Using Proxies

Route requests through an HTTP or SOCKS proxy:

val client = HttpClient() {
engine {
proxy = ProxyBuilder.http("http://proxy.example.com:8080")
// For a SOCKS proxy:
// proxy = ProxyBuilder.socks(host = "proxy.example.com", port = 1080)
}
}

See Using a proxy for details.

Streaming Data

Stream large data efficiently without loading it entirely into memory.

Stream request:

val response = client.post("https://example.com/upload") {
setBody(object: OutgoingContent.WriteChannelContent() {
override suspend fun writeTo(channel: ByteWriteChannel) {
repeat(1000) {
channel.writeString("Hello!")
}
}
})
}

Stream response:

client.prepareGet("https://example.com/largefile.zip").execute { response ->
val channel: ByteReadChannel = response.bodyAsChannel()

while (!channel.exhausted()) {
val chunk = channel.readBuffer()
// ...
}
}

Learn more at Streaming data.

Using SSE

Server-Sent Events (SSE) is a technology that allows a server to continuously push events to a client over an HTTP connection. It's particularly useful in cases where the server needs to send event-based updates without requiring the client to repeatedly poll the server.

Install the plugin:

val client = HttpClient(CIO) {
install(SSE)
}
client.sse(host = "0.0.0.0", port = 8080, path = "/events") {
while (true) {
for (event in incoming) {
println("Event from server:")
println(event)
}
}
}

Visit Using SSE to learn more.

Customizing a client with plugins

To extend out-of-the-box functionality, you can install plugins for a Ktor client:

val client = HttpClient {
install(ContentNegotiation) {
json()
}
}

There are many plugins available out of the box, and you can write your own. See Create custom client plugins to learn more.

Service Loader and Default Engine

On JVM, calling HttpClient() without specifying an engine uses a service loader mechanism to determine the appropriate default engine. This can introduce a performance overhead, especially on slower devices, such as Android.

Performance Note: If you are targeting platforms where initialization speed is critical, consider explicitly specifying an engine to avoid the service loader lookup.

Example with manual engine specification:

val client = HttpClient(Apache) // Explicitly uses Apache engine, bypassing service loader

By directly setting the engine (e.g., Apache, OkHttp), you can optimize startup performance by preventing the default service loader mechanism.

actual fun HttpClient(block: HttpClientConfig<*>.() -> Unit): HttpClient

Constructs an asynchronous HttpClient using optional block for configuring this client.

The HttpClientEngine is selected from the dependencies. https://ktor.io/docs/http-client-engines.html

actual fun HttpClient(block: HttpClientConfig<*>.() -> Unit): HttpClient

Constructs an asynchronous HttpClient using optional block for configuring this client.

The HttpClientEngine is selected from the dependencies. https://ktor.io/docs/http-client-engines.html