Ktor 2.0.1 Help

Making requests

After setting up the client, you can make HTTP requests. The main way for making HTTP requests is the request function that can take a URL as a parameter. Inside this function, you can configure various request parameters:

  • Specify a request URL.

  • Specify an HTTP method, such as GET, POST, PUT, DELETE, HEAD, OPTION, or PATCH.

  • Add headers and cookies.

  • Set the body of a request, for example, a plain text, a data object, or form parameters.

These parameters are exposed by the HttpRequestBuilder class.

import io.ktor.client.request.* import io.ktor.client.statement.* val response: HttpResponse = client.request("https://ktor.io/") { // Configure request parameters exposed by [[[HttpRequestBuilder|https://api.ktor.io/ktor-client/ktor-client-core/io.ktor.client.request/-http-request-builder/index.html]]] }

Note that this function allows you to receive a response as an HttpResponse object. HttpResponse exposes API required to get a response body in various ways (a string, a JSON object, etc.) and obtain response parameters, such as a status code, content type, headers, and so on. You can learn more from the Receiving responses topic.

Specify a request URL

Specify URL string

The request function can take a URL as a parameter:

val response: HttpResponse = client.request("https://ktor.io/") { // Configure request parameters exposed by [[[HttpRequestBuilder|https://api.ktor.io/ktor-client/ktor-client-core/io.ktor.client.request/-http-request-builder/index.html]]] }

Configure URL components separately

Another way to specify the URL is the url parameter exposed by HttpRequestBuilder. This parameter accepts URLBuilder and allows you to specify various URL components separately:

val response: HttpResponse = client.request { url { protocol = URLProtocol.HTTPS host = "ktor.io" } }

Set request parameters

In this section, we'll see on how to specify various request parameters, including an HTTP method, headers, and cookies. If you need to configure some default parameters for all requests of a specific client, use the DefaultRequest plugin.

HTTP method

When calling the request function, you can specify the desired HTTP method using the method property:

import io.ktor.client.request.* import io.ktor.client.statement.* import io.ktor.http.* val response: HttpResponse = client.request("https://ktor.io/") { method = HttpMethod.Get }

In addition to the request function, HttpClient provides specific functions for basic HTTP methods: get, post, put, and so on. For example, you can replace the example above with the following code:

import io.ktor.client.request.* import io.ktor.client.statement.* val response: HttpResponse = client.get("https://ktor.io/")

Headers

To add headers to the request, you can use the following ways:

  • The headers function allows you to add several headers at once:

    import io.ktor.client.request.* import io.ktor.client.statement.* import io.ktor.http.* val response: HttpResponse = client.get("https://ktor.io/") { headers { append(HttpHeaders.Accept, "text/html") append(HttpHeaders.Authorization, "token") append(HttpHeaders.UserAgent, "ktor client") } }
  • The header function allows you to append a single header.

  • The basicAuth and bearerAuth functions add the Authorization header with a corresponding HTTP scheme.

Cookies

To send cookies, use the cookie function:

import io.ktor.client.request.* import io.ktor.client.statement.* import io.ktor.util.date.* val response: HttpResponse = client.get("https://ktor.io/") { cookie(name = "user_name", value = "jetbrains", expires = GMTDate( seconds = 0, minutes = 0, hours = 10, dayOfMonth = 1, month = Month.APRIL, year = 2022 )) }

Ktor also provides the HttpCookies plugin that allows you to keep cookies between calls. If this plugin is installed, cookies added using the cookie function are ignored.

Query parameters

To add query string parameters, call the parameter function:

import io.ktor.client.* import io.ktor.client.request.* import io.ktor.client.statement.* val response: HttpResponse = client.get("http://localhost:8080/products") { parameter("price", "asc") }

Note that the value parameter accepts an Any instance. So, if you need to specify several values for a single key, you can pass these values as a List object.

Set request body

To set the body of a request, you need to call the setBody function exposed by HttpRequestBuilder. This function accepts different types of payloads, including plain text, arbitrary class instances, form data, byte arrays, and so on. Below we'll take a look at several examples.

Text

Sending plain text as body can be implemented in the following way:

import io.ktor.client.request.* import io.ktor.client.statement.* import io.ktor.http.* val response: HttpResponse = client.post("http://localhost:8080/post") { setBody("Body content") }

Objects

With the enabled ContentNegotiation plugin, you can send a class instance within a request body as JSON. To do this, pass a class instance to the setBody function and set the content type to application/json using the contentType function:

val response: HttpResponse = client.post("http://localhost:8080/customer") { contentType(ContentType.Application.Json) setBody(Customer(3, "Jet", "Brains")) }

You can learn more from the Content negotiation and serialization help section.

Form parameters

The Ktor client provides the submitForm function for sending form parameters using both x-www-form-urlencoded and multipart/form-data types. The example below shows how to send form parameters encoded as multipart/form-data:

  • url specifies a URL for making a request.

  • formParameters a set of form parameters built using Parameters.build.

val client = HttpClient(CIO) val response: HttpResponse = client.submitForm( url = "http://localhost:8080/signup", formParameters = Parameters.build { append("username", "JetBrains") append("email", "example@jetbrains.com") append("password", "foobar") append("confirmation", "foobar") } )

You can find the full example here: client-submit-form.

Upload a file

If you need to send a file with a form, you can use the following approaches:

  • Use the submitFormWithBinaryData function. In this case, a boundary will be generated automatically.

  • Call the post function and pass the MultiPartFormDataContent instance to the setBody function. Note that the MultiPartFormDataContent constructor also allows you to pass a boundary value.

For both approaches, you need to build form data using the formData function.

val client = HttpClient(CIO) val response: HttpResponse = client.submitFormWithBinaryData( url = "http://localhost:8080/upload", formData = formData { append("description", "Ktor logo") append("image", File("ktor_logo.png").readBytes(), Headers.build { append(HttpHeaders.ContentType, "image/png") append(HttpHeaders.ContentDisposition, "filename=ktor_logo.png") }) } )
val client = HttpClient(CIO) val response: HttpResponse = client.post("http://localhost:8080/upload") { setBody(MultiPartFormDataContent( formData { append("description", "Ktor logo") append("image", File("ktor_logo.png").readBytes(), Headers.build { append(HttpHeaders.ContentType, "image/png") append(HttpHeaders.ContentDisposition, "filename=ktor_logo.png") }) }, boundary = "WebAppBoundary" ) ) onUpload { bytesSentTotal, contentLength -> println("Sent $bytesSentTotal bytes from $contentLength") } }

MultiPartFormDataContent also allows you to override a boundary and content type as follows:

fun customMultiPartMixedDataContent(parts: List<PartData>): MultiPartFormDataContent { val boundary = "WebAppBoundary" val contentType = ContentType.MultiPart.Mixed.withParameter("boundary", boundary) return MultiPartFormDataContent(parts, boundary, contentType) }

You can find the full examples here:

Parallel requests

When sending two requests at once, the client suspends the second request execution until the first one is finished. If you need to perform several requests at once, you can use launch or async functions. The code snippet below shows how to perform two requests asynchronously:

runBlocking { // Parallel requests val firstRequest: Deferred<String> = async { client.get("http://localhost:8080/path1").bodyAsText() } val secondRequest: Deferred<String> = async { client.get("http://localhost:8080/path2").bodyAsText() } val firstRequestContent = firstRequest.await() val secondRequestContent = secondRequest.await() }

To see a full example, go to client-parallel-requests.

Cancel a request

If you need to cancel a request, you can cancel a coroutine that runs this request. The launch function returns a Job that can be used to cancel the running coroutine:

import kotlinx.coroutines.* val client = HttpClient(CIO) val job = launch { val requestContent: String = client.get("http://localhost:8080") } job.cancel()

Learn more about Cancellation and timeouts.

Last modified: 13 May 2022