Skip to content

Add documentation for 3.4.0#741

Merged
vnikolova merged 29 commits intomainfrom
3.4.0
Jan 23, 2026
Merged

Add documentation for 3.4.0#741
vnikolova merged 29 commits intomainfrom
3.4.0

Conversation

@vnikolova
Copy link
Collaborator

@vnikolova vnikolova commented Dec 16, 2025

New topics:

  • What's new in Ktor 3.4.0 (whats-new-340.md)
  • HTTP request lifecycle (server-http-request-lifecycle.md)
  • API Key authentication (server-api-key-auth.md)

New sections:

  • Token caching and cache control (client-auth.md)
  • Splitting header values (client-responses.md)
  • Compression level (server-compression.md)
  • Send partial HTML (server-html-dsl.md)
  • Install or replace a plugin (client-plugins, client-default-request)
  • Resource (server-responses.md)

Improved formatting, grammar and language:

  • Server responses (server-responses.md)
  • Basic and bearer auth (server-basic-auth.md, server-bearer-auth)

New code samples:

  • server-http-lifecycle

vnikolova and others added 11 commits December 2, 2025 15:10
* add multiple header parsing to "what's new"

* add multiple header parsing to client-responses.md
)

* Add a what's new entry for client auth token cache control

* document token cache control in client-auth and client-basic-auth

* add a step for the cacheTokens option in client-bearer-auth.md
* KTOR-9150 Add documentation for partial HTML response

* fix formatting, grammar, and language in server-responses.md
* fix: add Whats New section

* Apply suggestions from code review

Co-authored-by:  Vik Nikolova <contact@viknikolova.com>

* KTOR-9185 Add a new topic and project sample for the HttpRequestLifecycle plugin

---------

Co-authored-by: Vik Nikolova <contact@viknikolova.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 16, 2025

Walkthrough

This PR upgrades Ktor from 3.3.3 to 3.4.0 and Kotlin from 2.2.20 to 2.3.0 across documentation and code samples, adds two new snippet projects (openapi-spec-gen and server-http-request-lifecycle), and comprehensively documents new features including API Key authentication, Zstandard compression, HTML fragments, and runtime OpenAPI metadata generation.

Changes

