Skip to content

feat(http_extensions): introduce a new "routing" module #389

Draft
martintmk wants to merge 15 commits intomainfrom
routing
Draft

feat(http_extensions): introduce a new "routing" module #389
martintmk wants to merge 15 commits intomainfrom
routing

Conversation

@martintmk
Copy link
Copy Markdown
Member

@martintmk martintmk commented Apr 23, 2026

This module exposes flexible way to inject base_uri to outgoing requests.

Practical application:

// specify http client with a fallback uri
let http_client = http_client.with_routing(Routing::fallback(primary_uri, secondary_uri));

// or use fixed base uri
let http_client = http_client.with_routing(Routing::fallback(primary_uri, secondary_uri));

// force all callers to use relative path
let http_client = http_client.with_routing(Routing::base_uri(primary_uri).conflict_policy(BaseUriConflict::Fail));

Copilot AI review requested due to automatic review settings April 23, 2026 07:13
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 23, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.0%. Comparing base (ade63e3) to head (378f159).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff            @@
##             main     #389    +/-   ##
========================================
  Coverage   100.0%   100.0%            
========================================
  Files         224      226     +2     
  Lines       16187    16325   +138     
========================================
+ Hits        16187    16325   +138     

☔ 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.

Copy link
Copy Markdown
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 introduces a new http_extensions::routing module to resolve and inject a templated_uri::BaseUri into outgoing request targets, with configurable conflict behavior when a target URI already includes a base.

Changes:

  • Add http_extensions::routing with Routing, RoutingContext, and BaseUriConflict, plus tests.
  • Add templated_uri::Uri::into_parts() to split a Uri into (base_uri, path_and_query) for recomposition.
  • Add a new uri_conflict error label and an AsRef<Clock> impl for HttpBodyBuilder, plus changelog entries.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
crates/templated_uri/src/uri.rs Adds Uri::into_parts() for extracting base + path/query components.
crates/templated_uri/CHANGELOG.md Adds an Unreleased entry for the templated_uri change (currently mismatched to the actual API).
crates/http_extensions/src/routing/routing_context.rs Introduces RoutingContext passed to routing resolvers.
crates/http_extensions/src/routing/routing.rs Implements routing strategies, conflict policy handling, request URI update helper, and tests.
crates/http_extensions/src/routing/mod.rs Adds routing module docs and re-exports.
crates/http_extensions/src/lib.rs Exposes the new routing module publicly.
crates/http_extensions/src/error_labels.rs Adds LABEL_URI_CONFLICT for routing conflict validation errors.
crates/http_extensions/src/body/builder.rs Adds impl AsRef<Clock> for HttpBodyBuilder and updates trait assertions in tests.
crates/http_extensions/CHANGELOG.md Adds an Unreleased entry for the new routing module.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/templated_uri/src/uri.rs Outdated
self.try_into()
}

/// Returns the [`BaseUri`] and path and query of the URI as a tuple.
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

The doc comment says this returns the BaseUri and path/query, but the signature returns optional values and the second element is a TargetPathAndQuery (not necessarily a concrete PathAndQuery). Consider rewording to reflect what is actually returned.

Suggested change
/// Returns the [`BaseUri`] and path and query of the URI as a tuple.
/// Returns the optional [`BaseUri`] and optional [`TargetPathAndQuery`] components of the URI as a tuple.

