Skip to content

fix(macros): support prefix/suffix in TypedPath segments#3725

Open
dihannahdi wants to merge 1 commit into
tokio-rs:mainfrom
dihannahdi:fix/typed-path-prefix-suffix
Open

fix(macros): support prefix/suffix in TypedPath segments#3725
dihannahdi wants to merge 1 commit into
tokio-rs:mainfrom
dihannahdi:fix/typed-path-prefix-suffix

Conversation

@dihannahdi

Copy link
Copy Markdown
Contributor

Motivation

The TypedPath derive macro currently requires each path segment to be entirely a capture (/{id}) or entirely static (/users). This means routes with mixed segments—where a capture is embedded within static text—are rejected by the macro even though the underlying matchit router fully supports them.

Common real-world patterns that fail today:

#[derive(TypedPath, Deserialize)]
#[typed_path("/@{username}")]       // prefix capture
struct AtUsername { username: String }

#[derive(TypedPath, Deserialize)]
#[typed_path("/avatars/{id}.png")]   // suffix capture
struct AvatarPath { id: u32 }

#[derive(TypedPath, Deserialize)]
#[typed_path("/files/{name}.tar.gz")] // prefix + suffix
struct FilePath { name: String }

These all produce a compile error because parse_path() only recognises segments that start with { and end with }.

Closes #3681

Solution

Add a CaptureWithAffix variant to the internal Segment enum:

CaptureWithAffix {
    prefix: String,   // text before `{`
    capture: String,   // the capture name
    suffix: String,    // text after `}`
    span: Span,
}

parse_path() now scans each segment for {…} anywhere within it. When a capture is found with surrounding static text, the new variant is emitted. All downstream functions (format_str_from_path, captures_from_path, field expansion, unit-struct validation) are updated to handle it.

Escaped braces ({{, }}) are left alone as static segments—matching the existing behaviour.

Testing

  • New pass test (prefix_suffix_capture.rs) covering named structs, tuple structs, and paths with prefix-only, suffix-only, and prefix+suffix captures.
  • All existing tests continue to pass (cargo test -p axum-macros — 28/28 passing).

@dihannahdi dihannahdi force-pushed the fix/typed-path-prefix-suffix branch 2 times, most recently from f5093b4 to a7cfc20 Compare April 12, 2026 13:29
The TypedPath derive macro previously required path segments to be
entirely a capture (e.g., /{id}) or entirely static (e.g., /users).
This made it impossible to use routes with mixed segments like
/@{username} or /avatars/{id}.png, even though the underlying matchit
router fully supports them.

Add a CaptureWithAffix variant to the Segment enum and update
parse_path() to detect captures embedded within a segment,
extracting the prefix and suffix around the {capture}. The
format_str, captures, and field expansion functions are all
updated to handle the new variant.

Closes tokio-rs#3681
@dihannahdi dihannahdi force-pushed the fix/typed-path-prefix-suffix branch from 2f757ed to fbb5a22 Compare April 15, 2026 11:41
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.

The TypedPath derive macro breaks for segments with a prefix or suffix

1 participant