Skip to content

Conversation

@vnikolova
Copy link
Collaborator

@vnikolova vnikolova commented Feb 10, 2026

Description:

  • split up the existing documentation into separate topics grouped under "Dependency injection"
  • add a new "Configuration" section for DI-related app config
  • add a new sample project server-di and reference code from it where applicable
  • expand the intro and add overview sections

Preview on staging

Related issues:

KTOR-8997 Documentation for DI: Allow file configuration
KTOR-9176 Improve examples and flow in Dependency Injection
KTOR-9240 Document named dependency registration
KTOR-9294 Provide examples for nested dependencies in "Dependency Injection"

@vnikolova vnikolova changed the title KTOR-9176 Improve examples and flow in dependency injection topic KTOR-9176 Improve examples and flow in dependency injection + document configuration options Feb 10, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 10, 2026

Walkthrough

Adds a new server-di code snippet module with Ktor DI sample (sources, build, tests, resources, HTTP examples) and integrates it into codeSnippets/settings.gradle.kts. Reorganizes and expands dependency-injection documentation into a grouped "Dependency injection" TOC with five dedicated topic files and a condensed overview.

Changes

Cohort / File(s) Summary
Module Setup
codeSnippets/settings.gradle.kts, codeSnippets/snippets/server-di/build.gradle.kts, codeSnippets/snippets/server-di/README.md
Included new snippets:server-di module; added Gradle build script and README for the Ktor DI sample.
Core Services & Utilities
codeSnippets/snippets/server-di/src/main/kotlin/com.example/GreetingService.kt, .../Database.kt, .../Repositories.kt, .../Logging.kt, .../PrintStreamProvider.kt, .../OptionalExample.kt
Added service interfaces and implementations, database abstraction, repository, logger binding, printstream provider, and optional config data class; DI bindings/providers declared.
Application & Async DI
codeSnippets/snippets/server-di/src/main/kotlin/com.example/Application.kt, .../AsyncDependencies.kt
Added main entry and Application.module wired with DI parameters and routes (/greet, /db, /optional); introduced async dependency load/provide helpers.
Payments & Routing
codeSnippets/snippets/server-di/src/main/kotlin/com.example/PaymentService.kt
Added PaymentProcessor interface, two providers (CreditCardPaymentProvider, PointsBalancePaymentProvider), DI registration for external provider, and checkout routing with cookie/param validation and redirects.
Configuration & Examples
codeSnippets/snippets/server-di/src/main/resources/application.yaml, codeSnippets/snippets/server-di/requests.http
Added application.yaml wiring dependencies/modules and payments config; added HTTP request examples for checkout scenarios.
Tests
codeSnippets/snippets/server-di/src/test/kotlin/GreetingTest.kt
Added test using testApplication with fake implementations to assert /greet/Test returns expected fake greeting.
Documentation TOC & Overview
ktor.tree, topics/server-dependency-injection.md
Replaced standalone DI entry with grouped TOC "Dependency injection"; condensed overview doc and added example metadata and include references.
DI Topic Guides
topics/server-di-configuration.md, topics/server-di-dependency-registration.md, topics/server-di-dependency-resolution.md, topics/server-di-resource-lifecycle-management.md, topics/server-di-testing.md
Added five new DI documentation files covering configuration options, registration patterns, resolution (including async, named, optional, covariance), lifecycle cleanup, and testing guidance.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • Stexxe
  • osipxd
  • marychatte
🚥 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 clearly summarizes the main changes: improving DI examples/flow and documenting configuration options, with specific issue references.
Description check ✅ Passed The PR description clearly relates to the changeset, detailing the split of DI documentation into separate topics, the new 'Configuration' section, and the new 'server-di' sample project.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch vnikolova/di-updates

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.

@vnikolova vnikolova changed the title KTOR-9176 Improve examples and flow in dependency injection + document configuration options KTOR-9176 KTOR-8997 Improve examples and flow in dependency injection + document configuration options Feb 10, 2026
Copy link

@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: 3