Copilot uses AI. Check for mistakes.
/// Creates a new [`RoutingContext`] for the first (and only) attempt.
#[must_use]
pub fn new() -> Self {
Self::default()
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

RoutingContext::new() is documented as "first (and only) attempt", but it currently uses Default which sets is_last_attempt to false. Either set is_last_attempt to true in new()/Default or adjust the docs so callers don’t get misleading attempt metadata by default.

Suggested change
Self::default()
Self {
is_last_attempt: true,
..Self::default()
}

Copilot uses AI. Check for mistakes.
//! - [`Routing::default`] - returns no [`BaseUri`] (the target [`Uri`] is used as-is).
//! - [`Routing::base_uri`] - always returns the same [`BaseUri`].
//! - [`Routing::custom`] - delegates the decision to a user supplied closure that
//! receives a [`RoutingContext`].
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

Module docs list default, base_uri, and custom constructors, but the module also exposes Routing::fallback. Please include fallback in the construction section (or remove the exhaustive-looking list) so the docs match the public API.

Suggested change
//! receives a [`RoutingContext`].
//! receives a [`RoutingContext`].
//! - [`Routing::fallback`] - uses a fallback [`BaseUri`] when the target [`Uri`]
//! does not already provide one.

Copilot uses AI. Check for mistakes.
Comment on lines +348 to +350
fn assert_routing_size() {
static_assertions::assert_eq_size!(Routing, [u8; 16]);
}
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

This size assertion is likely to be brittle across architectures/compilers (e.g., 32-bit vs 64-bit pointer width, enum layout, future changes to Arc). Unless there’s a strong ABI requirement, consider removing it or gating it behind #[cfg(target_pointer_width = "64")] / using a less strict invariant.

Copilot uses AI. Check for mistakes.

- ✨ Features

- add `routing` module with `Routing`, `RoutingContext`, and `BaseUriConflict` for resolving the target `BaseUri` of outgoing requests
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

This PR also adds a new public trait impl (impl AsRef<Clock> for HttpBodyBuilder). Since the changelog entry is under user-visible features, consider documenting this addition here as well so consumers can discover it.

Suggested change
- add `routing` module with `Routing`, `RoutingContext`, and `BaseUriConflict` for resolving the target `BaseUri` of outgoing requests
- add `routing` module with `Routing`, `RoutingContext`, and `BaseUriConflict` for resolving the target `BaseUri` of outgoing requests
- implement `AsRef<Clock>` for `HttpBodyBuilder`

Copilot uses AI. Check for mistakes.
#[must_use]
pub fn custom<F>(resolver: F) -> Self
where
F: Fn(&RoutingContext) -> Option<BaseUri> + Send + Sync + 'static,
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

RoutingContext is declared as RoutingContext<'a>, but this file uses it without a lifetime parameter (e.g., Fn(&RoutingContext), fn resolve(&self, ctx: &RoutingContext)). This won’t compile and also doesn’t express the intended “any request lifetime” semantics. Consider using an HRTB like for<'a> Fn(&RoutingContext<'a>) -> Option<BaseUri> (and similarly for RoutingFn/resolve).

Suggested change
F: Fn(&RoutingContext) -> Option<BaseUri> + Send + Sync + 'static,
F: for<'a> Fn(&RoutingContext<'a>) -> Option<BaseUri> + Send + Sync + 'static,

Copilot uses AI. Check for mistakes.
Comment thread crates/templated_uri/CHANGELOG.md Outdated

- ✨ Features

- add `Uri::target_base_uri` getter to access the optional `BaseUri`
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

The Unreleased entry mentions adding a Uri::target_base_uri getter, but this PR actually introduces Uri::into_parts (and there’s no target_base_uri in the crate). Please update the changelog entry to match the API that was added.

Suggested change
- add `Uri::target_base_uri` getter to access the optional `BaseUri`
- add `Uri::into_parts`

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings April 23, 2026 07:43
Copy link
Copy Markdown
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

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/templated_uri/CHANGELOG.md Outdated

- ✨ Features

- add `Uri::target_base_uri` getter to access the optional `BaseUri`
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

The Unreleased changelog entry doesn’t match the code changes in this PR: it mentions adding a Uri::target_base_uri getter, but uri.rs adds Uri::into_parts() instead (and there is no target_base_uri in the crate). Please update the entry to describe the actual new API (or implement the documented getter and reference it here).

Suggested change
- add `Uri::target_base_uri` getter to access the optional `BaseUri`
- add `Uri::into_parts()` to access the URI components, including the optional `BaseUri`

Copilot uses AI. Check for mistakes.
Comment on lines +26 to +30
/// Creates a new [`RoutingContext`] for the first (and only) attempt.
#[must_use]
pub fn new() -> Self {
Self::default()
}
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

RoutingContext::new() is documented as creating a context for the "first (and only) attempt", but the default is_last_attempt value is false (and the tests assert that). Either update the docs to say "first attempt" or change the default so that new() sets is_last_attempt to true when that’s the intended meaning.

Copilot uses AI. Check for mistakes.
Comment on lines +34 to +48
/// Always route to a single base URI:
///
/// ```
/// use http_extensions::routing::{Routing, RoutingContext};
/// use templated_uri::{BaseUri, Uri};
///
/// let routing = Routing::base_uri(BaseUri::from_uri_static("https://api.example.com"));
/// let target: Uri = "/v1/items".parse().unwrap();
///
/// let resolved = routing.create_uri(RoutingContext::new(), target).unwrap();
/// assert_eq!(
/// resolved.to_string().declassify_into(),
/// "https://api.example.com/v1/items"
/// );
/// ```
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

PR description example for "fixed base uri" appears to repeat Routing::fallback(...) (same as the previous example). Since Routing::base_uri(...) is the fixed-base option implemented here, please correct the PR description snippet to avoid confusing reviewers/users.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings April 23, 2026 08:38
Copy link
Copy Markdown
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

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


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/http_extensions/src/routing/routing.rs Outdated
Comment thread crates/http_extensions/src/routing/routing.rs Outdated
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 23, 2026 09:14
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
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

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +4 to +9
//! Routing primitives for resolving the [`BaseUri`] of an outgoing request.
//!
//! A [`Routing`] decides which [`BaseUri`] should be attached to a target [`Uri`]
//! before it is sent. This is useful when a library or middleware needs to centralize
//! the resolution of the destination of HTTP requests while still allowing callers to
//! express the rest of the request (path, query, ...) independently.
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

The PR description’s usage examples don’t match the implemented API: the repo contains no with_routing method (searching the codebase finds no occurrences), and the “fixed base uri” example repeats Routing::fallback(...). Consider either adding the integration helper that the description advertises, or updating the description/module docs to demonstrate the supported usage (e.g., Routing::update_request_uri or Routing::create_uri during request construction).

Copilot uses AI. Check for mistakes.
@martintmk martintmk marked this pull request as draft April 27, 2026 09:56
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