Skip to content

Conversation

@nielsenko
Copy link
Collaborator

@nielsenko nielsenko commented Nov 17, 2025

Description

This PR refactors the Request class by removing the old url (the name has been repurposed) and handlerPath properties and their associated complexity. The url property was a relative path used for routing, while handlerPath represented the path to the current handler. Both have been removed in favor of using requestedUri (which is now called url) and matchedPath / remainingPath extension methods (ContextProperty convenience getters) directly throughout the codebase.

Key changes:

  • Removed url and handlerPath properties from the Request class, including complex validation logic for url and handlerPath relationships.
  • Updated all usage sites to use requestedUri instead of url.
  • Renamed requestedUri to url.
  • Simplified Request constructor and copyWith method
  • Removed path parameter from copyWith method
  • Renamed context.dart to result.dart
  • Removed encoding and context parameters from Response constructors
  • Updated StaticHandler to implement injectIn method
  • Simplified logging middleware

Related Issues

None referenced.

Pre-Launch Checklist

  • This update focuses on a single feature or bug fix. (For multiple fixes, please submit separate PRs.)
  • I have read and followed the Dart Style Guide and formatted the code using dart format.
  • I have referenced at least one issue this PR fixes or is related to.
  • I have updated/added relevant documentation (doc comments with ///), ensuring consistency with existing project documentation.
  • I have added new tests to verify the changes.
  • All existing and new tests pass successfully.
  • I have documented any breaking changes below.

Breaking Changes

  • Includes breaking changes.
  • No breaking changes.

Breaking changes:

  1. Request.url repurposed to be old Request.requestedUri instead
  2. Request.handlerPath removed - use routing middleware's matchedPath property
  3. Request.copyWith(path: ...) removed.
  4. Response constructors no longer accept encoding or context parameters.
  5. File renamed: lib/src/context/context.dartlib/src/context/result.dart (affects direct imports)

Additional Notes

This should barely impact Serverpod, but it is a significant API refactoring. Users should migrate by:

  • Replacing accommodating changed semantics ofrequest.url. Use request.url.pathAndQuery if root relative uri is required.
  • Using request.matchedPath from routing middleware where needed.
  • Removing any path arguments from request.copyWith() calls
  • Move encoding to Body.
  • Use ContextProperty instead of context map.

Summary by CodeRabbit

  • Documentation

    • Updated routing guidance, examples and middleware notes to show built-in Router usage and clarified URL/middleware rewriting semantics.
  • New Features

    • Static file handlers now support automatic router registration for GET/HEAD mounting.
  • Bug Fixes / Improvements

    • Consolidated Request URL surface to a single url property and standardized matched-path usage in examples/logging.
    • Simplified Response constructors and helpers to use a uniform Body/Headers model (removed separate encoding/context parameters).

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 17, 2025

Important

Review skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

Consolidates request/response surface to use a single Request.url and Body-centric Response, removes legacy requestedUri/handlerPath/context/encoding, updates imports to result.dart, wires StaticHandler into the router via injectIn, and updates docs/examples/tests to use Router/matchedPath semantics.

Changes

Cohort / File(s) Summary
Documentation
README.md, doc/site/docs/02-reference/04-requests.md, doc/site/docs/02-reference/07-middleware.md
Replace manual routing guidance with Router/routeWith usage; clarify Request.url is the complete original URI; update middleware warning to reference request.url.
Request API Core Refactor
lib/src/context/request.dart
Replace requestedUri/handlerPath with single public url field; simplify constructor and copyWith; add UriEx.pathAndQuery; update validation to operate on url.
Response API Core Refactor
lib/src/context/response.dart
Remove encoding/context params from constructor and convenience builders; unify API around Body and Headers; simplify redirect helper and copyWith.
Context Module Restructuring
lib/relic.dart, lib/src/context/message.dart, lib/src/adapter/adapter.dart, lib/src/adapter/io/request.dart, lib/src/adapter/io/response.dart
Switch exports/imports/part directives from context.dart to result.dart.
Handler/Middleware Imports & Minor Logic
lib/src/handler/cascade.dart, lib/src/handler/handler.dart, lib/src/middleware/context_property.dart, lib/src/middleware/middleware_logger.dart, lib/src/middleware/routing_middleware.dart
Update imports to result.dart; refactor logRequests to block form and rename local vars to use url; add doc-note that matchedPath replaces handlerPath.
Server Logging Update
lib/src/relic_server.dart
Update import and switch _logError to use request.url.path / request.url.query.
Static Handler Routing Integration
lib/src/io/static/static_handler.dart
Add injectIn(RelicRouter) method to register static handler with router.anyOf for GET/HEAD, enabling automatic router wiring.
Examples Updated
example/advanced/multi_isolate.dart, example/context/context_example.dart, example/routing/request_example.dart, example/routing/request_response_example.dart
Replace uses of requestedUri/manual path extraction with req.url and req.matchedPath; minor param rename in multi_isolate.
Tests — Imports & Assertions
multiple tests under test/ (e.g., test/*, test/static/*, test/message/*, test/src/*)
Update imports from context.dart to result.dart; adjust tests to use url/pathAndQuery/matchedPath; remove many handlerPath-specific tests; adapt static handler tests to use router-mounted static handlers and simplified makeRequest (no handlerPath).
Test Utilities
test/static/test_util.dart, test/util/test_util.dart
Remove _rootHandler wrapper; makeRequest no longer accepts handlerPath; default test handler messages now reference req.url.path.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Client
    participant Router as RelicRouter
    participant StaticHandler
    participant Response

    Client->>Router: GET /static/logo.png
    Note right of Router: route registered via StaticHandler.injectIn
    Router->>StaticHandler: invoke call()
    StaticHandler->>StaticHandler: locate file, build Body
    StaticHandler->>Response: create 200 Response(body, headers)
    Response-->>Client: 200 OK + content
Loading
sequenceDiagram
    autonumber
    participant OldFlow as Old Flow
    participant NewFlow as New Flow

    OldFlow->>OldFlow: Request.requestedUri + handlerPath
    OldFlow->>OldFlow: manual path manipulation / copyWith(path)
    OldFlow->>OldFlow: per-handler routing metadata

    NewFlow->>NewFlow: Request.url (single URI)
    NewFlow->>NewFlow: copyWith(url)
    NewFlow->>NewFlow: Router.anyOf / routeWith registers handlers
    NewFlow->>NewFlow: middleware sets req.matchedPath
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Areas needing extra attention:
    • Request/Response API changes (constructors, validators, convenience builders).
    • StaticHandler.injectIn routing integration and related tests.
    • Large-scale import/part directive shifts from context.dartresult.dart.
    • Test deletions/adjustments around handlerPath — ensure no regression in routing semantics.

Possibly related PRs

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main refactoring: removing deprecated request/response class arguments. It directly reflects the primary change across the codebase.
Description check ✅ Passed The PR description is comprehensive, covering all major changes, breaking changes, migration guidance, and pre-launch checklist items. One non-critical item (referencing an issue) is unchecked but does not prevent passing.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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.

@codecov
Copy link

codecov bot commented Nov 17, 2025

Codecov Report

❌ Patch coverage is 83.78378% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.94%. Comparing base (77144a3) to head (47a0fd1).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
lib/src/context/response.dart 80.95% 8 Missing ⚠️
lib/src/context/request.dart 80.00% 2 Missing ⚠️
lib/src/middleware/middleware_logger.dart 87.50% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #274      +/-   ##
==========================================
+ Coverage   91.84%   91.94%   +0.09%     
==========================================
  Files          93       93              
  Lines        3667     3611      -56     
  Branches     1863     1846      -17     
==========================================
- Hits         3368     3320      -48     
+ Misses        299      291       -8     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@nielsenko nielsenko self-assigned this Nov 17, 2025
@nielsenko
Copy link
Collaborator Author

@coderabbitai review

@nielsenko nielsenko force-pushed the response-simplify branch 2 times, most recently from a9d629a to e2d4c0c Compare November 19, 2025 14:08
@nielsenko
Copy link
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 19, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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: 0

Caution

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

⚠️ Outside diff range comments (5)
test/static/alternative_root_test.dart (2)

35-49: Fix test description: File is in subdirectory, not root.

The test description claims to test "a root file with space" but the file is actually located in the files/ subdirectory (/files/with%20space.txt). The description should accurately reflect this.

Apply this diff to fix the description:

   test(
-    'Given a root file with space when accessed then it returns the file content',
+    'Given a file with space in subdirectory when accessed then it returns the file content',
     () async {

51-65: Fix path to match test description or remove duplicate test.

This test has two issues:

  1. The description claims to test "unencoded space" but the path uses URL-encoded %20 (identical to line 44).
  2. The description says "root file" but the file is in the files/ subdirectory.

If the intent is to test unencoded space handling, the path should use an unencoded space character: '/files/with space.txt'. Otherwise, this test is a duplicate of the previous one (lines 35-49) and should be removed.

Apply this diff if testing unencoded space is the intent:

   test(
-    'Given a root file with unencoded space when accessed then it returns the file content',
+    'Given a file with unencoded space in subdirectory when accessed then it returns the file content',
     () async {
       final handler =
           StaticHandler.directory(
             Directory(d.sandbox),
             cacheControl: (_, _) => null,
           ).asHandler;
 
-      final response = await makeRequest(handler, '/files/with%20space.txt');
+      final response = await makeRequest(handler, '/files/with space.txt');
       expect(response.statusCode, HttpStatus.ok);
doc/site/docs/02-reference/04-requests.md (1)

27-46: Align url description with new semantics.

Line 27 now says url is the complete original URI, but the “Request url and path” section below still describes it as a handler-relative path+query. That’s the old behavior; please update this section to clarify that Request.url is the full requested URI and point users to url.pathAndQuery (or routing middleware properties) when they want a root‑relative path+query.

lib/src/context/response.dart (2)

163-176: Response.notModified no longer enforces content-length stripping as documented.

The doc comment still says that any content-length in headers will be removed, but the constructor now forwards headers ?? Headers.empty() unchanged into Response. That can produce 304 responses with a Content-Length header, which is against HTTP expectations and contradicts the docs. Consider wrapping the headers in a .transform that explicitly clears contentLength or omits the header when building a 304.


268-277: Update copyWith documentation to match the new signature.

copyWith now accepts a Body? and Headers?, but the doc block above still refers to String, List<int>, and Stream<List<int>> bodies. Please update the comment to describe passing a Body (created via Body.fromString, Body.fromBytes, etc.) so it matches the actual API and avoids confusion.

🧹 Nitpick comments (5)
example/routing/request_example.dart (1)

25-29: LGTM! API usage is correct.

The code correctly uses req.matchedPath for the matched route path and req.url for the full URI, properly implementing the refactored Request API.

For consistency with request_response_example.dart (line 29), consider using "Matched path" instead of "Relative URL" in the log message, as it more precisely describes what matchedPath represents.

-    log('Relative URL: $matchedPath, id: $id');
+    log('Matched path: $matchedPath, id: $id');
test/static/cache_busting_static_handler_test.dart (1)

15-379: Router-based StaticHandler wiring looks correct; consider deduplicating setup

Migrating from pipeline-based handlers to:

handler = (RelicRouter()
      ..injectAt('/static', StaticHandler.directory(...)))
    .asHandler;

(and variants such as '/static/', multiple injectAt calls, and differing mountPrefix/fileSystemRoot) keeps each test’s intent intact:

  • Requests now use full paths like /static/logo.png and /static/logo@abc.png, which aligns with the removal of handlerPath.
  • The scenarios for root-mounted vs router-mounted handlers, alternate mount points (/other, /cache), custom separators, and nested directories with separators are all still exercised via makeRequest.
  • Using the same StaticHandler instance injected at multiple prefixes in the later groups also accurately captures the “handler-level cache busting” behavior under different mount configurations.

Given how many groups repeat essentially the same RelicRouter()..injectAt('/static'|'/static/', StaticHandler.directory(...)) setup and nearly identical CacheBustingConfig construction, you might want to factor out a small helper (e.g., Handler buildStaticHandler(String mount, Directory root, {CacheBustingConfig config})) to reduce duplication and make future tweaks to router injection or cache-busting config less error-prone. This is purely an ergonomics/maintenance improvement; the current tests are clear and functionally sound.

test/static/test_util.dart (1)

4-19: Consider clarifying naming in makeRequest.

req on Line 16 actually holds the handler’s result (usually a Response), while request is the Request. Consider renaming req to result or response to avoid confusion between the inbound request and the handler’s result.

test/message/request_test.dart (1)

6-87: Tests correctly target url.pathAndQuery, but description is slightly stale.

The assertions using request.url.pathAndQuery for various URIs look correct for the new API. The description “when no url is provided…” (Line 47) still reflects the old optional-url constructor; consider rephrasing to something like “when an absolute URL is provided, url.pathAndQuery exposes the relativized path and query” for clarity.

test/src/adapter/context_test.dart (1)

2-93: Tests correctly exercise copyWith(url: ...) and token preservation.

Updating these tests to use url in copyWith and in assertions is consistent with the new Request API, and they still verify that the token survives multiple transformations. The group descriptions still mention “withRequest”, which is slightly outdated but non‑blocking—consider renaming in a follow‑up for clarity.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 77144a3 and e2d4c0c.

📒 Files selected for processing (35)
  • README.md (1 hunks)
  • doc/site/docs/02-reference/04-requests.md (1 hunks)
  • doc/site/docs/02-reference/07-middleware.md (1 hunks)
  • example/advanced/multi_isolate.dart (1 hunks)
  • example/context/context_example.dart (1 hunks)
  • example/routing/request_example.dart (1 hunks)
  • example/routing/request_response_example.dart (1 hunks)
  • lib/relic.dart (1 hunks)
  • lib/src/adapter/adapter.dart (1 hunks)
  • lib/src/adapter/io/request.dart (1 hunks)
  • lib/src/adapter/io/response.dart (1 hunks)
  • lib/src/context/message.dart (1 hunks)
  • lib/src/context/request.dart (4 hunks)
  • lib/src/context/response.dart (7 hunks)
  • lib/src/handler/cascade.dart (1 hunks)
  • lib/src/handler/handler.dart (1 hunks)
  • lib/src/io/static/static_handler.dart (1 hunks)
  • lib/src/middleware/context_property.dart (1 hunks)
  • lib/src/middleware/middleware_logger.dart (2 hunks)
  • lib/src/middleware/routing_middleware.dart (1 hunks)
  • lib/src/relic_server.dart (2 hunks)
  • test/handler/cascade_test.dart (1 hunks)
  • test/message/request_test.dart (6 hunks)
  • test/message/response_test.dart (1 hunks)
  • test/middleware/middleware_object_test.dart (1 hunks)
  • test/middleware/routing_middleware_test.dart (1 hunks)
  • test/relic_server_serve_test.dart (1 hunks)
  • test/router/router_handler_test.dart (1 hunks)
  • test/router/router_inject_test.dart (1 hunks)
  • test/src/adapter/context_test.dart (3 hunks)
  • test/src/middleware/context_property_test.dart (1 hunks)
  • test/static/alternative_root_test.dart (5 hunks)
  • test/static/cache_busting_static_handler_test.dart (14 hunks)
  • test/static/test_util.dart (1 hunks)
  • test/util/test_util.dart (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.dart

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.dart: All Dart code must pass static analysis using dart analyze --fatal-infos with no issues
All Dart files must be formatted with dart format (CI enforces dart format --set-exit-if-changed .)

Files:

  • test/router/router_inject_test.dart
  • lib/src/adapter/io/request.dart
  • test/src/middleware/context_property_test.dart
  • lib/src/adapter/io/response.dart
  • test/static/alternative_root_test.dart
  • lib/src/adapter/adapter.dart
  • lib/src/io/static/static_handler.dart
  • test/middleware/routing_middleware_test.dart
  • lib/src/middleware/routing_middleware.dart
  • lib/src/relic_server.dart
  • test/router/router_handler_test.dart
  • lib/src/middleware/context_property.dart
  • test/middleware/middleware_object_test.dart
  • example/routing/request_example.dart
  • test/src/adapter/context_test.dart
  • example/context/context_example.dart
  • lib/src/handler/handler.dart
  • lib/relic.dart
  • test/util/test_util.dart
  • test/handler/cascade_test.dart
  • example/routing/request_response_example.dart
  • lib/src/context/message.dart
  • test/relic_server_serve_test.dart
  • test/message/request_test.dart
  • lib/src/context/request.dart
  • test/static/cache_busting_static_handler_test.dart
  • test/static/test_util.dart
  • lib/src/middleware/middleware_logger.dart
  • example/advanced/multi_isolate.dart
  • lib/src/handler/cascade.dart
  • test/message/response_test.dart
  • lib/src/context/response.dart
test/**/*.dart

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

test/**/*.dart: Tests should follow the Given-When-Then pattern in descriptions (flexible structuring allowed)
Use Arrange-Act-Assert pattern within test bodies
Provide clear, descriptive test titles; prefer single responsibility per test unless related assertions improve clarity
Place tests in the test/ directory mirroring the lib/ structure

Files:

  • test/router/router_inject_test.dart
  • test/src/middleware/context_property_test.dart
  • test/static/alternative_root_test.dart
  • test/middleware/routing_middleware_test.dart
  • test/router/router_handler_test.dart
  • test/middleware/middleware_object_test.dart
  • test/src/adapter/context_test.dart
  • test/util/test_util.dart
  • test/handler/cascade_test.dart
  • test/relic_server_serve_test.dart
  • test/message/request_test.dart
  • test/static/cache_busting_static_handler_test.dart
  • test/static/test_util.dart
  • test/message/response_test.dart
lib/**/*.dart

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

lib/**/*.dart: Use Uint8List for request/response bodies for performance; avoid List for body payloads
Use type-safe HTTP header parsing and validation when accessing headers
Use router with trie-based matching and symbol-based path parameters (e.g., #name, #age) for routing
Ensure WebSocket handling includes proper lifecycle management (e.g., ping/pong for connection health)

Files:

  • lib/src/adapter/io/request.dart
  • lib/src/adapter/io/response.dart
  • lib/src/adapter/adapter.dart
  • lib/src/io/static/static_handler.dart
  • lib/src/middleware/routing_middleware.dart
  • lib/src/relic_server.dart
  • lib/src/middleware/context_property.dart
  • lib/src/handler/handler.dart
  • lib/relic.dart
  • lib/src/context/message.dart
  • lib/src/context/request.dart
  • lib/src/middleware/middleware_logger.dart
  • lib/src/handler/cascade.dart
  • lib/src/context/response.dart
🧠 Learnings (22)
📓 Common learnings
Learnt from: nielsenko
Repo: serverpod/relic PR: 76
File: lib/src/handler/handler.dart:20-20
Timestamp: 2025-05-23T04:15:01.420Z
Learning: In the relic codebase, ResponseContext is a subtype of HandledContext, making functions with signature ResponseContext Function(RequestContext) assignable to the Handler typedef (FutureOr<HandledContext> Function(NewContext ctx)) due to covariant return types and contravariant parameter types in Dart's type system.
Learnt from: CR
Repo: serverpod/relic PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-09T16:21:09.310Z
Learning: Applies to lib/**/*.dart : Use router with trie-based matching and symbol-based path parameters (e.g., `#name`, `#age`) for routing
Learnt from: nielsenko
Repo: serverpod/relic PR: 48
File: lib/src/handler/handler.dart:59-67
Timestamp: 2025-04-25T07:39:38.915Z
Learning: Nielsenko prefers using switch statements with pattern matching over if statements when working with sealed classes in Dart, as they provide exhaustiveness checking at compile time and can be more concise.
📚 Learning: 2025-09-22T08:30:14.860Z
Learnt from: nielsenko
Repo: serverpod/relic PR: 179
File: lib/src/middleware/routing_middleware.dart:42-43
Timestamp: 2025-09-22T08:30:14.860Z
Learning: In Relic's routing middleware, Uri.decodeFull(req.url.path) is used to decode incoming request paths before routing. This is correct because routes are defined with plain paths (not percent-encoded), so incoming requests need to be decoded to match the route definitions. The concern about %2F changing segmentation is not relevant since route definitions don't use percent-encoding.

Applied to files:

  • doc/site/docs/02-reference/07-middleware.md
  • README.md
  • doc/site/docs/02-reference/04-requests.md
  • example/routing/request_example.dart
  • example/routing/request_response_example.dart
📚 Learning: 2025-10-09T16:21:09.310Z
Learnt from: CR
Repo: serverpod/relic PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-09T16:21:09.310Z
Learning: Applies to lib/**/*.dart : Use router with trie-based matching and symbol-based path parameters (e.g., `#name`, `#age`) for routing

Applied to files:

  • doc/site/docs/02-reference/07-middleware.md
  • test/router/router_inject_test.dart
  • lib/src/adapter/io/request.dart
  • lib/src/io/static/static_handler.dart
  • test/middleware/routing_middleware_test.dart
  • lib/src/middleware/routing_middleware.dart
  • test/router/router_handler_test.dart
  • README.md
  • doc/site/docs/02-reference/04-requests.md
  • example/routing/request_example.dart
  • example/context/context_example.dart
  • lib/src/handler/handler.dart
  • example/routing/request_response_example.dart
  • test/static/cache_busting_static_handler_test.dart
📚 Learning: 2025-10-20T14:05:34.503Z
Learnt from: nielsenko
Repo: serverpod/relic PR: 226
File: lib/src/router/relic_app.dart:147-156
Timestamp: 2025-10-20T14:05:34.503Z
Learning: In the relic codebase, hot-reload and other development-time features in lib/src/router/relic_app.dart should fail loudly (raise exceptions) rather than catch and suppress errors, as this helps developers diagnose issues during development.

Applied to files:

  • test/router/router_inject_test.dart
  • lib/src/relic_server.dart
  • test/router/router_handler_test.dart
  • test/middleware/middleware_object_test.dart
  • test/src/adapter/context_test.dart
  • test/relic_server_serve_test.dart
  • test/static/cache_busting_static_handler_test.dart
📚 Learning: 2025-10-09T16:21:09.310Z
Learnt from: CR
Repo: serverpod/relic PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-09T16:21:09.310Z
Learning: Applies to test/**/*.dart : Provide clear, descriptive test titles; prefer single responsibility per test unless related assertions improve clarity

Applied to files:

  • test/router/router_inject_test.dart
  • test/src/middleware/context_property_test.dart
  • test/static/alternative_root_test.dart
  • test/middleware/routing_middleware_test.dart
  • test/middleware/middleware_object_test.dart
  • test/src/adapter/context_test.dart
  • test/util/test_util.dart
  • test/handler/cascade_test.dart
  • test/relic_server_serve_test.dart
  • test/message/request_test.dart
📚 Learning: 2025-04-24T04:14:12.943Z
Learnt from: nielsenko
Repo: serverpod/relic PR: 47
File: test/hijack/relic_hijack_test.dart:82-90
Timestamp: 2025-04-24T04:14:12.943Z
Learning: Tests within a single file in Dart's test package run sequentially, not concurrently, so global state for test resources within a file doesn't present race condition risks.

Applied to files:

  • test/router/router_inject_test.dart
  • test/middleware/routing_middleware_test.dart
  • test/middleware/middleware_object_test.dart
  • test/src/adapter/context_test.dart
  • test/handler/cascade_test.dart
📚 Learning: 2025-10-09T16:21:09.310Z
Learnt from: CR
Repo: serverpod/relic PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-09T16:21:09.310Z
Learning: Applies to test/**/*.dart : Use Arrange-Act-Assert pattern within test bodies

Applied to files:

  • test/router/router_inject_test.dart
  • test/middleware/routing_middleware_test.dart
  • test/middleware/middleware_object_test.dart
  • test/src/adapter/context_test.dart
  • test/handler/cascade_test.dart
  • test/message/request_test.dart
📚 Learning: 2025-10-09T16:21:09.310Z
Learnt from: CR
Repo: serverpod/relic PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-09T16:21:09.310Z
Learning: Applies to lib/**/*.dart : Use Uint8List for request/response bodies for performance; avoid List<int> for body payloads

Applied to files:

  • lib/src/adapter/io/request.dart
  • lib/src/adapter/io/response.dart
  • lib/relic.dart
  • test/relic_server_serve_test.dart
  • lib/src/context/response.dart
📚 Learning: 2025-10-09T16:21:09.310Z
Learnt from: CR
Repo: serverpod/relic PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-09T16:21:09.310Z
Learning: Applies to lib/**/*.dart : Use type-safe HTTP header parsing and validation when accessing headers

Applied to files:

  • lib/src/adapter/io/request.dart
  • lib/src/adapter/io/response.dart
  • lib/src/relic_server.dart
  • lib/src/context/message.dart
  • test/message/request_test.dart
📚 Learning: 2025-05-23T04:15:01.420Z
Learnt from: nielsenko
Repo: serverpod/relic PR: 76
File: lib/src/handler/handler.dart:20-20
Timestamp: 2025-05-23T04:15:01.420Z
Learning: In the relic codebase, ResponseContext is a subtype of HandledContext, making functions with signature ResponseContext Function(RequestContext) assignable to the Handler typedef (FutureOr<HandledContext> Function(NewContext ctx)) due to covariant return types and contravariant parameter types in Dart's type system.

Applied to files:

  • test/src/middleware/context_property_test.dart
  • lib/src/adapter/io/response.dart
  • test/router/router_handler_test.dart
  • lib/src/middleware/context_property.dart
  • lib/src/handler/handler.dart
  • test/util/test_util.dart
  • lib/src/context/request.dart
  • test/static/test_util.dart
  • lib/src/handler/cascade.dart
  • test/message/response_test.dart
  • lib/src/context/response.dart
📚 Learning: 2025-10-09T16:21:09.310Z
Learnt from: CR
Repo: serverpod/relic PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-09T16:21:09.310Z
Learning: Applies to lib/**/*.dart : Ensure WebSocket handling includes proper lifecycle management (e.g., ping/pong for connection health)

Applied to files:

  • lib/src/adapter/io/response.dart
  • lib/src/adapter/adapter.dart
📚 Learning: 2025-05-05T14:40:00.323Z
Learnt from: nielsenko
Repo: serverpod/relic PR: 52
File: lib/src/router/router.dart:37-53
Timestamp: 2025-05-05T14:40:00.323Z
Learning: In the Router and PathTrie implementation in Dart, both static and dynamic routes consistently throw ArgumentError when attempting to add duplicate routes, despite comments suggesting dynamic routes would be overwritten with a warning.

Applied to files:

  • lib/src/io/static/static_handler.dart
  • lib/src/middleware/routing_middleware.dart
📚 Learning: 2025-05-09T07:55:38.627Z
Learnt from: nielsenko
Repo: serverpod/relic PR: 62
File: lib/src/router/router.dart:31-38
Timestamp: 2025-05-09T07:55:38.627Z
Learning: In the Relic router implementation, attaching a sub-router doesn't require clearing the parent router's static cache because it only adds new routes without affecting existing cache entries. The sub-router's cache is cleared primarily to save memory.

Applied to files:

  • lib/src/io/static/static_handler.dart
  • test/static/cache_busting_static_handler_test.dart
📚 Learning: 2025-10-09T16:21:09.310Z
Learnt from: CR
Repo: serverpod/relic PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-09T16:21:09.310Z
Learning: Applies to test/**/*.dart : Place tests in the `test/` directory mirroring the `lib/` structure

Applied to files:

  • test/middleware/routing_middleware_test.dart
  • test/middleware/middleware_object_test.dart
  • test/src/adapter/context_test.dart
  • test/handler/cascade_test.dart
  • test/relic_server_serve_test.dart
  • test/message/request_test.dart
📚 Learning: 2025-05-09T10:11:33.427Z
Learnt from: nielsenko
Repo: serverpod/relic PR: 62
File: lib/src/router/router.dart:0-0
Timestamp: 2025-05-09T10:11:33.427Z
Learning: In the Router implementation, re-adding a route with the same path isn't currently allowed and will throw an ArgumentError from _allRoutes.add(), but handling cache invalidation or updates proactively is important for future-proofing in case route updates are later supported.

Applied to files:

  • lib/src/middleware/routing_middleware.dart
📚 Learning: 2025-10-22T15:43:43.812Z
Learnt from: nielsenko
Repo: serverpod/relic PR: 216
File: test/relic_server_test.dart:44-47
Timestamp: 2025-10-22T15:43:43.812Z
Learning: In Dart, the `Uri.http` constructor's path parameter (`unencodedPath`) is optional and defaults to an empty string. Code like `Uri.http('localhost:$port')` is valid without supplying a path argument.

Applied to files:

  • doc/site/docs/02-reference/04-requests.md
  • test/relic_server_serve_test.dart
  • test/message/request_test.dart
  • lib/src/context/request.dart
📚 Learning: 2025-11-04T10:24:49.925Z
Learnt from: nielsenko
Repo: serverpod/relic PR: 264
File: lib/src/context/context.dart:4-4
Timestamp: 2025-11-04T10:24:49.925Z
Learning: In Dart, cyclic imports between libraries are not a problem and are handled by the language without compile-time errors, unlike some other programming languages.

Applied to files:

  • lib/src/handler/handler.dart
📚 Learning: 2025-10-22T11:25:39.264Z
Learnt from: nielsenko
Repo: serverpod/relic PR: 216
File: lib/src/router/relic_app.dart:47-49
Timestamp: 2025-10-22T11:25:39.264Z
Learning: In the serverpod/relic repository, validation of the `noOfIsolates` parameter should be handled in the `RelicServer` constructor (lib/src/relic_server.dart), not in `RelicApp.run` (lib/src/router/relic_app.dart).

Applied to files:

  • test/relic_server_serve_test.dart
📚 Learning: 2025-06-04T15:12:15.865Z
Learnt from: nielsenko
Repo: serverpod/relic PR: 91
File: lib/src/util/util.dart:49-62
Timestamp: 2025-06-04T15:12:15.865Z
Learning: In Dart, StreamController instances created locally in methods and returned as sinks don't cause resource leaks when abandoned. The garbage collector automatically reclaims the entire object graph (sink → controller → stream → subscription) when there are no external references, as StreamControllers don't hold system resources requiring explicit cleanup.

Applied to files:

  • test/relic_server_serve_test.dart
📚 Learning: 2025-05-05T16:06:15.941Z
Learnt from: nielsenko
Repo: serverpod/relic PR: 52
File: lib/src/router/normalized_path.dart:72-86
Timestamp: 2025-05-05T16:06:15.941Z
Learning: When writing tests for Dart classes with private constructors and factory methods, extending the class for test purposes may not be possible. The NormalizedPath class in particular uses a private constructor and factory constructor pattern.

Applied to files:

  • test/message/request_test.dart
📚 Learning: 2025-10-09T16:21:09.310Z
Learnt from: CR
Repo: serverpod/relic PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-09T16:21:09.310Z
Learning: Applies to test/**/*.dart : Tests should follow the Given-When-Then pattern in descriptions (flexible structuring allowed)

Applied to files:

  • test/message/request_test.dart
📚 Learning: 2025-04-24T14:06:32.810Z
Learnt from: nielsenko
Repo: serverpod/relic PR: 48
File: example/example.dart:31-36
Timestamp: 2025-04-24T14:06:32.810Z
Learning: In the example code, `sleep()` is intentionally used instead of `await Future.delayed()` to simulate CPU-bound work that benefits from multiple isolates/cores. Using a blocking call demonstrates why multiple isolates are necessary, while an async approach would allow a single isolate to handle multiple requests concurrently, defeating the purpose of the multi-isolate example.

Applied to files:

  • example/advanced/multi_isolate.dart
🔇 Additional comments (35)
lib/src/middleware/routing_middleware.dart (1)

121-122: LGTM! Documentation enhancement aids migration.

The added note clearly communicates that matchedPath replaces the deprecated handlerPath property, helping users understand the API evolution and migrate their code accordingly.

test/static/alternative_root_test.dart (3)

28-28: LGTM: Simplified path correctly references root file.

The simplified path '/root.txt' correctly accesses the root-level file created in setUp.


76-76: LGTM: Path correctly references file in subdirectory.

The simplified path '/files/test.txt' correctly accesses the file created in the files/ subdirectory.


92-92: LGTM: Path correctly tests non-existent file handling.

The simplified path '/not_here.txt' appropriately tests the 404 response for a non-existent file.

example/context/context_example.dart (1)

122-122: LGTM! Correct usage of the new API.

The change correctly uses req.matchedPath to access the matched route path, aligning with the PR's removal of Request.handlerPath and introduction of the routing middleware's matchedPath extension.

example/routing/request_response_example.dart (1)

26-30: LGTM! Excellent example of the new API.

The code correctly demonstrates the refactored Request API with precise terminology. Using "Matched path" in the log message clearly communicates that matchedPath represents the matched route path from the routing middleware.

lib/src/adapter/io/response.dart (1)

3-21: Import switch to result.dart is consistent with the context refactor

Using ../../context/result.dart keeps Response and related types available to this IO adapter, and the existing writeHttpResponse implementation remains correct with Body.read() returning a Stream<Uint8List>. No further changes needed here.

lib/src/context/message.dart (1)

1-43: part of 'result.dart' aligns Message with the new context module

Pointing this part file at result.dart matches the broader context consolidation without changing Message behavior (headers/body, readAsString, encoding, etc.). Looks good.

test/middleware/routing_middleware_test.dart (1)

2-12: Test import update to result.dart matches the new context layout

Switching to package:relic/src/context/result.dart keeps RequestInternal and related types available, and _request now correctly constructs Request with the new (method, url, token) signature via Uri.http. The tests continue to exercise routing and pathParameters as intended.

test/message/response_test.dart (1)

173-188: Encoding moved from Response to Body is consistent with the new API

Passing encoding: latin1 into Body.fromString and leaving the Response constructor unaware of encoding matches the refactor where Body owns encoding. The subsequent copyWith and encoding expectations remain valid because Response.encoding still delegates to body.bodyType?.encoding. No issues here.

lib/src/context/request.dart (1)

1-120: Request simplification and URL validation align well with the new API surface

The new shape of Request:

  • Promotes a single, authoritative url (final Uri url;) in place of requestedUri/handlerPath.
  • Validates the URL eagerly in the private constructor via pathSegments / queryParametersAll, plus explicit checks for isAbsolute and an empty fragment, which is appropriate for actual HTTP requests.
  • Keeps copyWith straightforward by allowing headers, url, and body overrides while preserving method, protocol version, and token; this matches how Response.copyWith behaves in the tests.

The UriEx extension:

extension UriEx on Uri {
  Uri get pathAndQuery => Uri(path: path, query: query);
}

provides the intended “root-relative” representation without mutating the original Uri, and integrates cleanly with the migration guidance to use request.url.pathAndQuery where a non-absolute URI is needed. If you ever find you mainly need a string form, you could optionally add a helper like String get pathAndQueryString => pathAndQuery.toString() on top of this, but the current design is already sound.

example/advanced/multi_isolate.dart (1)

47-51: LGTM!

The parameter rename from request to req improves naming consistency across the codebase. The corresponding usage update to req.url is correct.

lib/src/adapter/adapter.dart (1)

5-5: LGTM!

The import path update from context.dart to result.dart aligns with the documented breaking changes in this PR.

lib/src/middleware/context_property.dart (1)

1-1: LGTM!

The import path update correctly reflects the context module reorganization.

lib/src/adapter/io/request.dart (1)

6-6: LGTM!

The import path update is correct and consistent with the broader refactoring.

test/middleware/middleware_object_test.dart (1)

2-2: LGTM!

The import path update is correct for the test file and aligns with the context module reorganization.

lib/src/handler/handler.dart (1)

3-3: LGTM!

The import path update correctly references the reorganized context module.

test/router/router_inject_test.dart (1)

4-4: LGTM!

The import path update is correct and maintains consistency across test files.

test/src/middleware/context_property_test.dart (1)

2-2: LGTM!

The import path update is correct and completes the migration to the reorganized context module structure.

test/handler/cascade_test.dart (1)

2-2: LGTM! Import path updated correctly.

The import path change from context/context.dart to context/result.dart aligns with the repository-wide context module restructuring.

doc/site/docs/02-reference/07-middleware.md (1)

180-182: LGTM! Documentation accurately reflects the new API.

The warning correctly states that rewriting request.url in middleware attached with router.use(...) will not re-route the request or update routing metadata, which aligns with the PR's changes to the Request API.

lib/src/handler/cascade.dart (1)

1-1: LGTM! Import path updated correctly.

The import path change from context/context.dart to context/result.dart is consistent with the context module restructuring across the codebase.

lib/src/relic_server.dart (2)

5-5: LGTM! Import path updated correctly.

The import change aligns with the context module restructuring.


180-183: LGTM! Error logging updated to use the new API.

The logging correctly uses request.url.path and request.url.query instead of the removed requestedUri property, maintaining the same functionality.

test/router/router_handler_test.dart (1)

2-2: LGTM! Import path updated correctly.

The import path change from context/context.dart to context/result.dart is consistent with the repository-wide refactoring.

test/relic_server_serve_test.dart (1)

74-77: LGTM! Test updated correctly for the new API.

The test now uses req.url instead of req.requestedUri, and correctly expects /foo/bar with a leading slash (as Uri.path includes the leading slash). These changes align with the PR's API refactoring.

lib/relic.dart (1)

8-8: LGTM! Public API export updated correctly.

The export path change from context/context.dart to context/result.dart aligns with the context module restructuring, while preserving the hide RequestInternal directive to maintain API encapsulation.

test/util/test_util.dart (2)

8-8: LGTM! Import path updated correctly.

The import change aligns with the context module restructuring.


30-30: LGTM! Test utility updated to use the new API.

The helper function now correctly uses req.url.path instead of the removed req.requestedUri.path, maintaining the same functionality with the new API.

lib/src/io/static/static_handler.dart (1)

122-126: StaticHandler.injectIn wiring looks correct.

Registering Directory under /** and File under / for GET/HEAD only matches the internal use of remainingPath and keeps method validation centralized in _serveFile. This aligns with the router-based mounting pattern introduced in the PR.

README.md (1)

96-112: Routing documentation update looks consistent.

The new paragraph and example around Router, routeWith, and router.asHandler align with the router‑centric model used elsewhere in the README and tests (colon path params + symbol keys). No issues from a behavior or clarity standpoint.

lib/src/middleware/middleware_logger.dart (2)

14-42: logRequests refactor preserves behavior.

The expanded closure form with localLogger keeps the same timing, logging, and error‑handling semantics while improving readability. Using request.url in _message correctly reflects the new URL API.


48-61: URL logging update matches new Request.url model.

Switching _message to log ${url.path}${_formatQuery(url.query)} via request.url maintains the previous path+query behavior now that url represents the original requested URI. This keeps log output stable across the API change.

test/message/request_test.dart (1)

134-169: copyWith tests align with new url-based Request API.

The copyWith() test correctly checks that url and url.pathAndQuery are preserved when no arguments are provided, and that body streaming still works via the controller. This is a good regression guard for the simplified copyWith implementation.

lib/src/context/response.dart (1)

1-1: Part directive matches the new library unit.

Changing this file to part of 'result.dart'; is consistent with the context/result refactor described in the PR and keeps Response within the new public library surface.

@nielsenko
Copy link
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 20, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nielsenko nielsenko requested a review from Copilot November 20, 2025 09:29
Copilot finished reviewing on behalf of nielsenko November 20, 2025 09:32
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR simplifies the Request and Response classes by removing deprecated properties and parameters. The changes consolidate the URL representation into a single url property (repurposed from the old requestedUri), remove the handlerPath property in favor of extension methods, and simplify Response constructors by removing encoding and context parameters. Additionally, the core context file is renamed from context.dart to result.dart.

Key changes:

  • Removed Request.handlerPath - replaced with matchedPath extension method from routing middleware
  • Renamed Request.requestedUri to Request.url (repurposing the old url field name)
  • Removed path parameter from Request.copyWith()
  • Removed encoding and context parameters from all Response constructors
  • Renamed lib/src/context/context.dart to lib/src/context/result.dart

Reviewed Changes

Copilot reviewed 35 out of 36 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
lib/src/context/request.dart Simplified Request class by removing handlerPath/url properties and complex validation; renamed requestedUri to url; added UriEx extension
lib/src/context/response.dart Removed encoding and context parameters from all Response constructors
lib/src/context/result.dart Renamed from context.dart; contains Result, Request, Response, and Message classes
lib/src/middleware/routing_middleware.dart Added documentation clarifying matchedPath replaces handlerPath
test/static/cache_busting_static_handler_test.dart Refactored tests to use buildStaticHandler helper and removed handlerPath parameter
test/static/alternative_root_test.dart Simplified test requests by removing handlerPath parameter
test/message/request_test.dart Updated tests to use new url property and removed handlerPath/url validation tests
example/routing/*.dart Updated examples to use matchedPath instead of url and renamed requestedUri to url
doc/site/docs/02-reference/*.md Updated documentation to reflect new URL semantics

@nielsenko nielsenko marked this pull request as ready for review November 21, 2025 07:00
@nielsenko nielsenko requested a review from a team November 21, 2025 07:01
Copy link
Contributor

@SandPod SandPod left a comment

Choose a reason for hiding this comment

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

One minor question, otherwise the changes looks good.

@nielsenko nielsenko merged commit 47f933d into serverpod:main Nov 21, 2025
26 of 27 checks passed
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.

2 participants