Cohort / File(s) Summary
Version upgrades (repetitive pattern)
codeSnippets/gradle.properties, codeSnippets/snippets/gradle/libs.versions.toml (multiple), codeSnippets/snippets/*/build.gradle.kts (14 files), codeSnippets/snippets/*/gradle.properties, codeSnippets/snippets/tutorial-server-get-started-maven/pom.xml, help-versions.json, project.ihp, v.list
Systematic updates: Ktor plugin bumped from 3.3.3 → 3.4.0; Kotlin from 2.2.20 → 2.3.0; new Gradle properties added (kotlin.mpp.applyDefaultHierarchyTemplate=false, org.gradle.java.installations.auto-download=false); Maven and version catalogs updated consistently.
New OpenAPI spec generation sample
codeSnippets/snippets/openapi-spec-gen/*
Complete new Ktor sample project with 8 files: build.gradle.kts with OpenAPI plugin configuration, Application.kt implementing user CRUD routes with OpenAPI describe blocks and schema generation, test file, and configuration resources (application.conf, logback.xml, README.md). Demonstrates runtime OpenAPI metadata generation and Swagger/OpenAPI UI integration.
New HTTP request lifecycle sample
codeSnippets/snippets/server-http-request-lifecycle/*
Complete new Ktor sample project with 6 files: build.gradle.kts, Application.kt implementing HttpRequestLifecycle plugin with cancelCallOnClose configuration and long-running endpoint with cancellation handling, integration test demonstrating client disconnection cancellation, and configuration resources.
Gradle repository and build configuration updates
codeSnippets/build.gradle.kts, codeSnippets/snippets/json-kotlinx-openapi/build.gradle.kts, codeSnippets/snippets/tutorial-server-docker-compose/build.gradle.kts, codeSnippets/snippets/tutorial-server-websockets/build.gradle.kts
Replaced literal URL strings with uri() construction (url "..." → url = uri("...")); refactored Kotlin version from project property to hardcoded value in json-kotlinx-openapi; added ktor-server-routing-openapi dependency; replaced -jvm classifiers on ktor-client-content-negotiation artifacts.
Apache5 and OkHttp client engine enhancements
codeSnippets/snippets/_misc_client/Apache5Create.kt, codeSnippets/snippets/_misc_client/OkHttpConfig.kt, codeSnippets/snippets/_misc_client/InstallOrReplacePlugin.kt
Added configureConnectionManager block with connection pool settings (setMaxConnPerRoute, setMaxConnTotal); added duplexStreamingEnabled for OkHttp HTTP/2; new InstallOrReplacePlugin.kt demonstrating replaceable install mechanism for ContentNegotiation.
OAuth and HTML routing enhancements
codeSnippets/snippets/auth-oauth-google/src/main/kotlin/.../Application.kt, codeSnippets/snippets/html/src/main/kotlin/.../Application.kt
Added OAuth2 fallback error handler with redirect to /login-after-fallback endpoint; added GET /fragment route returning HTML fragment with HTTP 201 Created status using respondHtmlFragment.
Documentation: authentication and client features
topics/client-auth.md, topics/client-basic-auth.md, topics/client-bearer-auth.md, topics/client-default-request.md, topics/client-plugins.md
Extensive rewrites: added token caching control section with clearToken() and cacheTokens options; introduced installOrReplace() and defaultRequest(replace=true) patterns; restructured plugin installation guidance with new "Add plugin dependencies" and "Install or replace" sections; updated code-style link formatting throughout.
Documentation: server authentication and compression
topics/server-api-key-auth.md (new), topics/server-auth.md, topics/server-compression.md, topics/server-ssl.md
Added comprehensive API Key authentication guide (285 lines) with configuration, validation, security practices; added Zstandard (zstd) compression support with dependency and level configuration; updated SSL configuration for trust store (trustStore, trustStorePassword, enabledProtocols); updated server-auth.md to list API Key scheme.
Documentation: HTTP responses and HTML DSL
topics/client-responses.md, topics/server-responses.md, topics/server-html-dsl.md
Reorganized streaming sections with sequential chunk processing and HttpStatement patterns; added respondHtmlFragment() for partial HTML fragments; expanded templates section with detailed walkthrough; updated header access descriptions with contentType(), charset(), etag(), setCookie() functions; added Resource section for respondResource().
Documentation: OpenAPI and Swagger
topics/openapi-spec-generation.md, topics/server-openapi.md, topics/server-swagger-ui.md, topics/whats-new-330.md
Major refactor: introduced compile-time and runtime OpenAPI metadata generation modes; documented runtime route annotations with .describe {}; split static vs. runtime generation paths; added Ktor 3.4.0 dependency notes and 3.4.1 migration warnings; updated example snippets for OpenApiDocSource.Routing and metadata precedence; converted experimental label from secondary to primary.
Documentation: release notes and new features
topics/releases.md, topics/whats-new-340.md (new)
Added 3.4.0 release entry (January 23, 2026) to releases table; created comprehensive 609-line whats-new-340.md documenting OAuth fallback, Zstd, HTML fragments, HTTP lifecycle, respondResource(), runtime OpenAPI, API Key auth, token cache control, duplex streaming, engine improvements, and I/O enhancements.
Documentation: client engines and WebRTC
topics/client-engines.md, topics/client-webrtc.md
Expanded Apache5 configureConnectionManager guidance with preserve-behavior notes; updated WinHttp/Curl engine reference links; added iOS platform support to WebRTC with platform-specific rendering examples and getNative() usage across JS/Wasm/Android/iOS tabs; updated permissions and supported platforms.
Documentation: OAuth and HTML DSL
topics/server-oauth.md
Updated snippet include-line ranges for Application.kt to reflect fallback handler code; added documentation bullet for fallback property error handling.
Glossary and configuration metadata
cfg/glossary.xml, labels.list, ktor.tree
Added "classpath" glossary term; updated experimental label short-name from empty to "Experimental" and removed secondary experimental label; added ktor.tree TOC entries for server-http-request-lifecycle.md and server-api-key-auth.md under Requests and Authentication sections.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

dependencies, documentation, samples

Suggested reviewers

  • Stexxe
  • e5l
  • bjhham
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add documentation for 3.4.0' accurately reflects the main objective of the PR, which is to add and improve documentation for Ktor version 3.4.0.
Description check ✅ Passed The description comprehensively lists new topics, sections, improvements, and code samples added in the PR, all of which are supported by the changeset details.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@AlejandraPedroza AlejandraPedroza self-assigned this Dec 17, 2025
Copy link

@AlejandraPedroza AlejandraPedroza left a comment

Choose a reason for hiding this comment

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

Huge work! I left some suggestions. Please check:

  • External links (especially those pointing to ktorio repo on GitHub), as they appear as page not found.
  • Code comments that should be in 3rd person verb, above the code line, and other criteria listed in our style guide.
  • Consistency across plugin names, which in some cases appear in monospaced fonts and in some cases they not.
  • Functions that may be missing () next to their names.

Copy link

@AlejandraPedroza AlejandraPedroza left a comment

Choose a reason for hiding this comment

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

Huge work! I left some suggestions. Please check:

  • External links (especially those pointing to ktorio repo on GitHub), as they appear as page not found.
  • Code comments that should be in 3rd person verb, above the code line, and other criteria listed in our style guide.
  • Consistency across plugin names, which in some cases appear in monospaced fonts and in some cases they not.
  • Functions that may be missing () next to their names.

Copy link

@AlejandraPedroza AlejandraPedroza left a comment

Choose a reason for hiding this comment

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

Thanks for the changes. LGTM 🚀

vnikolova and others added 5 commits January 2, 2026 13:07
* add a what's new entry for shared source set support for js and wasmJS
…ation (#744)

* KTOR-9165 and KTOR-9193 docs for runtime route annotations and openapi compiler extension

* add a code sample project, update docs and add todos

* update openapi compiler plugin configuration

* update for technical accuracy and add links

* update comment formatting, add metadata precedence and code inference rules

* update sample project, compiler config options descriptions and invalid deps

* update the swagger and openapi plugin topics

* resolve comments and add a new section for Route.hide()
* KTOR-8996 Add documentation for WebRTC iOS Client
@vnikolova vnikolova marked this pull request as ready for review January 23, 2026 12:48
@vnikolova vnikolova added this to the 3.4.0 milestone Jan 23, 2026
@vnikolova vnikolova merged commit 391fdf2 into main Jan 23, 2026
1 check was pending
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
topics/client-webrtc.md (1)

12-13: Update the TLDR to include iOS platform support.

The TLDR section still lists only "JS/Wasm, Android" as supported platforms, but the rest of the documentation now includes iOS support. This inconsistency will confuse users.

📝 Proposed fix
     <p>
-        <b>Supported platforms</b>: JS/Wasm, Android
+        <b>Supported platforms</b>: JS/Wasm, Android, iOS
     </p>   
🤖 Fix all issues with AI agents
In `@codeSnippets/snippets/_misc_client/InstallOrReplacePlugin.kt`:
- Around line 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.

In `@codeSnippets/snippets/proguard/build.gradle.kts`:
- Around line 17-21: The plugin declaration uses a non-existent version "3.4.0"
for io.ktor.plugin; update the version string in the plugins block (the
id("io.ktor.plugin") version "3.4.0" entry) to the available release "3.3.3" so
Gradle can resolve the plugin and the build will succeed.

In
`@codeSnippets/snippets/server-http-request-lifecycle/src/test/kotlin/ApplicationTest.kt`:
- Around line 24-26: The test is calling the wrong route: in ApplicationTest.kt
the launched job invokes client.get("http://localhost:8080/long") but the server
route is registered as "/long-process"; update the request URL used in the
coroutine (the client.get call inside the job) to
"http://localhost:8080/long-process" so the test hits the intended LongProcess
route and verifies cancellation behavior.

In `@topics/server-compression.md`:
- Line 23: The examples in the topics/server-compression.md file reference
non-existent Ktor DSL functions (zstd() and ztsd()) for the Compression plugin;
replace those examples with working approaches: either remove the invalid
zstd()/ztsd() calls or show how to wire a custom ContentEncoder implementation
into the Compression plugin (follow the file’s own "Implement custom encoder"
pattern), and if relying on ktor-server-compression-zstd, demonstrate
integrating its encoder class instead of calling zstd()—update every occurrence
(lines referenced for ztsd/zstd in examples) to use the Compression plugin with
gzip()/deflate()/identity() or a documented custom encoder class name (e.g.,
your ZstdContentEncoder) so the examples compile and reflect real APIs.
🟡 Minor comments (22)
codeSnippets/snippets/html/src/main/kotlin/com/example/Application.kt-28-34 (1)

28-34: Use 200 OK for a GET response instead of 201 Created.

A GET should generally return 200 OK; 201 Created implies resource creation and is typically used for POST. Keeping 200 avoids confusing readers of the docs. Line 29.

✅ Suggested change
-            call.respondHtmlFragment(HttpStatusCode.Created) {
+            call.respondHtmlFragment(HttpStatusCode.OK) {
topics/client-engines.md-291-293 (1)

291-293: Fix markdownlint MD039 by keeping link text contiguous.

The link text is split across lines, which triggers the “no-space-in-links” rule. Consolidate it to a single line.

💡 Suggested fix
-   [
-   `WinHttpClientEngineConfig`](https://api.ktor.io/ktor-client-winhttp/io.ktor.client.engine.winhttp/-win-http-client-engine-config/index.html).
+   [`WinHttpClientEngineConfig`](https://api.ktor.io/ktor-client-winhttp/io.ktor.client.engine.winhttp/-win-http-client-engine-config/index.html).
codeSnippets/snippets/auth-oauth-google/src/main/kotlin/com/example/oauth/google/Application.kt-57-63 (1)

57-63: Avoid reflecting raw OAuth error messages to clients.
cause.message can be null and may expose provider details. Prefer a generic response (and log the cause if needed).

🔧 Safer response message
             fallback = { cause ->
                 if (cause is OAuth2RedirectError) {
                     respondRedirect("/login-after-fallback")
                 } else {
-                    respond(HttpStatusCode.Forbidden, cause.message)
+                    respond(HttpStatusCode.Forbidden, "OAuth authentication failed")
                 }
             }
topics/server-oauth.md-133-134 (1)

133-134: Standardize “Authorized” spelling and resolve linted fragments.
LanguageTool and markdownlint flagged this line. Consider aligning on US spelling (“Authorized”) to match “authorization/authorize,” and confirm the fragment target is valid for your doc toolchain (or adjust to the generated slug).

💡 Suggested tweak (spelling)
-* The `urlProvider` specifies a [redirect route](`#redirect-route`) that will be invoked when authorization is completed.
-  > Make sure that this route is added to a list of [**Authorised redirect URIs**](`#authorization-credentials`).
+* The `urlProvider` specifies a [redirect route](`#redirect-route`) that will be invoked when authorization is completed.
+  > Make sure that this route is added to a list of [**Authorized redirect URIs**](`#authorization-credentials`).
codeSnippets/snippets/openapi-spec-gen/README.md-16-20 (1)

16-20: Use localhost/127.0.0.1 in the browser-facing URLs.
0.0.0.0 is a bind address and can confuse users when pasted into a browser. Consider swapping to localhost (or 127.0.0.1) for the doc links.

💡 Suggested update
-- [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.
+- [http://localhost:8080/docs.json](http://localhost:8080/docs.json) to view a JSON document of the API spec.
+- [http://localhost:8080/openApi](http://localhost:8080/openApi) to view the OpenAPI UI for the API spec.
+- [http://localhost:8080/swaggerUI](http://localhost:8080/swaggerUI) to view the Swagger UI for the API spec.
codeSnippets/snippets/server-http-request-lifecycle/src/main/resources/logback.xml-4-4 (1)

4-4: Use lowercase yyyy for calendar year in date pattern.

The pattern YYYY represents "week year" (ISO 8601), not "calendar year". This can produce incorrect year values near year boundaries (e.g., December 31, 2024 might display as 2025). Use lowercase yyyy for the standard calendar year.

Proposed fix
-        <pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
+        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
codeSnippets/snippets/openapi-spec-gen/src/main/resources/logback.xml-4-4 (1)

4-4: Use lowercase yyyy for calendar year in date pattern.

Same issue as the other logback.xml — YYYY is "week year" which can produce unexpected results near year boundaries. Use yyyy for calendar year.

Proposed fix
-        <pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
+        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
codeSnippets/snippets/server-http-request-lifecycle/src/main/kotlin/com/example/Application.kt-26-34 (1)

26-34: Unreachable code: call.respond("Completed") can never execute.

The while (isActive) loop on line 27 only exits when the coroutine is cancelled (i.e., isActive becomes false). At that point, a CancellationException is thrown at the delay() suspension point, which jumps directly to the catch block. The call.respond("Completed") statement on line 31 is therefore dead code.

If the intent is to demonstrate cleanup on cancellation, consider removing the unreachable respond call or restructuring to show a finite operation that can complete normally.

Suggested fix
         get("/long-process") {
             try {
-                while (isActive) {
+                repeat(10) {
+                    ensureActive()
                     delay(10_000)
                     log.info("Very important work.")
                 }
                 call.respond("Completed")
             } catch (e: CancellationException) {
                 log.info("Cleaning up resources.")
             }
         }
topics/server-http-request-lifecycle.md-57-59 (1)

57-59: Remove blank line between blockquotes to fix markdown lint warning.

The blank line on line 58 between the note block and the tip block triggers a markdown lint warning (MD028: no-blanks-blockquote). These should be adjacent or separated by regular content.

Suggested fix
 > [Coroutine cancellation](https://kotlinlang.org/docs/cancellation-and-timeouts.html).
 {style="note"}
-
+
 > For the full example, see [%example_name%](https://github.com/ktorio/ktor-documentation/tree/%ktor_version%/codeSnippets/snippets/%example_name%).

If both blocks should remain separate, consider adding a brief transitional sentence between them, or merge the example link into the note block.

codeSnippets/snippets/server-http-request-lifecycle/build.gradle.kts-25-29 (1)

25-29: Inconsistent test dependency versions: add explicit version variables to lines 26-28.

Lines 26-28 declare ktor-server-netty, ktor-client-cio, and kotlinx-coroutines-test without versions while line 25 and earlier dependencies use explicit version variables. This inconsistency may cause unpredictable transitive dependency resolution. Use $ktor_version for Ktor dependencies and define or use version variables for others to match the pattern throughout the file.

codeSnippets/snippets/server-http-request-lifecycle/build.gradle.kts-8-8 (1)

8-8: Use the kotlin_version property instead of hardcoding the serialization plugin version.

The serialization plugin version is hardcoded to "2.2.20" while the project's kotlin_version property is 2.3.0 (from codeSnippets/gradle.properties). This creates a version mismatch that could cause incompatibilities.

Suggested fix
-    kotlin("plugin.serialization").version("2.2.20")
+    kotlin("plugin.serialization").version(kotlin_version)
topics/server-responses.md-12-14 (1)

12-14: Remove parentheses from call.response property reference.

ApplicationCall.response is a Kotlin property (not a function), defined as abstract val response: ApplicationResponse. The parentheses in call.response() incorrectly imply a function call and can mislead developers.

Fix
-* The [`call.response()`](https://api.ktor.io/ktor-server-core/io.ktor.server.application/-application-call/response.html) property that returns the [`ApplicationResponse`](https://api.ktor.io/ktor-server-core/io.ktor.server.response/-application-response/index.html) object, providing access to [response parameters](`#parameters`) for setting the status code, adding headers, and configuring cookies.
+* The [`call.response`](https://api.ktor.io/ktor-server-core/io.ktor.server.application/-application-call/response.html) property that returns the [`ApplicationResponse`](https://api.ktor.io/ktor-server-core/io.ktor.server.response/-application-response/index.html) object, providing access to [response parameters](`#parameters`) for setting the status code, adding headers, and configuring cookies.
topics/releases.md-36-43 (1)

36-43: Fix the release link variable for the 3.4.0 row.

The 3.4.0 row still sets the version variable to 3.3.3, which will link to the wrong release details.

💡 Proposed fix
-<var name="version" value="3.3.3"/>
+<var name="version" value="3.4.0"/>
topics/server-openapi.md-73-95 (1)

73-95: Ensure the runtime OpenAPI section has a stable anchor and link text.

The runtime section is linked from above; add an explicit id and a non-empty link label for the tip.

💡 Proposed fix
-## Generate runtime OpenAPI metadata
+## Generate runtime OpenAPI metadata {id="generate-runtime-openapi-metadata"}
@@
-> For more information on the OpenAPI compiler extension and runtime APIs, see [](openapi-spec-generation.md).
+> For more information on the OpenAPI compiler extension and runtime APIs, see [OpenAPI specification generation](openapi-spec-generation.md).
topics/server-swagger-ui.md-62-81 (1)

62-81: Add an explicit anchor id and link text for the runtime OpenAPI section.

The intro links to #generate-runtime-openapi-metadata, but the heading lacks an explicit id. Also the tip link text is empty.

💡 Proposed fix
-## Generate runtime OpenAPI metadata
+## Generate runtime OpenAPI metadata {id="generate-runtime-openapi-metadata"}
@@
-> For more information on the OpenAPI compiler extension and runtime APIs, see [](openapi-spec-generation.md).
+> For more information on the OpenAPI compiler extension and runtime APIs, see [OpenAPI specification generation](openapi-spec-generation.md).
codeSnippets/snippets/tutorial-server-db-integration/gradle/libs.versions.toml-6-6 (1)

6-6: Add -jvm suffix to ktor-client-content-negotiation for consistency.

Artifact io.ktor:ktor-client-content-negotiation-jvm:3.4.0 is published and available on Maven Central with JVM variant support. However, line 26 omits the -jvm suffix while all other Ktor artifacts in this catalog (lines 11–24) include it. Update line 26 to "io.ktor:ktor-client-content-negotiation-jvm" to align with the file's convention.

topics/whats-new-340.md-282-282 (1)

282-282: Header name mismatch in example.

The header is set as "X-Multi-Header" on line 279, but line 282 retrieves "X-Quoted". This will return null since the header names don't match.

Proposed fix
-val forceSplit = headers.getSplitValues("X-Quoted", splitInsideQuotes = true)
+val forceSplit = headers.getSplitValues("X-Multi-Header", splitInsideQuotes = true)
codeSnippets/snippets/openapi-spec-gen/src/main/kotlin/com/example/Application.kt-104-104 (1)

104-104: Incorrect route path creates duplicate /users segment.

The route at line 104 uses get("/users") but it's already nested inside route("/users") (line 77), resulting in the path /api/users/users instead of the intended /api/users.

Proposed fix
-                get("/users") {
+                get {
topics/whats-new-340.md-82-94 (1)

82-94: Incorrect code block language identifier.

The code block is marked as kotlin but contains HOCON configuration syntax (application.conf). This will cause incorrect syntax highlighting.

Proposed fix

Change the language identifier from kotlin to an appropriate format. Since HOCON isn't universally supported, consider using a generic identifier:

-```kotlin
+```
 // application.conf
 ktor {

Or remove the // application.conf comment and keep kotlin if the docs renderer doesn't support HOCON.

topics/openapi-spec-generation.md-134-141 (1)

134-141: Inconsistency between documentation text and code example.

Line 134 mentions adding an ignore marker, but the code example on line 137 shows // ignore! (with exclamation mark). Clarify whether the marker should be ignore or ignore! and ensure consistency between text and example.

Suggested clarification

Either update the text to match the code:

-If inference produces incorrect metadata for a specific endpoint, you can exclude it by adding an `ignore` marker:
+If inference produces incorrect metadata for a specific endpoint, you can exclude it by adding an `ignore!` marker:

Or update the code to match the text:

-// ignore!
+// ignore
codeSnippets/snippets/openapi-spec-gen/src/main/kotlin/com/example/Application.kt-159-161 (1)

159-161: Missing closing brace for route block.

The route("/api") block on line 76 appears to be missing its closing brace. Line 161 closes userCrud() but there should be an additional brace to close the outer route("/api") block.

Proposed fix
                 }
 
+        }
 }
topics/openapi-spec-generation.md-311-313 (1)

311-313: Change RoutingSource to Routing.

Line 311 uses OpenApiDocSource.RoutingSource, but all other documentation and code examples use OpenApiDocSource.Routing. Update to match the correct API name.

🧹 Nitpick comments (12)
codeSnippets/snippets/json-kotlinx-openapi/build.gradle.kts (2)

1-4: Inconsistent version declaration pattern.

kotlin_version is now hardcoded while ktor_version, logback_version, and swagger_codegen_version still use by project delegation. Consider aligning all version declarations to the same pattern for maintainability.


9-9: Duplicated hardcoded Kotlin version.

The serialization plugin version "2.2.20" is duplicated here instead of referencing the kotlin_version variable from line 2. If the Kotlin version changes, this line could be missed.

♻️ Suggested fix
-    kotlin("plugin.serialization").version("2.2.20")
+    kotlin("plugin.serialization").version(kotlin_version)
topics/client-webrtc.md (2)

286-318: Consider adding import statement example for iOS code.

The CocoaPod configuration changes the module name from "WebRTC-SDK" to "WebRTC" (line 311), which affects how developers import the types used in the example (RTCVideoTrack, RTCMTLVideoView). Adding a brief import statement example would help clarify how to use the renamed module.

📝 Suggested enhancement

Add after line 316, before the closing tab tag:

// In your Kotlin code, import the types:
import WebRTC.RTCVideoTrack
import WebRTC.RTCMTLVideoView

341-342: Consider adding Oxford comma for clarity.

The list "JavaScript/Wasm, Android and iOS" could be clearer with an Oxford comma: "JavaScript/Wasm, Android, and iOS".

📝 Suggested enhancement
-- Supported platforms are JavaScript/Wasm, Android and iOS. JVM desktop, and Kotlin/Native support are planned in future
+- Supported platforms are JavaScript/Wasm, Android, and iOS. JVM desktop, and Kotlin/Native support are planned in future
   releases.
topics/server-api-key-auth.md (1)

183-199: Consider adding a note about the kotlinx-datetime dependency.

The code example uses Clock.System.now() which requires the kotlinx-datetime library. Readers may not have this dependency and could be confused by the compile error.

📝 Suggested addition

Add a note before or after the code block:

> The example above uses `Clock.System.now()` from the [kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) library.
>
{style="note"}
codeSnippets/snippets/server-http-request-lifecycle/src/test/kotlin/ApplicationTest.kt (1)

22-31: HttpClient not closed after use.

The HttpClient instance created on line 22 is never closed, which could leak resources. While this is a test and the impact is limited, it's good practice to close clients.

Suggested fix
         val client = HttpClient(CIO)

         val job = launch {
-            client.get("http://localhost:8080/long")
+            client.get("http://localhost:8080/long-process")
         }

         delay(300)
         job.cancelAndJoin() // Simulate client disconnect

+        client.close()
         server.stop()
topics/server-compression.md (1)

110-116: Inconsistent code block indentation.

The code block has inconsistent indentation - install(Compression) has leading whitespace while the inner deflate block doesn't.

Proposed fix
-    install(Compression) {
-    deflate {
-        minimumSize(1024)
+install(Compression) {
+    deflate {
+        minimumSize(1024)
     }
-}
+}
topics/client-auth.md (1)

154-158: Consider varying sentence structure in the list.

Three consecutive list items begin with "When". Consider rephrasing for variety.

Proposed fix
 Clearing cached tokens is typically used in the following scenarios:
 
 - When the user logs out.
-- When credentials or tokens stored by your application change.
-- When you need to force providers to reload the authentication state on the next request.
+- After credentials or tokens stored by your application change.
+- To force providers to reload the authentication state on the next request.
codeSnippets/snippets/openapi-spec-gen/src/test/kotlin/ApplicationTest.kt (1)

10-13: Avoid a no-op test; add a minimal smoke assertion.

testRoot currently has no assertions, so it will always pass. Consider adding a minimal request/assertion against any route defined in this snippet or mark the test as intentionally empty with a TODO/ignore.

codeSnippets/snippets/openapi-spec-gen/src/main/kotlin/com/example/Application.kt (1)

78-78: Thread-safety concern with shared mutable state.

The mutableListOf<User>() is shared across concurrent requests without synchronization. While acceptable for a documentation sample, consider adding a comment noting this is for demonstration purposes only and not suitable for production use.

Suggested comment
         route("/users") {
+                // Note: In-memory list for demonstration only. Not thread-safe.
                 val list = mutableListOf<User>()
codeSnippets/snippets/openapi-spec-gen/build.gradle.kts (1)

1-3: Inconsistent version declaration for kotlin_version.

ktor_version and logback_version are declared using project properties (by project), but kotlin_version is hardcoded to "2.2.20". Consider using a project property for consistency with other version declarations in the repository.

Suggested change
 val ktor_version: String by project
-val kotlin_version = "2.2.20"
+val kotlin_version: String by project
 val logback_version: String by project
topics/whats-new-340.md (1)

271-272: Non-null assertion on nullable return value.

headers.getSplitValues() returns a nullable type, but the code uses !! without demonstrating proper null handling. Consider showing a safer pattern in documentation examples.

Suggested improvement
-val splitValues = headers.getSplitValues("X-Multi-Header")!!
-// ["1", "2", "3"]
+val splitValues = headers.getSplitValues("X-Multi-Header")
+// splitValues: ["1", "2", "3"]

Or demonstrate null handling:

val splitValues = headers.getSplitValues("X-Multi-Header") ?: emptyList()

Comment on lines +1 to +7
import io.ktor.client.*
import io.ktor.client.engine.cio.*

val client = HttpClient(CIO) {
installOrReplace(ContentNegotiation) {
// ...
}
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.

Comment on lines 17 to 21
plugins {
application
kotlin("jvm")
id("io.ktor.plugin") version "3.3.3"
id("io.ktor.plugin") version "3.4.0"
}
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 | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Ktor Gradle plugin io.ktor.plugin 3.4.0 release

💡 Result:

  • Ktor 3.4.0 (framework) release: published 22 January 2026 on the ktorio/ktor GitHub releases page. [2]
  • io.ktor.plugin Gradle plugin 3.4.0: as of now, the Gradle Plugin Portal lists 3.3.3 as the latest version (created 27 November 2025) and does not show a 3.4.0 plugin release. [1]

Sources:
[1] (plugins.gradle.org)
[2] (github.com)

Citations:


Update io.ktor.plugin version from 3.4.0 to 3.3.3.

The io.ktor.plugin 3.4.0 does not exist on the Gradle Plugin Portal. The latest available version is 3.3.3, released 27 November 2025. Using 3.4.0 will cause a build failure.

🤖 Prompt for AI Agents
In `@codeSnippets/snippets/proguard/build.gradle.kts` around lines 17 - 21, The
plugin declaration uses a non-existent version "3.4.0" for io.ktor.plugin;
update the version string in the plugins block (the id("io.ktor.plugin") version
"3.4.0" entry) to the available release "3.3.3" so Gradle can resolve the plugin
and the build will succeed.

Comment on lines +24 to +26
val job = launch {
client.get("http://localhost:8080/long")
}
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 | 🔴 Critical

Wrong endpoint path: test requests /long but route is /long-process.

The test makes a request to "/long" but Application.kt defines the route as "/long-process". This test will receive a 404 response and won't actually test the cancellation behavior.

Proposed fix
         val job = launch {
-            client.get("http://localhost:8080/long")
+            client.get("http://localhost:8080/long-process")
         }
📝 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
val job = launch {
client.get("http://localhost:8080/long")
}
val job = launch {
client.get("http://localhost:8080/long-process")
}
🤖 Prompt for AI Agents
In
`@codeSnippets/snippets/server-http-request-lifecycle/src/test/kotlin/ApplicationTest.kt`
around lines 24 - 26, The test is calling the wrong route: in ApplicationTest.kt
the launched job invokes client.get("http://localhost:8080/long") but the server
route is registered as "/long-process"; update the request URL used in the
coroutine (the client.get call inside the job) to
"http://localhost:8080/long-process" so the test hits the intended LongProcess
route and verifies cancellation behavior.

plugin.

With the `Compression` plugin, you can:
- Use different compression algorithms, including `gzip`, `ztsd` and `deflate`.
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 | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Ktor compression zstd function API documentation

💡 Result:

Ktor’s server Compression plugin does not provide a built-in zstd() DSL/function in its API. In current Ktor API docs, CompressionConfig exposes only gzip(...), deflate(...), and identity(...). [1]

If you want Zstandard (zstd), you need to implement a custom ContentEncoder and plug it into the Compression configuration (the docs explicitly point to implementing ContentEncoder for custom encoders). [2], [3]

Relevant official docs pages:

  • io.ktor.server.plugins.compression package / CompressionConfig functions list (shows gzip/deflate/identity, no zstd) [1]
  • ContentEncoder interface API reference [2]
  • Ktor “Compression” plugin guide (mentions custom encoder via ContentEncoder) [3]

Sources: [1] (api.ktor.io) [2] (api.ktor.io) [3] (ktor.io)

Citations:


🏁 Script executed:

# Check the file content to verify the typos
cat -n topics/server-compression.md | head -100

Repository: ktorio/ktor-documentation

Length of output: 4458


🏁 Script executed:

sed -n '140,160p' topics/server-compression.md

Repository: ktorio/ktor-documentation

Length of output: 598


🏁 Script executed:

# Check if there's a custom ContentEncoder implementation shown anywhere in the file
grep -n "ContentEncoder\|custom.*encoder" topics/server-compression.md | head -20

Repository: ktorio/ktor-documentation

Length of output: 220


🏁 Script executed:

# Let's also check the complete Zstandard section to see all references
sed -n '145,180p' topics/server-compression.md

Repository: ktorio/ktor-documentation

Length of output: 855


🏁 Script executed:

# Check if ktor-server-compression-zstd is a real artifact and what it provides
rg "ktor-server-compression-zstd|ContentEncoder" topics/server-compression.md

Repository: ktorio/ktor-documentation

Length of output: 315


🏁 Script executed:

# Search for more context on ktor-server-compression-zstd and any actual zstd implementation examples
rg -A 10 "ktor-server-compression-zstd" topics/server-compression.md

Repository: ktorio/ktor-documentation

Length of output: 668


🏁 Script executed:

# Let's verify if ktor-server-compression-zstd might be a real artifact that provides the zstd() function
# Check if there are any example files or snippets showing actual zstd usage
find . -name "*.kt" -o -name "*.kts" | xargs grep -l "zstd\|ztsd" 2>/dev/null | head -10

Repository: ktorio/ktor-documentation

Length of output: 51


🏁 Script executed:

# Also check if there's any version info or release notes mentioning when zstd() was added
rg "version|zstd|ztsd" topics/server-compression.md | head -20

Repository: ktorio/ktor-documentation

Length of output: 758


These code examples document non-existent Ktor API functions and will not work.

The Ktor Compression plugin does not provide built-in zstd() or ztsd() functions. The official Ktor API provides only gzip(), deflate(), and identity() encoders. The code examples on lines 23, 64, 78–80, and 156 (both ztsd and zstd spellings) show functions that don't exist.

Per the file's own "Implement custom encoder" section, Zstandard compression requires implementing a custom ContentEncoder. The ktor-server-compression-zstd dependency likely provides utilities or pre-built encoder implementations, but not the zstd() DSL function shown in the examples.

Remove or replace these non-functional examples with actual working code (custom ContentEncoder implementation).

🤖 Prompt for AI Agents
In `@topics/server-compression.md` at line 23, The examples in the
topics/server-compression.md file reference non-existent Ktor DSL functions
(zstd() and ztsd()) for the Compression plugin; replace those examples with
working approaches: either remove the invalid zstd()/ztsd() calls or show how to
wire a custom ContentEncoder implementation into the Compression plugin (follow
the file’s own "Implement custom encoder" pattern), and if relying on
ktor-server-compression-zstd, demonstrate integrating its encoder class instead
of calling zstd()—update every occurrence (lines referenced for ztsd/zstd in
examples) to use the Compression plugin with gzip()/deflate()/identity() or a
documented custom encoder class name (e.g., your ZstdContentEncoder) so the
examples compile and reflect real APIs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants