Conversation
* add multiple header parsing to "what's new" * add multiple header parsing to client-responses.md
fix: KTOR-8880
* 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>
WalkthroughThis 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
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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. Comment |
* KTOR-9175 Add api key auth documentation --------- Co-authored-by: Vik Nikolova <contact@viknikolova.com>
AlejandraPedroza
left a comment
There was a problem hiding this comment.
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.
codeSnippets/snippets/server-http-request-lifecycle/src/main/kotlin/com/example/Application.kt
Outdated
Show resolved
Hide resolved
codeSnippets/snippets/server-http-request-lifecycle/src/main/kotlin/com/example/Application.kt
Outdated
Show resolved
Hide resolved
codeSnippets/snippets/server-http-request-lifecycle/src/test/kotlin/ApplicationTest.kt
Outdated
Show resolved
Hide resolved
AlejandraPedroza
left a comment
There was a problem hiding this comment.
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.
…#742) * add a what's new entry for dispatcher config for native client engines * fix broken API link and add a new one for engine configs
AlejandraPedroza
left a comment
There was a problem hiding this comment.
Thanks for the changes. LGTM 🚀
* 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
There was a problem hiding this comment.
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
GETshould generally return200 OK;201 Createdimplies resource creation and is typically used forPOST. Keeping200avoids 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.messagecan 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.0is 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 lowercaseyyyyfor calendar year in date pattern.The pattern
YYYYrepresents "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 lowercaseyyyyfor 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 lowercaseyyyyfor calendar year in date pattern.Same issue as the other logback.xml —
YYYYis "week year" which can produce unexpected results near year boundaries. Useyyyyfor 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.,isActivebecomesfalse). At that point, aCancellationExceptionis thrown at thedelay()suspension point, which jumps directly to thecatchblock. Thecall.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, andkotlinx-coroutines-testwithout versions while line 25 and earlier dependencies use explicit version variables. This inconsistency may cause unpredictable transitive dependency resolution. Use$ktor_versionfor 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'skotlin_versionproperty is2.3.0(fromcodeSnippets/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 fromcall.responseproperty reference.
ApplicationCall.responseis a Kotlin property (not a function), defined asabstract val response: ApplicationResponse. The parentheses incall.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-jvmsuffix toktor-client-content-negotiationfor consistency.Artifact
io.ktor:ktor-client-content-negotiation-jvm:3.4.0is published and available on Maven Central with JVM variant support. However, line 26 omits the-jvmsuffix 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 returnnullsince 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/userssegment.The route at line 104 uses
get("/users")but it's already nested insideroute("/users")(line 77), resulting in the path/api/users/usersinstead 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
kotlinbut contains HOCON configuration syntax (application.conf). This will cause incorrect syntax highlighting.Proposed fix
Change the language identifier from
kotlinto an appropriate format. Since HOCON isn't universally supported, consider using a generic identifier:-```kotlin +``` // application.conf ktor {Or remove the
// application.confcomment and keepkotlinif 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
ignoremarker, but the code example on line 137 shows// ignore!(with exclamation mark). Clarify whether the marker should beignoreorignore!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! +// ignorecodeSnippets/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 closesuserCrud()but there should be an additional brace to close the outerroute("/api")block.Proposed fix
} + } }topics/openapi-spec-generation.md-311-313 (1)
311-313: ChangeRoutingSourcetoRouting.Line 311 uses
OpenApiDocSource.RoutingSource, but all other documentation and code examples useOpenApiDocSource.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_versionis now hardcoded whilektor_version,logback_version, andswagger_codegen_versionstill useby projectdelegation. 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 thekotlin_versionvariable 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 thekotlinx-datetimedependency.The code example uses
Clock.System.now()which requires thekotlinx-datetimelibrary. 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
HttpClientinstance 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 innerdeflateblock 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.
testRootcurrently 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 forkotlin_version.
ktor_versionandlogback_versionare declared using project properties (by project), butkotlin_versionis 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 projecttopics/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()
| import io.ktor.client.* | ||
| import io.ktor.client.engine.cio.* | ||
|
|
||
| val client = HttpClient(CIO) { | ||
| installOrReplace(ContentNegotiation) { | ||
| // ... | ||
| } |
There was a problem hiding this comment.
🧩 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.
| 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.
| plugins { | ||
| application | ||
| kotlin("jvm") | ||
| id("io.ktor.plugin") version "3.3.3" | ||
| id("io.ktor.plugin") version "3.4.0" | ||
| } |
There was a problem hiding this comment.
🧩 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/ktorGitHub releases page. [2] io.ktor.pluginGradle 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:
- 1: https://plugins.gradle.org/plugin/io.ktor.plugin?utm_source=openai
- 2: https://github.com/ktorio/ktor/releases
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.
| val job = launch { | ||
| client.get("http://localhost:8080/long") | ||
| } |
There was a problem hiding this comment.
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.
| 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`. |
There was a problem hiding this comment.
🧩 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.compressionpackage /CompressionConfigfunctions list (showsgzip/deflate/identity, nozstd) [1]ContentEncoderinterface 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:
- 1: https://api.ktor.io/ktor-server-compression/io.ktor.server.plugins.compression/index.html
- 2: https://api.ktor.io/3.1.x/ktor-utils/io.ktor.util/-content-encoder/index.html?utm_source=openai
- 3: https://ktor.io/docs/server-compression.html
🏁 Script executed:
# Check the file content to verify the typos
cat -n topics/server-compression.md | head -100Repository: ktorio/ktor-documentation
Length of output: 4458
🏁 Script executed:
sed -n '140,160p' topics/server-compression.mdRepository: 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 -20Repository: 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.mdRepository: 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.mdRepository: 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.mdRepository: 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 -10Repository: 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 -20Repository: 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.
New topics:
whats-new-340.md)server-http-request-lifecycle.md)server-api-key-auth.md)New sections:
client-auth.md)client-responses.md)server-compression.md)server-html-dsl.md)client-plugins,client-default-request)server-responses.md)Improved formatting, grammar and language:
server-responses.md)server-basic-auth.md,server-bearer-auth)New code samples:
server-http-lifecycle