Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
862c75e
docs: KTOR-8533 Add docs for SaveBodyPlugin deprecation (#632)
vnikolova Jun 6, 2025
096886c
What's new in Ktor 3.2.0: network and gradle
ElviraMustafina Jun 13, 2025
1c4f9ae
KTOR-8469 Add documentation about wrapWithContent and wrap deprecatio…
daniCsorbaJB Jun 16, 2025
53c070a
Merge branch '3.2.0' into KTOR-8542-access-resolved-ip-address
ElviraMustafina Jun 16, 2025
6b6b392
docs: KTOR-8533 Add docs for SaveBodyPlugin deprecation (#632)
vnikolova Jun 6, 2025
2451f74
KTOR-8469 Add documentation about wrapWithContent and wrap deprecatio…
daniCsorbaJB Jun 16, 2025
88780f0
chore: bump Ktor version to 3.2.0 and add release details (#638)
vnikolova Jun 17, 2025
59b9652
review
ElviraMustafina Jun 17, 2025
57eecb1
Merge branch '3.2.0' into KTOR-8542-access-resolved-ip-address
ElviraMustafina Jun 17, 2025
0665f65
KTOR-8530 Add documentation for version catalog support (#633)
vnikolova Jun 17, 2025
b45ac7e
twr review
ElviraMustafina Jun 18, 2025
26d20e3
Merge branch '3.2.0' into KTOR-8542-access-resolved-ip-address
ElviraMustafina Jun 18, 2025
3e43566
two options for running with Gradle
ElviraMustafina Jun 18, 2025
fedc041
What's new in Ktor 3.2.0: network and Gradle
ElviraMustafina Jun 19, 2025
ae8cedb
chore: rename what's new file and add a release date
vnikolova Jun 19, 2025
4ad71b7
feat: coroutine support for modules
danil-pavlov Jun 19, 2025
55d5268
fix: review suggestions
danil-pavlov Jun 20, 2025
8bece35
KTOR-8405 Add typed configuration in the "What's new" doc (#640)
vnikolova Jun 20, 2025
8990f5f
docs: KTOR-8545 make testApplication client mutable
sarahhaggarty Jun 19, 2025
8378c3d
KTOR-8197 Add documentation for HTMX support (#639)
vnikolova Jun 24, 2025
8483484
fix: review suggestions
danil-pavlov Jun 25, 2025
010b6ac
Merge pull request #642 from ktorio/application-modules
danil-pavlov Jun 25, 2025
c60cc87
Merge remote-tracking branch 'origin/main' into 3.2.0
vnikolova Jun 25, 2025
dec3083
update: KTOR-8509 Document the Unix domain socket functionality in ma…
zamulla Jun 27, 2025
aded430
Add documentation for DI (#643)
vnikolova Jul 3, 2025
68f0365
Fix headings and DI code examples
vnikolova Jul 4, 2025
32827a6
KTOR-8582 Add Gradle properties overview for concurrent module loading
vnikolova Jul 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions codeSnippets/settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ module("snippets", "tutorial-server-routing-and-requests")
module("snippets", "tutorial-server-restful-api")
module("snippets", "tutorial-server-websockets")
module("snippets", "tutorial-server-docker-compose")
module("snippets", "htmx-integration")

if(!System.getProperty("os.name").startsWith("Windows")) {
module("snippets", "embedded-server-native")
Expand Down
13 changes: 13 additions & 0 deletions codeSnippets/snippets/htmx-integration/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# HTMX integration

A sample Ktor project demonstrating how to integrate HTMX using the HTML DSL and HTMX-aware server-side routing.

> This sample is a part of the [codeSnippets](../../README.md) Gradle project.

## Running

To run this sample, execute the following command in a repository's root directory:

```bash
./gradlew :htmx-integration:run
```
33 changes: 33 additions & 0 deletions codeSnippets/snippets/htmx-integration/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@

val kotlin_version: String by project
val logback_version: String by project

plugins {
kotlin("jvm")
id("io.ktor.plugin") version "3.2.0"
}

group = "com.example"
version = "0.0.1"

application {
mainClass = "io.ktor.server.netty.EngineMain"
}

repositories {
mavenCentral()
}

dependencies {
implementation("io.ktor:ktor-server-core-jvm")
implementation("io.ktor:ktor-server-netty")
implementation("ch.qos.logback:logback-classic:$logback_version")
implementation("io.ktor:ktor-server-core")
implementation("io.ktor:ktor-server-htmx")
implementation("io.ktor:ktor-htmx")
implementation("io.ktor:ktor-htmx-html")
implementation("io.ktor:ktor-server-html-builder")
implementation("io.ktor:ktor-server-config-yaml")
testImplementation("io.ktor:ktor-server-test-host")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.example

import io.ktor.server.application.*

fun main(args: Array<String>) {
io.ktor.server.netty.EngineMain.main(args)
}

fun Application.module() {
configureHtmx()
}
83 changes: 83 additions & 0 deletions codeSnippets/snippets/htmx-integration/src/main/kotlin/Routing.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package com.example

import io.ktor.htmx.HxSwap
import io.ktor.htmx.html.hx
import io.ktor.server.application.*
import io.ktor.server.html.respondHtml
import io.ktor.server.htmx.hx
import io.ktor.server.response.*
import io.ktor.server.routing.*
import io.ktor.utils.io.ExperimentalKtorApi
import kotlinx.html.*

fun Application.configureRouting() {
routing {
get("/") {
call.respondText("Hello World!")
}
}
}

@OptIn(ExperimentalKtorApi::class)
fun Application.configureHtmx() {
routing {
get("/") {
call.respondHtml {
head {
// Include HTMX library
script(src = "https://unpkg.com/[email protected]") {}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Consider pinning HTMX version for consistency.

The HTMX library is loaded from a CDN with a specific version (1.9.10). Consider verifying this is the intended version for the sample.


🌐 Web query:

What is the latest stable version of HTMX?

💡 Result:

The latest stable version of HTMX is 2.0.4, released on December 13, 2024. (github.com) This release introduced several improvements and bug fixes. For a comprehensive list of changes, you can refer to the HTMX changelog.

Citations:


Update HTMX version to the latest stable release

The snippet currently pins HTMX at 1.9.10, but the latest stable version is 2.0.4 (released December 13, 2024). Updating to 2.0.4 ensures you pick up the newest features and bug fixes.

• File: codeSnippets/snippets/htmx-integration/src/main/kotlin/Routing.kt
Line: 28

Suggested change:

-    script(src = "https://unpkg.com/[email protected]") {}
+    script(src = "https://unpkg.com/[email protected]") {}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
script(src = "https://unpkg.com/htmx.org@1.9.10") {}
script(src = "https://unpkg.com/htmx.org@2.0.4") {}
🤖 Prompt for AI Agents
In codeSnippets/snippets/htmx-integration/src/main/kotlin/Routing.kt at line 28,
update the HTMX script source URL from version 1.9.10 to the latest stable
version 2.0.4 by changing the version number in the src attribute to ensure the
application uses the newest features and bug fixes.

}
body {
div {
id = "content"
h1 { +"HTMX Demo" }

button {
id = "load-button"
attributes.hx {
get = "/data"
target = "#result"
swap = HxSwap.innerHtml
trigger = "click"
}
+"Load Data"
}

div {
id = "result"
+"Data will appear here"
}
}
}
}
}

route("data") {
// Regular request
get {
call.respondText("Please use HTMX to load this data")
}

// Any HTMX request
hx.get {
call.respondText("<p>Data loaded via HTMX!</p>")
}

// HTMX request with specific target
hx {
target("#result") {
get {
call.respondText("<p>Data specifically for #result element</p>")
}
}

// HTMX request with specific trigger
trigger("#load-button") {
get {
call.respondText("<p>Data loaded by #load-button</p>")
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
ktor:
application:
modules:
- com.example.ApplicationKt.module
deployment:
port: 8080
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
<logger name="org.eclipse.jetty" level="INFO"/>
<logger name="io.netty" level="INFO"/>
</configuration>
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class CustomerTests {
application {
main()
}
val client = createClient {
client = createClient {
install(ContentNegotiation) {
json()
}
Expand Down
3 changes: 3 additions & 0 deletions ktor.tree
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
accepts-web-file-names="configuration.html,configurations.html,environments.html,configuration-file.html"/>
<toc-element topic="server-modules.md"
accepts-web-file-names="modules.html"/>
<toc-element topic="server-dependency-injection.md"/>
<toc-element topic="server-plugins.md"
toc-title="Plugins"
accepts-web-file-names="zfeatures.html,features.html,plugins.html"/>
Expand Down Expand Up @@ -376,11 +377,13 @@

<toc-element toc-title="Integrations">
<toc-element topic="full-stack-development-with-kotlin-multiplatform.topic"/>
<toc-element topic="htmx-integration.md"/>
<toc-element topic="tutorial-first-steps-with-kotlin-rpc.topic"/>
</toc-element>

<toc-element toc-title="Releases">
<toc-element topic="releases.md"/>
<toc-element topic="whats-new-320.md"/>
<toc-element topic="migration-to-20x.md"
accepts-web-file-names="migrating-2.html"/>
<toc-element topic="migration-to-22x.md"
Expand Down
3 changes: 3 additions & 0 deletions labels.list
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
<primary-label id="server-plugin" short-name="S" name="Server Plugin" color="purple">
Server Plugin
</primary-label>
<primary-label id="experimental" name="Experimental" short-name="" color="tangerine">
This feature is experimental. It may be dropped or changed at any time. Opt-in is required (see details below).
</primary-label>

<secondary-label id="wip" name="WIP" color="purple">Work in progress</secondary-label>
<secondary-label id="beta" name="β" color="tangerine">Beta</secondary-label>
Expand Down
35 changes: 33 additions & 2 deletions topics/client-default-request.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ The [DefaultRequest](https://api.ktor.io/ktor-client/ktor-client-core/io.ktor.cl

## Install DefaultRequest {id="install_plugin"}

To install `DefaultRequest`, pass it to the `install` function inside a [client configuration block](client-create-and-configure.md#configure-client) ...
To install `DefaultRequest`, pass it to the `install` function inside a [client configuration block](client-create-and-configure.md#configure-client):

```kotlin
import io.ktor.client.*
import io.ktor.client.engine.cio.*
Expand All @@ -33,7 +34,7 @@ val client = HttpClient(CIO) {
}
```

... or call the `defaultRequest` function and [configure](#configure) required request parameters:
Or call the `defaultRequest` function and [configure](#configure) required request parameters:

```kotlin
import io.ktor.client.*
Expand Down Expand Up @@ -99,6 +100,36 @@ defaultRequest {
}
```

### Unix domain sockets

> Unix domain sockets are supported only in the CIO engine.
>
{style="note"}

You can [build individual requests with Unix domain sockets](client-requests.md#specify-a-unix-domain-socket),
but you can also configure a default request with a socket parameter.

To do that, pass a `unixSocket` call with the path to the socket to the `defaultRequest` function,
for example:

```kotlin
val client = HttpClient(CIO)

// Sending a single request to a Unix domain socket
val response: HttpResponse = client.get("/") {
unixSocket("/tmp/test-unix-socket-ktor.sock")
}

// Setting up the socket for all requests from that client
val clientDefault = HttpClient(CIO) {
defaultRequest {
unixSocket("/tmp/test-unix-socket-ktor.sock")
}
}

val response: HttpResponse = clientDefault.get("/")
```

## Example {id="example"}

The example below uses the following `DefaultRequest` configuration:
Expand Down
43 changes: 43 additions & 0 deletions topics/client-dependencies.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,46 @@ which dependencies you need from a topic for a required plugin.

> For a multiplatform project, a plugin dependency should be added to the `commonMain` source set. Note that some
plugins might have [limitations](client-engines.md#limitations) for specific platforms.

## Ensure Ktor version consistency

<chapter title="Using the Ktor BOM dependency">

The Ktor BOM allows you to ensure that all Ktor modules use the same consistent version without specifying
the version for each dependency individually.

To add the Ktor BOM dependency, declare it in your build script as follows:

<tabs group="languages">
<tab title="Gradle (Kotlin)" group-key="kotlin">
<code-block lang="Kotlin">
implementation(platform("io.ktor:ktor-bom:$ktor_version"))
</code-block>
</tab>
<tab title="Gradle (Groovy)" group-key="groovy">
<code-block lang="Groovy">
implementation platform "io.ktor:ktor-bom:$ktor_version"
</code-block>
</tab>
<tab title="Maven" group-key="maven">
<code-block lang="XML">
<![CDATA[
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.ktor</groupId>
<artifactId>ktor-bom</artifactId>
<version>%ktor_version%</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
]]>
</code-block>
</tab>
</tabs>
</chapter>

<var name="target_module" value="client"/>
<include from="server-dependencies.topic" element-id="using-version-catalog"/>
24 changes: 21 additions & 3 deletions topics/client-requests.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Learn how to make requests and specify various request parameters: a request URL
After [setting up the client](client-create-and-configure.md), you can make HTTP requests. The main way of making HTTP requests is the [request](https://api.ktor.io/ktor-client/ktor-client-core/io.ktor.client.request/request.html) function that can take a URL as a parameter. Inside this function, you can configure various request parameters:
* Specify an HTTP method, such as `GET`, `POST`, `PUT`, `DELETE`, `HEAD`, `OPTIONS`, or `PATCH`.
* Specify a URL as a string or configure URL components (a domain, a path, query parameters, etc.) separately.
* Specify a Unix domain socket.
* Add headers and cookies.
* Set the body of a request, for example, a plain text, a data object, or form parameters.

Expand Down Expand Up @@ -119,6 +120,25 @@ You can configure a URL fragment using the `fragment` property.
Note that `fragment` [encodes][percent_encoding] a URL fragment.
To disable encoding, use `encodedFragment`.

## Specify a Unix domain socket

> Unix domain sockets are supported only in the CIO engine.
> To use a Unix socket with a Ktor server, [configure the server](server-configuration-code.topic#cio-code) accordingly.
>
{style="note"}

You can make requests to a server listening to a Unix domain socket by calling the `unixSocket` function
for a CIO client:

```kotlin
val client = HttpClient(CIO)

val response: HttpResponse = client.get("/") {
unixSocket("/tmp/test-unix-socket-ktor.sock")
}
```

You can also set up a Unix domain socket as a part of a [default request](client-default-request.md#unix-domain-sockets).

## Set request parameters {id="parameters"}
In this section, we'll see 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](client-default-request.md) plugin.
Expand All @@ -134,8 +154,7 @@ To add headers to the request, you can use the following ways:
- The [header](https://api.ktor.io/ktor-client/ktor-client-core/io.ktor.client.request/header.html) function allows you to append a single header.
- The `basicAuth` and `bearerAuth` functions add the `Authorization` header with a corresponding HTTP scheme.
> For advanced authentication configuration, refer to [](client-auth.md).




### Cookies {id="cookies"}
To send cookies, use the [cookie](https://api.ktor.io/ktor-client/ktor-client-core/io.ktor.client.request/cookie.html) function:
Expand All @@ -147,7 +166,6 @@ To send cookies, use the [cookie](https://api.ktor.io/ktor-client/ktor-client-co
Ktor also provides the [HttpCookies](client-cookies.md) plugin that allows you to keep cookies between calls. If this plugin is installed, cookies added using the `cookie` function are ignored.



## Set request body {id="body"}
To set the body of a request, you need to call the `setBody` function exposed by [HttpRequestBuilder](https://api.ktor.io/ktor-client/ktor-client-core/io.ktor.client.request/-http-request-builder/index.html). 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.

Expand Down
7 changes: 5 additions & 2 deletions topics/client-responses.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,11 @@ below shows how to get a response as a `ByteArray` and save it to a file:
The [`onDownload()`](https://api.ktor.io/ktor-client/ktor-client-core/io.ktor.client.plugins/on-download.html) extension
function in the example above is used to display download progress.

This approach loads the entire response into memory at once, which can be problematic for large files. To reduce memory
usage, consider [streaming the data](#streaming) in chunks.
For non-streaming requests, the response body is automatically loaded and cached in memory, allowing repeated access.
While this is efficient for small payloads, it may lead to high memory usage with large responses.

To handle large responses efficiently, use a [streaming approach](#streaming),
which processes the response incrementally without saving it in memory.

### JSON object {id="json"}

Expand Down
Loading