Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
ebce600
KTOR-9028 Add docs for the OAuth fallback function (#722)
vnikolova Dec 2, 2025
6ce1e92
KTOR-8952 Documentation for multiple header parsing (#727)
vnikolova Dec 5, 2025
bdeb6f4
fix: KTOR-8880
nomisRev Dec 8, 2025
522c4a5
Merge pull request #731 from ktorio/nomisrev/ktor-8880
nomisRev Dec 9, 2025
d30f9dc
Merge remote-tracking branch 'origin/main' into 3.4.0
vnikolova Dec 10, 2025
e748739
KTOR-8949, KTOR-8950, KTOR-8948 Docs for client auth cache control (#…
vnikolova Dec 10, 2025
9663db3
KTOR-9068 Documentation for OkHttp duplex streaming config property (…
vnikolova Dec 10, 2025
6f51031
KTOR-9149 Add documentation for SSL trust store settings in a config …
vnikolova Dec 10, 2025
5ef7f88
KTOR-9150 Documentation for Partial HTML response (#736)
vnikolova Dec 15, 2025
a8533c0
KTOR-9185 Http Request Lifecycle (#733)
nomisRev Dec 15, 2025
2d8ea58
fix typo
vnikolova Dec 15, 2025
c58e767
KTOR-8900 Documentation for Apache5 connection manager config (#739)
vnikolova Dec 16, 2025
3ae05c1
KTOR-8902 Add documentation for replacing plugin configuration (#740)
vnikolova Dec 16, 2025
4c69ee1
KTOR-9175 Add API Key auth documentation (#737)
nathanfallet Dec 16, 2025
61bd4fa
KTOR-8959 Add docs for the `respondResource` method (#738)
Stexxe Dec 18, 2025
e69cc58
add a what's new entry on API key auth and fix dependencies
vnikolova Dec 18, 2025
fb73e9f
KTOR-9160 Add a what's new entry for native engines dispatcher config…
vnikolova Dec 19, 2025
1a80da6
KTOR-9161 Add a what's new entry for running .execute on the engine d…
vnikolova Dec 19, 2025
87bcf75
resolve comments from tw review
vnikolova Dec 19, 2025
1bea16b
update ktor version in docs only
vnikolova Dec 19, 2025
b598d6f
remove code comment
vnikolova Jan 2, 2026
7fcd193
KTOR-9216 Documentation for ByteReadChannel.readTo util (#748)
vnikolova Jan 5, 2026
982c2ed
KTOR-9159 Documentation for shared web source set support (#747)
vnikolova Jan 20, 2026
4d59084
KTOR-9165 and KTOR-9193 Documentation for OpenAPI specification gener…
vnikolova Jan 20, 2026
c7d619c
KTOR-8996 Add documentation for WebRTC iOS Client (#751)
zibet27 Jan 20, 2026
236232d
Changes for Zstd (#750)
bjhham Jan 23, 2026
f69f423
bump Kotlin and Ktor versions, add release details and API links in w…
vnikolova Jan 23, 2026
124624b
fix non-unique id
vnikolova Jan 23, 2026
d4b008c
Add a warning for required dependency with SwaggerUI and OpenAPI plug…
vnikolova Jan 23, 2026
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
3 changes: 3 additions & 0 deletions cfg/glossary.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@
<term name="query_string">
A part of a URL that assigns values to specified parameters and starts with the ? character.
</term>
<term name="classpath">
A list of locations where the JVM looks for user classes and resources.
</term>
</terms>
8 changes: 4 additions & 4 deletions codeSnippets/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ buildscript {
}
repositories {
mavenLocal()
maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots") }
}

configurations.classpath {
Expand Down Expand Up @@ -70,14 +70,14 @@ allprojects {
kotlin_version = rootProject.properties['kotlin_snapshot_version']
repositories {
mavenLocal()
maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots") }
}
}

repositories {
mavenCentral()
maven {
url "https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev"
url = uri("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev")
}
}
}
Expand All @@ -89,7 +89,7 @@ def ktorRepositoryDir = file("$buildDir/m2")
if (ktorRepositoryDir.exists()) {
allprojects {
repositories {
maven { url ktorRepositoryDir.absolutePath }
maven { url = uri(ktorRepositoryDir.absolutePath) }
}
}
} else {
Expand Down
6 changes: 4 additions & 2 deletions codeSnippets/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ kotlin.code.style = official
kotlin.native.binary.memoryModel = experimental
# gradle configuration
org.gradle.configureondemand = false
kotlin.mpp.applyDefaultHierarchyTemplate=false
org.gradle.java.installations.auto-download=false
# versions
kotlin_version = 2.2.20
ktor_version = 3.3.3
kotlin_version = 2.3.0
ktor_version = 3.4.0
kotlinx_coroutines_version = 1.10.1
kotlinx_serialization_version = 1.8.0
kotlin_css_version = 1.0.0-pre.721
Expand Down
2 changes: 2 additions & 0 deletions codeSnippets/settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ module("snippets", "tutorial-server-restful-api")
module("snippets", "tutorial-server-websockets")
module("snippets", "tutorial-server-docker-compose")
module("snippets", "htmx-integration")
module("snippets", "server-http-request-lifecycle")
module("snippets", "openapi-spec-gen")

if(!System.getProperty("os.name").startsWith("Windows")) {
module("snippets", "embedded-server-native")
Expand Down
10 changes: 10 additions & 0 deletions codeSnippets/snippets/_misc_client/Apache5Create.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,21 @@ val client = HttpClient(Apache5) {
socketTimeout = 10_000
connectTimeout = 10_000
connectionRequestTimeout = 20_000

// Configure the Apache5 ConnectionManager
configureConnectionManager {
setMaxConnPerRoute(1_000)
setMaxConnTotal(2_000)
}

// Customize the underlying Apache client for other settings
customizeClient {
// this: HttpAsyncClientBuilder
setProxy(HttpHost("127.0.0.1", 8080))
// ...
}

// Customize per-request settings
customizeRequest {
// this: RequestConfig.Builder
}
Expand Down
8 changes: 8 additions & 0 deletions codeSnippets/snippets/_misc_client/InstallOrReplacePlugin.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import io.ktor.client.*
import io.ktor.client.engine.cio.*

val client = HttpClient(CIO) {
installOrReplace(ContentNegotiation) {
// ...
}
Comment on lines +1 to +7
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Ktor 3.4.0 HttpClientConfig installOrReplace ContentNegotiation imports

💡 Result:

For Ktor 3.4.0 HttpClientConfig.installOrReplace(ContentNegotiation) { ... }, use the client ContentNegotiation plugin + the installOrReplace extension imports:

import io.ktor.client.HttpClient
import io.ktor.client.plugins.installOrReplace // or: import io.ktor.client.plugins.*
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation // or: import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.serialization.kotlinx.json.* // for json()

ContentNegotiation for the client lives in io.ktor.client.plugins.contentnegotiation (not the server package). [1][2]

If you’re using kotlinx JSON, you also need these deps: ktor-client-content-negotiation and ktor-serialization-kotlinx-json. [1]

Sources: [1] [2]


Add missing imports for installOrReplace and ContentNegotiation.

The io.ktor.client.* wildcard import doesn't include plugin APIs. This snippet won't compile without explicit imports for the plugin function and ContentNegotiation type.

🔧 Proposed fix
 import io.ktor.client.*
 import io.ktor.client.engine.cio.*
+import io.ktor.client.plugins.installOrReplace
+import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
📝 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
import io.ktor.client.*
import io.ktor.client.engine.cio.*
val client = HttpClient(CIO) {
installOrReplace(ContentNegotiation) {
// ...
}
import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.plugins.installOrReplace
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
val client = HttpClient(CIO) {
installOrReplace(ContentNegotiation) {
// ...
}
🤖 Prompt for AI Agents
In `@codeSnippets/snippets/_misc_client/InstallOrReplacePlugin.kt` around lines 1
- 7, The snippet is missing explicit Ktor plugin imports so it won't compile;
add imports for the plugin API and the content negotiation plugin (specifically
the symbols installOrReplace and ContentNegotiation) by importing the Ktor
client plugin packages (e.g., the ContentNegotiation class from
io.ktor.client.plugins.contentnegotiation and the installOrReplace extension
from the Ktor client plugins package) so the use of
installOrReplace(ContentNegotiation) in the HttpClient builder resolves.

}
1 change: 1 addition & 0 deletions codeSnippets/snippets/_misc_client/OkHttpConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ val client = HttpClient(OkHttp) {
addNetworkInterceptor(interceptor)

preconfigured = okHttpClientInstance
duplexStreamingEnabled = true // Only available for HTTP/2 connections
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ fun Application.main(httpClient: HttpClient = applicationHttpClient) {
}
)
}
fallback = { cause ->
if (cause is OAuth2RedirectError) {
respondRedirect("/login-after-fallback")
} else {
respond(HttpStatusCode.Forbidden, cause.message)
}
}
client = httpClient
}
}
Expand Down Expand Up @@ -101,6 +108,9 @@ fun Application.main(httpClient: HttpClient = applicationHttpClient) {
call.respondText("Hello, ${userInfo.name}!")
}
}
get("/login-after-fallback") {
call.respondText("Redirected after fallback")
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ val logback_version: String by project
plugins {
application
kotlin("jvm")
id("io.ktor.plugin") version "3.3.3"
id("io.ktor.plugin") version "3.4.0"
}

application {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ val logback_version: String by project
plugins {
application
kotlin("jvm")
id("io.ktor.plugin") version "3.3.3"
id("io.ktor.plugin") version "3.4.0"
}

application {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ val logback_version: String by project
plugins {
application
kotlin("jvm")
id("io.ktor.plugin") version "3.3.3"
id("io.ktor.plugin") version "3.4.0"
}

application {
Expand Down
2 changes: 1 addition & 1 deletion codeSnippets/snippets/forwarded-header/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ val logback_version: String by project
plugins {
application
kotlin("jvm")
id("io.ktor.plugin") version "3.3.3"
id("io.ktor.plugin") version "3.4.0"
}

application {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ junit = "4.13.2"
kotlin = "2.2.20"
kotlinx-coroutines = "1.10.2"
kotlinxSerializationJson = "1.8.1"
ktor = "3.3.3"
ktor = "3.4.0"
logback = "1.5.18"

[libraries]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,12 @@ fun Application.module() {
}
}
}
get("/fragment") {
call.respondHtmlFragment(HttpStatusCode.Created) {
div("fragment") {
span { +"Created!" }
}
}
}
}
}
2 changes: 1 addition & 1 deletion codeSnippets/snippets/htmx-integration/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ val logback_version: String by project

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

group = "com.example"
Expand Down
3 changes: 2 additions & 1 deletion codeSnippets/snippets/json-kotlinx-openapi/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
val ktor_version: String by project
val kotlin_version: String by project
val kotlin_version = "2.2.20"
val logback_version: String by project
val swagger_codegen_version: String by project

Expand Down Expand Up @@ -28,6 +28,7 @@ dependencies {
implementation("io.ktor:ktor-server-content-negotiation:$ktor_version")
implementation("io.ktor:ktor-serialization-kotlinx-json:$ktor_version")
implementation("io.ktor:ktor-client-content-negotiation:$ktor_version")
implementation("io.ktor:ktor-server-routing-openapi:$ktor_version")
implementation("io.swagger.codegen.v3:swagger-codegen-generators:$swagger_codegen_version")
implementation("ch.qos.logback:logback-classic:$logback_version")
testImplementation("io.ktor:ktor-server-test-host-jvm:$ktor_version")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ val logback_version: String by project
plugins {
application
kotlin("jvm")
id("io.ktor.plugin") version "3.3.3"
id("io.ktor.plugin") version "3.4.0"
}

application {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ktor_version=3.3.3
ktor_version=3.4.0
kotlin_version=2.2.20
logback_version=1.5.6
kotlin.code.style=official
20 changes: 20 additions & 0 deletions codeSnippets/snippets/openapi-spec-gen/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# OpenAPI documentation

A sample Ktor project showing how to build OpenAPI documentation using routing annotations and the compiler
extension of the Ktor Gradle plugin.

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

## Run the application

To run the application, execute the following command in the repository's root directory:

```bash
./gradlew :openapi-spec-gen:run
```

To view the OpenAPI documentation, navigate to the following URLs:

- [http://0.0.0.0:8080/docs.json](http://0.0.0.0:8080/docs.json) to view a JSON document of the API spec.
- [http://0.0.0.0:8080/openApi](http://0.0.0.0:8080/openApi) to view the OpenAPI UI for the API spec.
- [http://0.0.0.0:8080/swaggerUI](http://0.0.0.0:8080/swaggerUI) to view the Swagger UI for the API spec.
40 changes: 40 additions & 0 deletions codeSnippets/snippets/openapi-spec-gen/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
val ktor_version: String by project
val kotlin_version = "2.2.20"
val logback_version: String by project

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

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

repositories {
mavenCentral()
maven("https://maven.pkg.jetbrains.space/public/p/ktor/eap")
}

ktor {
openApi {
enabled = true
codeInferenceEnabled = true
onlyCommented = false
}
}


dependencies {
implementation("io.ktor:ktor-server-core:$ktor_version")
implementation("io.ktor:ktor-server-routing-openapi:$ktor_version")
implementation("io.ktor:ktor-server-openapi:$ktor_version")
implementation("io.ktor:ktor-server-content-negotiation:${ktor_version}")
implementation("io.ktor:ktor-serialization-kotlinx-json:${ktor_version}")
implementation("io.ktor:ktor-server-swagger:${ktor_version}")
implementation("io.ktor:ktor-server-netty:$ktor_version")
implementation("ch.qos.logback:logback-classic:$logback_version")
testImplementation("io.ktor:ktor-server-test-host-jvm:$ktor_version")
testImplementation("org.jetbrains.kotlin:kotlin-test")
}
Loading