🤖 Fix all issues with AI agents
In `@codeSnippets/snippets/server-di/src/main/kotlin/com.example/Logging.kt`:
- Line 7: There is an extra leading space before the class declaration; remove
the leading space so the declaration "class Logger(private val out: PrintStream)
{" aligns with the file's top-level indentation and other type declarations
(i.e., adjust the "class Logger" line to start at column 1 with no leading
spaces).

In `@codeSnippets/snippets/server-di/src/main/resources/application.yaml`:
- Around line 13-14: The sample database connectionUrl uses a non-standard
PostgreSQL port (postgres://localhost:3037/admin); either change the port to the
standard 5432 in the database.connectionUrl value or add a YAML comment next to
database.connectionUrl explaining that 3037 is intentionally non-standard for
demo purposes so readers aren't confused when copying the config.

In `@topics/server-di-configuration.md`:
- Line 64: Add a trailing period to the sentence "It will not resolve as
`Collection?`, because that combination is not included in the expression" so it
ends with a period; update the text in topics/server-di-configuration.md (the
sentence containing `Collection?` in that paragraph) to be punctuated
consistently.
🧹 Nitpick comments (6)
codeSnippets/snippets/server-di/build.gradle.kts (1)

1-3: kotlin_version is declared but unused.

The kotlin_version property is read from the project but never referenced in this build script. Consider removing it to avoid confusion.

Proposed fix
 val ktor_version: String by project
-val kotlin_version: String by project
 val logback_version: String by project
topics/server-di-resource-lifecycle-management.md (2)

39-46: Undeclared types Closer and CustomCloser in the snippet may confuse readers.

Unlike the other snippets which use recognizable names (DatabaseConnection, ResourceManager), Closer and CustomCloser appear without context. Consider using more descriptive names (e.g., ResourceHandler / CustomResourceHandler) or adding a brief comment indicating what they represent.


11-21: Indentation uses 2 spaces instead of the Kotlin convention of 4 spaces.

The inline Kotlin snippets use 2-space indentation. Kotlin's official coding conventions recommend 4 spaces. This applies to the other snippets in this file as well.

topics/server-di-dependency-registration.md (1)

84-92: Tabs block only contains a YAML tab — consider adding HOCON.

The <tabs> element has only an application.yaml tab. If Ktor's file-based DI configuration also supports application.conf (HOCON), adding that tab would be consistent with other Ktor documentation pages that show both formats side by side.

topics/server-di-testing.md (1)

9-17: Consider referencing the actual sample project test instead of (or in addition to) inline pseudo-code.

The PR includes a concrete test in GreetingTest.kt with FakeGreetingService, FakeUserRepository, etc. Referencing it here (using {src=...}) would give readers a working, runnable example rather than generic MyService/MockService pseudo-code, and would keep the documentation consistent with the approach used in the registration topic.

topics/server-di-configuration.md (1)

79-93: IgnoreConflicts description only mentions test behavior, not the general policy.

The descriptions for Default and OverridePrevious explain what the policy does, but IgnoreConflicts only explains its default usage in tests. Consider adding a brief description of the general behavior (e.g., "Keeps the first registered dependency and silently ignores subsequent conflicting registrations") before mentioning the test-environment default.

Comment on lines +13 to +16
database:
connectionUrl: postgres://localhost:3037/admin
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Non-standard PostgreSQL port in sample configuration.

Port 3037 is unusual for PostgreSQL (default is 5432). If this is intentional for demonstration purposes, consider adding a YAML comment to avoid confusing readers who may copy this config.

🤖 Prompt for AI Agents
In `@codeSnippets/snippets/server-di/src/main/resources/application.yaml` around
lines 13 - 14, The sample database connectionUrl uses a non-standard PostgreSQL
port (postgres://localhost:3037/admin); either change the port to the standard
5432 in the database.connectionUrl value or add a YAML comment next to
database.connectionUrl explaining that 3037 is intentionally non-standard for
demo purposes so readers aren't confused when copying the config.

Copy link

@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: 2

🤖 Fix all issues with AI agents
In
`@codeSnippets/snippets/server-di/src/main/kotlin/com.example/PaymentService.kt`:
- Around line 58-60: The route path in the GET handler is misspelled as
"/paymment/{amount}"; update the route string used in the get(...) call inside
PaymentService (the GET handler that calls call.respondText with
call.parameters["amount"]) to "/payment/{amount}" and verify any tests or
callers referencing "/paymment" are updated to the corrected "/payment" path.

In `@topics/server-di-dependency-resolution.md`:
- Around line 66-69: The included snippet uses incorrect include-lines for
src/main/resources/application.yaml so the example shows payment modules instead
of the database config; update the include-lines from "1,4-6,13-14" to the lines
that contain the database section (the lines with the database.connectionUrl and
database keys, e.g., change to include the lines covering the database block
such as 15-16) so the YAML excerpt demonstrates database.connectionUrl
resolution correctly.
🧹 Nitpick comments (2)
codeSnippets/snippets/server-di/src/main/resources/application.yaml (1)

23-25: Sample secret in configuration is fine for demo, but consider adding a comment.

The clientKey value "super-secret-client-key" is clearly a placeholder, which is appropriate for a sample project. A brief YAML comment (e.g., # Replace with an environment variable in production) could reinforce best practices for readers who copy-paste this config.

codeSnippets/snippets/server-di/src/main/kotlin/com.example/PaymentService.kt (1)

28-31: User-supplied values in redirect URL are not URL-encoded.

userId, cartId, and amount are interpolated directly into the redirect URL. While this is a sample project, it could mislead readers. Consider using URLBuilder or encodeURLParameter() for the query parameters to demonstrate best practices.

Comment on lines +58 to +60
get("/paymment/{amount}") {
call.respondText("Payment for ${call.parameters["amount"]} is pending...")
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Typo in route path: /paymment/payment.

Double 'm' in the route path.

Proposed fix
-        get("/paymment/{amount}") {
+        get("/payment/{amount}") {
📝 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
get("/paymment/{amount}") {
call.respondText("Payment for ${call.parameters["amount"]} is pending...")
}
get("/payment/{amount}") {
call.respondText("Payment for ${call.parameters["amount"]} is pending...")
}
🤖 Prompt for AI Agents
In
`@codeSnippets/snippets/server-di/src/main/kotlin/com.example/PaymentService.kt`
around lines 58 - 60, The route path in the GET handler is misspelled as
"/paymment/{amount}"; update the route string used in the get(...) call inside
PaymentService (the GET handler that calls call.respondText with
call.parameters["amount"]) to "/payment/{amount}" and verify any tests or
callers referencing "/paymment" are updated to the corrected "/payment" path.

Comment on lines +66 to +69
```yaml
```
{src="snippets/server-di/src/main/resources/application.yaml" include-lines="1,4-6,13-14"}

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Incorrect include-lines — shows payment modules instead of database configuration.

The surrounding text explains that database.connectionUrl is resolved from the configuration, but include-lines="1,4-6,13-14" pulls in the payment-related module entries (lines 13–14 of application.yaml). You likely want lines 15–16 to show the database section:

Proposed fix
-{src="snippets/server-di/src/main/resources/application.yaml" include-lines="1,4-6,13-14"}
+{src="snippets/server-di/src/main/resources/application.yaml" include-lines="1,4-6,15-16"}
📝 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
```yaml
```
{src="snippets/server-di/src/main/resources/application.yaml" include-lines="1,4-6,13-14"}
🤖 Prompt for AI Agents
In `@topics/server-di-dependency-resolution.md` around lines 66 - 69, The included
snippet uses incorrect include-lines for src/main/resources/application.yaml so
the example shows payment modules instead of the database config; update the
include-lines from "1,4-6,13-14" to the lines that contain the database section
(the lines with the database.connectionUrl and database keys, e.g., change to
include the lines covering the database block such as 15-16) so the YAML excerpt
demonstrates database.connectionUrl resolution correctly.

@vnikolova vnikolova force-pushed the vnikolova/di-updates branch from d9b7ca0 to 6fece44 Compare February 10, 2026 16:55
@vnikolova vnikolova requested a review from bjhham February 10, 2026 16:55
Copy link

@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: 3

🤖 Fix all issues with AI agents
In `@codeSnippets/snippets/server-di/requests.http`:
- Around line 1-6: The `@host` variable is defined but unused and the cartId
values are inconsistent; update the HTTP requests to use the host variable
(replace hardcoded "http://localhost:8080" with "{{host}}" in each request URL)
or delete the `@host` line if you prefer hardcoding, and make all Cookie headers
use a consistent cartId format (e.g., change "cart123" to "cart-123" in the
successful checkout request) so the Cookie header and all request URLs (the POST
/checkout requests) are consistent.

In `@topics/server-di-configuration.md`:
- Around line 88-91: The sentence for the <code>Default</code> policy title is
missing a trailing period; update the description text for the
<code>Default</code> entry to add a period at the end so it matches the
punctuation style of the <code>OverridePrevious</code> entry and other entries.

In `@topics/server-di-testing.md`:
- Around line 17-26: Clarify that loadServices() is a placeholder for the app's
module/bootstrap function by updating the example to call or comment that it
should call your real module initialization (e.g., the function that registers
routes/services) instead of a Ktor API; reference loadServices(),
testApplication, application, dependencies.provide<MyService>, and MockService
so readers know to replace loadServices() with their actual application module
bootstrap or leave a short inline comment explaining that loadServices()
represents the project's module-loading/DI registration step.
🧹 Nitpick comments (6)
codeSnippets/snippets/server-di/src/main/kotlin/com.example/AsyncDependencies.kt (1)

10-13: Consider noting the provide-before-resolve ordering requirement.

installEvents() calls resolve() which will fail if loadEventsConnection() (the provide call) hasn't been invoked first. Since this is a documentation snippet, ensure the accompanying topic text or the calling code makes the required ordering clear to readers. If it's already addressed in the docs, feel free to disregard.

topics/server-di-configuration.md (1)

96-100: IgnoreConflicts description reads more like a usage note than a definition.

The other two policy entries (Default, OverridePrevious) describe what the policy does. The IgnoreConflicts entry instead describes where it's used by default. Consider leading with the behavior (e.g., "Silently keeps the first registration and ignores subsequent conflicting ones.") and then adding the note about test-engine defaults as supplementary detail.

topics/server-di-testing.md (1)

13-41: Consider referencing the sample project's test for a more complete example.

The testing page is quite minimal. The PR adds GreetingTest.kt in the server-di sample project which demonstrates a full test flow with fakes and endpoint assertions. Referencing or including that snippet would give readers a concrete, runnable example alongside the conceptual snippets here.

codeSnippets/snippets/server-di/build.gradle.kts (1)

19-29: Inconsistent string interpolation style.

Some dependency declarations use bare $ktor_version (e.g., lines 20–22) while others use ${ktor_version} (lines 23, 26). Both are functionally identical, but picking one style improves readability.

codeSnippets/snippets/server-di/src/test/kotlin/GreetingTest.kt (1)

23-29: Consider making the fake greeting include the name parameter for a more realistic example.

Since this is a documentation sample, it could be more instructive if FakeGreetingService.greet used the name parameter (e.g., "Fake greeting, $name"), and the assertion verified "Fake greeting, Test". This would better demonstrate that the route correctly passes path parameters through to the service.

codeSnippets/snippets/server-di/src/main/kotlin/com.example/PaymentService.kt (1)

10-12: Consider separating ApplicationCall from the PaymentProcessor interface.

Passing ApplicationCall into a domain-level interface couples payment processing to Ktor's HTTP layer. For a documentation sample that aims to showcase DI best practices, having the processor return a result object and letting the route handler translate it to an HTTP response would better demonstrate the decoupling benefits of DI.

That said, this is a sample project and the current approach keeps things concise, so this is a minor point.

Comment on lines +1 to +6
@host = http://localhost:8080

### Successful checkout using cookies and amount
POST http://localhost:8080/checkout?amount=1500
Content-Type: application/x-www-form-urlencoded
Cookie: userId=alice; cartId=cart123
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

@host variable defined but never used; cartId value inconsistent across requests.

The @host variable on line 1 is never referenced — all requests hardcode http://localhost:8080. Either use {{host}}/checkout... in the request URLs or remove the variable.

Also, the successful checkout (line 6) uses cartId=cart123 while the other two scenarios (lines 13, 20) use cartId=cart-123. Consider making the format consistent to avoid confusing readers of the sample.

Proposed fix
-@host = http://localhost:8080
-
 ### Successful checkout using cookies and amount
-POST http://localhost:8080/checkout?amount=1500
+POST {{host}}/checkout?amount=1500
 Content-Type: application/x-www-form-urlencoded
-Cookie: userId=alice; cartId=cart123
+Cookie: userId=alice; cartId=cart-123
 
 ###
 
 ### Missing userId cookie
-POST http://localhost:8080/checkout?amount=1500
+POST {{host}}/checkout?amount=1500
 Content-Type: application/x-www-form-urlencoded
 Cookie: cartId=cart-123
 
 ###
 
 ### Missing amount query parameter
-POST http://localhost:8080/checkout
+POST {{host}}/checkout
 Content-Type: application/x-www-form-urlencoded
 Cookie: userId=alice; cartId=cart-123
🤖 Prompt for AI Agents
In `@codeSnippets/snippets/server-di/requests.http` around lines 1 - 6, The `@host`
variable is defined but unused and the cartId values are inconsistent; update
the HTTP requests to use the host variable (replace hardcoded
"http://localhost:8080" with "{{host}}" in each request URL) or delete the `@host`
line if you prefer hardcoding, and make all Cookie headers use a consistent
cartId format (e.g., change "cart123" to "cart-123" in the successful checkout
request) so the Cookie header and all request URLs (the POST /checkout requests)
are consistent.

Comment on lines +88 to +91
<def>
<title><code>Default</code></title>
Throws an exception when a conflicting dependency is declared
</def>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Missing trailing period for consistency.

The Default policy description on line 90 is missing a period, unlike the OverridePrevious entry on line 94.

Proposed fix
 <def>
 <title><code>Default</code></title>
-Throws an exception when a conflicting dependency is declared
+Throws an exception when a conflicting dependency is declared.
 </def>
📝 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
<def>
<title><code>Default</code></title>
Throws an exception when a conflicting dependency is declared
</def>
<def>
<title><code>Default</code></title>
Throws an exception when a conflicting dependency is declared.
</def>
🤖 Prompt for AI Agents
In `@topics/server-di-configuration.md` around lines 88 - 91, The sentence for the
<code>Default</code> policy title is missing a trailing period; update the
description text for the <code>Default</code> entry to add a period at the end
so it matches the punctuation style of the <code>OverridePrevious</code> entry
and other entries.

Comment on lines +17 to +26
```kotlin
fun test() = testApplication {
application {
dependencies.provide<MyService> {
MockService()
}
loadServices()
}
}
```
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Clarify what loadServices() represents.

loadServices() on line 23 isn't a standard Ktor function and isn't explained. Readers won't know whether this is a placeholder for their own module-loading logic or a real API. Consider replacing it with a more recognizable pattern (e.g., calling an actual application module function) or adding a brief comment/sentence explaining its purpose.

🤖 Prompt for AI Agents
In `@topics/server-di-testing.md` around lines 17 - 26, Clarify that
loadServices() is a placeholder for the app's module/bootstrap function by
updating the example to call or comment that it should call your real module
initialization (e.g., the function that registers routes/services) instead of a
Ktor API; reference loadServices(), testApplication, application,
dependencies.provide<MyService>, and MockService so readers know to replace
loadServices() with their actual application module bootstrap or leave a short
inline comment explaining that loadServices() represents the project's
module-loading/DI registration step.

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.

1 participant