From 80fcd97fdb5928f4200a6fab57d600fa3713bb97 Mon Sep 17 00:00:00 2001 From: "leonid.stashevsky" Date: Mon, 7 Oct 2024 12:50:51 +0200 Subject: [PATCH] KTOR-6501 Update API Docs for HttpClient --- .../common/src/io/ktor/client/HttpClient.kt | 1170 ++++++++++++++++- .../ktor-client-tests/build.gradle.kts | 1 + 2 files changed, 1158 insertions(+), 13 deletions(-) diff --git a/ktor-client/ktor-client-core/common/src/io/ktor/client/HttpClient.kt b/ktor-client/ktor-client-core/common/src/io/ktor/client/HttpClient.kt index 043f80d781c..7e481c7d211 100644 --- a/ktor-client/ktor-client-core/common/src/io/ktor/client/HttpClient.kt +++ b/ktor-client/ktor-client-core/common/src/io/ktor/client/HttpClient.kt @@ -19,10 +19,294 @@ import kotlinx.coroutines.* import kotlin.coroutines.* /** - * Creates an asynchronous [HttpClient] with the specified [block] configuration. + * 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. * - * Note that the client requires an engine for processing network requests. - * The [HttpClientEngine] is selected from the [dependencies](https://ktor.io/docs/client-dependencies.html). + * # Creating client + * To create a new client, you can call: + * ```kotlin + * 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](https://ktor.io/docs/create-client.html). + * + * # Making API Requests + * For every HTTP method (GET, POST, PUT, etc.), there is a corresponding function: + * ```kotlin + * val response: HttpResponse = client.get("https://ktor.io/") + * val body = response.bodyAsText() + * ``` + * See [Making HTTP requests](https://ktor.io/docs/client-requests.html) for more details. + * + * # Query Parameters + * Add query parameters to your request using the `parameter` function: + * ```kotlin + * val response = client.get("https://google.com/search") { + * url { + * parameter("q", "REST API with Ktor") + * } + * } + * ``` + * For more information, refer to [Passing request parameters](https://ktor.io/docs/client-requests.html#parameters). + * + * # Adding Headers + * Include headers in your request using the `headers` builder or the `header` function: + * ```kotlin + * 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](https://ktor.io/docs/client-requests.html#headers). + * + * # 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`: + * ```kotlin + * 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](https://ktor.io/docs/client-serialization.html) for maven configuration and other details. + * + * # Submitting Forms + * Submit form data using `FormDataContent` or the `submitForm` function: + * ```kotlin + * // 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](https://ktor.io/docs/client-requests.html#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: + * ```kotlin + * 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](https://ktor.io/docs/client-auth.html) for more details. + * + * # Setting Timeouts and Retries + * Configure timeouts and implement retry logic for your requests: + * ```kotlin + * val client = HttpClient { + * install(HttpTimeout) { + * requestTimeoutMillis = 10000 + * connectTimeoutMillis = 5000 + * socketTimeoutMillis = 15000 + * } + * } + * ``` + * + * For the request timeout: + * ```kotlin + * client.get("") { + * timeout { + * requestTimeoutMillis = 1000 + * } + * } + * ``` + * See [Timeout](https://ktor.io/docs/client-timeout.html) for more information. + * + * # Handling Cookies + * + * Manage cookies automatically by installing the `HttpCookies` plugin: + * ```kotlin + * val client = HttpClient { + * install(HttpCookies) { + * storage = AcceptAllCookiesStorage() + * } + * } + * + * // Accessing cookies + * val cookies: List = client.cookies("https://example.com") + * ``` + * Learn more at [Cookies](https://ktor.io/docs/client-cookies.html). + * + * # Uploading Files + * Upload files using multipart/form-data requests: + * ```kotlin + * 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](https://ktor.io/docs/client-websockets.html). + * + * # 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](https://ktor.io/docs/client-response-validation.html) 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](https://ktor.io/docs/client-ssl.html). + * + * # Using Proxies + * Route requests through an HTTP or SOCKS proxy: + * ```kotlin + * 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](https://ktor.io/docs/client-proxy.html) for details. + * + * # Streaming Data + * + * Stream large data efficiently without loading it entirely into memory. + * + * Stream request: + * ```kotlin + * 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: + * ```kotlin + * 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](https://ktor.io/docs/client-responses.html#streaming). + * + * # 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: + * ```kotlin + * 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](https://ktor.io/docs/client-server-sent-events.html#install_plugin) to learn more. + * + * # Customizing a client with plugins + * To extend out-of-the-box functionality, you can install plugins for a Ktor client: + * ```kotlin + * 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](https://ktor.io/docs/client-custom-plugins.html) to learn more. */ @KtorDsl public expect fun HttpClient( @@ -30,9 +314,294 @@ public expect fun HttpClient( ): HttpClient /** - * Creates an asynchronous [HttpClient] with the specified [HttpClientEngineFactory] and optional [block] configuration. - * Note that a specific platform may require a specific engine for processing requests. - * You can learn more about available engines from [Engines](https://ktor.io/docs/http-client-engines.html). + * 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 client + * To create a new client, you can call: + * ```kotlin + * 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](https://ktor.io/docs/create-client.html). + * + * # Making API Requests + * For every HTTP method (GET, POST, PUT, etc.), there is a corresponding function: + * ```kotlin + * val response: HttpResponse = client.get("https://ktor.io/") + * val body = response.bodyAsText() + * ``` + * See [Making HTTP requests](https://ktor.io/docs/client-requests.html) for more details. + * + * # Query Parameters + * Add query parameters to your request using the `parameter` function: + * ```kotlin + * val response = client.get("https://google.com/search") { + * url { + * parameter("q", "REST API with Ktor") + * } + * } + * ``` + * For more information, refer to [Passing request parameters](https://ktor.io/docs/client-requests.html#parameters). + * + * # Adding Headers + * Include headers in your request using the `headers` builder or the `header` function: + * ```kotlin + * 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](https://ktor.io/docs/client-requests.html#headers). + * + * # 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`: + * ```kotlin + * 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](https://ktor.io/docs/client-serialization.html) for maven configuration and other details. + * + * # Submitting Forms + * Submit form data using `FormDataContent` or the `submitForm` function: + * ```kotlin + * // 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](https://ktor.io/docs/client-requests.html#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: + * ```kotlin + * 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](https://ktor.io/docs/client-auth.html) for more details. + * + * # Setting Timeouts and Retries + * Configure timeouts and implement retry logic for your requests: + * ```kotlin + * val client = HttpClient { + * install(HttpTimeout) { + * requestTimeoutMillis = 10000 + * connectTimeoutMillis = 5000 + * socketTimeoutMillis = 15000 + * } + * } + * ``` + * + * For the request timeout: + * ```kotlin + * client.get("") { + * timeout { + * requestTimeoutMillis = 1000 + * } + * } + * ``` + * See [Timeout](https://ktor.io/docs/client-timeout.html) for more information. + * + * # Handling Cookies + * + * Manage cookies automatically by installing the `HttpCookies` plugin: + * ```kotlin + * val client = HttpClient { + * install(HttpCookies) { + * storage = AcceptAllCookiesStorage() + * } + * } + * + * // Accessing cookies + * val cookies: List = client.cookies("https://example.com") + * ``` + * Learn more at [Cookies](https://ktor.io/docs/client-cookies.html). + * + * # Uploading Files + * Upload files using multipart/form-data requests: + * ```kotlin + * 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](https://ktor.io/docs/client-websockets.html). + * + * # 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](https://ktor.io/docs/client-response-validation.html) 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](https://ktor.io/docs/client-ssl.html). + * + * # Using Proxies + * Route requests through an HTTP or SOCKS proxy: + * ```kotlin + * 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](https://ktor.io/docs/client-proxy.html) for details. + * + * # Streaming Data + * + * Stream large data efficiently without loading it entirely into memory. + * + * Stream request: + * ```kotlin + * 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: + * ```kotlin + * 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](https://ktor.io/docs/client-responses.html#streaming). + * + * # 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: + * ```kotlin + * 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](https://ktor.io/docs/client-server-sent-events.html#install_plugin) to learn more. + * + * # Customizing a client with plugins + * To extend out-of-the-box functionality, you can install plugins for a Ktor client: + * ```kotlin + * 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](https://ktor.io/docs/client-custom-plugins.html) to learn more. */ @KtorDsl public fun HttpClient( @@ -53,9 +622,294 @@ public fun HttpClient( } /** - * Creates an asynchronous [HttpClient] with the specified [HttpClientEngine] and optional [block] configuration. - * Note that a specific platform may require a specific engine for processing requests. - * You can learn more about available engines from [Engines](https://ktor.io/docs/http-client-engines.html). + * 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 client + * To create a new client, you can call: + * ```kotlin + * 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](https://ktor.io/docs/create-client.html). + * + * # Making API Requests + * For every HTTP method (GET, POST, PUT, etc.), there is a corresponding function: + * ```kotlin + * val response: HttpResponse = client.get("https://ktor.io/") + * val body = response.bodyAsText() + * ``` + * See [Making HTTP requests](https://ktor.io/docs/client-requests.html) for more details. + * + * # Query Parameters + * Add query parameters to your request using the `parameter` function: + * ```kotlin + * val response = client.get("https://google.com/search") { + * url { + * parameter("q", "REST API with Ktor") + * } + * } + * ``` + * For more information, refer to [Passing request parameters](https://ktor.io/docs/client-requests.html#parameters). + * + * # Adding Headers + * Include headers in your request using the `headers` builder or the `header` function: + * ```kotlin + * 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](https://ktor.io/docs/client-requests.html#headers). + * + * # 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`: + * ```kotlin + * 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](https://ktor.io/docs/client-serialization.html) for maven configuration and other details. + * + * # Submitting Forms + * Submit form data using `FormDataContent` or the `submitForm` function: + * ```kotlin + * // 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](https://ktor.io/docs/client-requests.html#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: + * ```kotlin + * 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](https://ktor.io/docs/client-auth.html) for more details. + * + * # Setting Timeouts and Retries + * Configure timeouts and implement retry logic for your requests: + * ```kotlin + * val client = HttpClient { + * install(HttpTimeout) { + * requestTimeoutMillis = 10000 + * connectTimeoutMillis = 5000 + * socketTimeoutMillis = 15000 + * } + * } + * ``` + * + * For the request timeout: + * ```kotlin + * client.get("") { + * timeout { + * requestTimeoutMillis = 1000 + * } + * } + * ``` + * See [Timeout](https://ktor.io/docs/client-timeout.html) for more information. + * + * # Handling Cookies + * + * Manage cookies automatically by installing the `HttpCookies` plugin: + * ```kotlin + * val client = HttpClient { + * install(HttpCookies) { + * storage = AcceptAllCookiesStorage() + * } + * } + * + * // Accessing cookies + * val cookies: List = client.cookies("https://example.com") + * ``` + * Learn more at [Cookies](https://ktor.io/docs/client-cookies.html). + * + * # Uploading Files + * Upload files using multipart/form-data requests: + * ```kotlin + * 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](https://ktor.io/docs/client-websockets.html). + * + * # 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](https://ktor.io/docs/client-response-validation.html) 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](https://ktor.io/docs/client-ssl.html). + * + * # Using Proxies + * Route requests through an HTTP or SOCKS proxy: + * ```kotlin + * 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](https://ktor.io/docs/client-proxy.html) for details. + * + * # Streaming Data + * + * Stream large data efficiently without loading it entirely into memory. + * + * Stream request: + * ```kotlin + * 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: + * ```kotlin + * 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](https://ktor.io/docs/client-responses.html#streaming). + * + * # 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: + * ```kotlin + * 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](https://ktor.io/docs/client-server-sent-events.html#install_plugin) to learn more. + * + * # Customizing a client with plugins + * To extend out-of-the-box functionality, you can install plugins for a Ktor client: + * ```kotlin + * 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](https://ktor.io/docs/client-custom-plugins.html) to learn more. */ @KtorDsl public fun HttpClient( @@ -64,12 +918,294 @@ public fun HttpClient( ): HttpClient = HttpClient(engine, HttpClientConfig().apply(block), manageEngine = false) /** - * A multiplatform asynchronous HTTP client, which allows you to make requests and handle responses, - * extend its functionality with plugins, such as authentication, JSON serialization, and so on. + * 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 client + * To create a new client, you can call: + * ```kotlin + * 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() + * ``` * - * You can learn how to create a configure [HttpClient] from + * To learn more on how to create and configure an [HttpClient] see the tutorial page: * [Creating and configuring a client](https://ktor.io/docs/create-client.html). - * @property engine [HttpClientEngine] used to execute network requests. + * + * # Making API Requests + * For every HTTP method (GET, POST, PUT, etc.), there is a corresponding function: + * ```kotlin + * val response: HttpResponse = client.get("https://ktor.io/") + * val body = response.bodyAsText() + * ``` + * See [Making HTTP requests](https://ktor.io/docs/client-requests.html) for more details. + * + * # Query Parameters + * Add query parameters to your request using the `parameter` function: + * ```kotlin + * val response = client.get("https://google.com/search") { + * url { + * parameter("q", "REST API with Ktor") + * } + * } + * ``` + * For more information, refer to [Passing request parameters](https://ktor.io/docs/client-requests.html#parameters). + * + * # Adding Headers + * Include headers in your request using the `headers` builder or the `header` function: + * ```kotlin + * 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](https://ktor.io/docs/client-requests.html#headers). + * + * # 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`: + * ```kotlin + * 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](https://ktor.io/docs/client-serialization.html) for maven configuration and other details. + * + * # Submitting Forms + * Submit form data using `FormDataContent` or the `submitForm` function: + * ```kotlin + * // 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](https://ktor.io/docs/client-requests.html#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: + * ```kotlin + * 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](https://ktor.io/docs/client-auth.html) for more details. + * + * # Setting Timeouts and Retries + * Configure timeouts and implement retry logic for your requests: + * ```kotlin + * val client = HttpClient { + * install(HttpTimeout) { + * requestTimeoutMillis = 10000 + * connectTimeoutMillis = 5000 + * socketTimeoutMillis = 15000 + * } + * } + * ``` + * + * For the request timeout: + * ```kotlin + * client.get("") { + * timeout { + * requestTimeoutMillis = 1000 + * } + * } + * ``` + * See [Timeout](https://ktor.io/docs/client-timeout.html) for more information. + * + * # Handling Cookies + * + * Manage cookies automatically by installing the `HttpCookies` plugin: + * ```kotlin + * val client = HttpClient { + * install(HttpCookies) { + * storage = AcceptAllCookiesStorage() + * } + * } + * + * // Accessing cookies + * val cookies: List = client.cookies("https://example.com") + * ``` + * Learn more at [Cookies](https://ktor.io/docs/client-cookies.html). + * + * # Uploading Files + * Upload files using multipart/form-data requests: + * ```kotlin + * 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](https://ktor.io/docs/client-websockets.html). + * + * # 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](https://ktor.io/docs/client-response-validation.html) 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](https://ktor.io/docs/client-ssl.html). + * + * # Using Proxies + * Route requests through an HTTP or SOCKS proxy: + * ```kotlin + * 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](https://ktor.io/docs/client-proxy.html) for details. + * + * # Streaming Data + * + * Stream large data efficiently without loading it entirely into memory. + * + * Stream request: + * ```kotlin + * 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: + * ```kotlin + * 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](https://ktor.io/docs/client-responses.html#streaming). + * + * # 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: + * ```kotlin + * 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](https://ktor.io/docs/client-server-sent-events.html#install_plugin) to learn more. + * + * # Customizing a client with plugins + * To extend out-of-the-box functionality, you can install plugins for a Ktor client: + * ```kotlin + * 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](https://ktor.io/docs/client-custom-plugins.html) to learn more. */ @OptIn(InternalAPI::class) public class HttpClient( @@ -86,6 +1222,14 @@ public class HttpClient( this.manageEngine = manageEngine } + private suspend fun x() { + get("") { + url { + parameter("key", "value") + } + } + } + private val closed = atomic(false) private val clientJob: CompletableJob = Job(engine.coroutineContext[Job]) diff --git a/ktor-client/ktor-client-tests/build.gradle.kts b/ktor-client/ktor-client-tests/build.gradle.kts index fe4f24e6f22..f68685f0878 100644 --- a/ktor-client/ktor-client-tests/build.gradle.kts +++ b/ktor-client/ktor-client-tests/build.gradle.kts @@ -59,6 +59,7 @@ kotlin.sourceSets { dependencies { api(project(":ktor-client:ktor-client-apache")) api(project(":ktor-client:ktor-client-apache5")) + api(project(":ktor-client:ktor-client-cio")) runtimeOnly(project(":ktor-client:ktor-client-android")) runtimeOnly(project(":ktor-client:ktor-client-okhttp")) if (currentJdk >= 11) {