Preparing the request

    or even simpler form(due to kotlin generic type inference):

    For example to perform a GET request fully reading a String:

    1. val htmlContent = client.get<String>("https://en.wikipedia.org/wiki/Main_Page")
    2. // same as
    3. val content: String = client.get("https://en.wikipedia.org/wiki/Main_Page")

    And in the case you are interested in the raw bits, you can read a ByteArray:

    1. val channel: ByteArray = client.get("https://en.wikipedia.org/wiki/Main_Page")

    Or get full HttpResponse:

    1. val response: HttpResponse = client.get("https://en.wikipedia.org/wiki/Main_Page")

    The is downloaded in memory by default. To learn how to download response partially or work with a stream data consult with the Streaming section.

    And even your data class using feature:

    1. @Serializable
    2. data class User(val id: Int)
    3. val response: User = client.get("https://myapi.com/user?id=1")

    Please note that some of response types are Closeable and can hold resources.

    We cannot live only on get requests, Ktor allows you to build complex requests with any of the HTTP verbs, with the flexibility to process responses in many ways.

    Similar to request, there are several extension methods to perform requestswith the most common HTTP verbs: GET, POST, PUT, DELETE, PATCH, HEAD and OPTIONS.

    1. val text = client.post<String>("http://127.0.0.1:8080/") {
    2. header("Hello", "World")
    3. }

    The HttpRequestBuilder looks like this:

    1. class HttpRequestBuilder : HttpMessageBuilder {
    2. var method: HttpMethod
    3. val url: URLBuilder
    4. fun url(block: URLBuilder.(URLBuilder) -> Unit)
    5. val headers: HeadersBuilder
    6. fun header(key: String, value: String)
    7. fun headers(block: HeadersBuilder.() -> Unit)
    8. var body: Any = EmptyContent
    9. val executionContext: CompletableDeferred<Unit>
    10. fun takeFrom(builder: HttpRequestBuilder): HttpRequestBuilder
    11. }

    The HttpClient class only offers some basic functionality, and all the methods for building requests are exposed as extensions.You can check the standard available .

    In addition to call, there is a request method for performing a typed request,receiving a specific type like String, HttpResponse, or an arbitrary class.You have to specify the URL and the method when building the request.

    1. val call = client.request<String> {
    2. url("http://127.0.0.1:8080/")
    3. method = HttpMethod.Get
    4. }

    There are a couple of convenience extension methods for submitting form information.The detailed refrence is listed .

    The method:

    1. client.submitForm(
    2. formParameters: Parameters = Parameters.Empty,
    3. encodeInQuery: Boolean = false,
    4. block: HttpRequestBuilder.() -> Unit = {}
    5. )

    It allows requesting with the Parameters encoded in the query string(GET by default) or requesting with the Parameters encoded as multipart(POST by default) depending on the encodeInQuery parameter.

    The submitFormWithBinaryData method:

    1. client.submitFormWithBinaryData(
    2. formData: List<PartData>,
    3. block: HttpRequestBuilder.() -> Unit = {}
    4. ): T

    It allows to generate a multipart POST request from a list of PartData.PartData can be PartData.FormItem, PartData.BinaryItem or PartData.FileItem.

    To build a list of PartData, you can use the formData builder:

    1. // this : HttpMessageBuilder
    2. // Convenience method to add a header
    3. header("My-Custom-Header", "HeaderValue")
    4. // Calls methods from the headers: HeadersBuilder to manipulate the headers
    5. headers.clear()
    6. headers.append("My-Custom-Header", "HeaderValue")
    7. headers.appendAll("My-Custom-Header", listOf("HeaderValue1", "HeaderValue2"))
    8. headers.remove("My-Custom-Header")
    9. // Applies the headers with the `headers` convenience method
    10. headers { // this: HeadersBuilder
    11. clear()
    12. append("My-Custom-Header", "HeaderValue")
    13. appendAll("My-Custom-Header", listOf("HeaderValue1", "HeaderValue2"))
    14. remove("My-Custom-Header")
    15. }

    Complete HeadersBuilder API is listed here.

    For POST and requests, you can set the body property:

    1. client.post<Unit> {
    2. body = // ...
    3. }

    The HttpRequestBuilder.body property can be a subtype of OutgoingContent as well as a String instance:

    • body = "HELLO WORLD!"
    • body = TextContent("HELLO WORLD!", ContentType.Text.Plain)
    • body = ByteArrayContent("HELLO WORLD!".toByteArray(Charsets.UTF_8))
    • body = LocalFileContent(File("build.gradle"))
    • body = JarFileContent(File("myjar.jar"), "test.txt", ContentType.fromFileExtension("txt").first())
    • body = URIFileContent(";)

    If you install the JsonFeature, and set the content type to application/jsonyou can use arbitrary instances as the body, and they will be serialized as JSON:

    1. data class HelloWorld(val hello: String)
    2. val client = HttpClient(Apache) {
    3. install(JsonFeature) {
    4. serializer = GsonSerializer {
    5. // Configurable .GsonBuilder
    6. serializeNulls()
    7. disableHtmlEscaping()
    8. }
    9. }
    10. }
    11. client.post<Unit> {
    12. url("http://127.0.0.1:8080/")
    13. body = HelloWorld(hello = "world")
    14. }

    Alternatively (using the integrated JsonSerializer):

    1. val json = io.ktor.client.features.json.defaultSerializer()
    2. client.post<Unit>() {
    3. url("http://127.0.0.1:8080/")
    4. body = json.write(HelloWorld(hello = "world")) // Generates an OutgoingContent
    5. }

    Or using Jackson (JVM only):

    1. val json = jacksonObjectMapper()
    2. client.post<Unit> {
    3. url("http://127.0.0.1:8080/")
    4. body = TextContent(json.writeValueAsString(userData), contentType = ContentType.Application.Json)
    5. }

    Remember that your classes must be top-level to be recognized by Gson. If you try to send a class that is inside a function, the feature will send a null.

    Ktor HTTP Client has support for making MultiPart requests.The idea is to use the MultiPartFormDataContent(parts: List<PartData>) as OutgoingContent for the body of the request.

    The easiest way is to use the method.