Skip to content

fix(routing): wildcard *path params never get schema-lite type coercion - #234

Merged
ZhuchkaTriplesix merged 1 commit into
devfrom
issue-212-path-param-wildcard-string
Sep 29, 2026
Merged

ZhuchkaTriplesix merged 1 commit into
devfrom
issue-212-path-param-wildcard-string

Conversation

@ZhuchkaTriplesix

Copy link
Copy Markdown
Member

Problem

Every path param value — including a *name catch-all capturing an arbitrary sub-path — went through the same int/float/bool schema-lite coercion as a single-segment :name param (value_for_path_param, src/params.rs).

This broke StaticFiles (mounted via app.mount(...), which registers a *path wildcard route) on any file whose name looked numeric or boolean: GET /static/42 arrived at the handler as int, and int has no .split("/"), so the route 500'd. It also silently mistyped ownership/auth checks comparing a wildcard path segment against a string ID.

Fix

I deliberately scoped this to the wildcard case, not a redesign of path-param coercion in general: the single-segment :name coercion is an existing, documented, thoroughly-tested feature (tests/test_path_param_coercion.py, docs/) with real intentional use, so changing its default behavior would be a much larger, riskier API change out of proportion to this bug.

  • Added RouteExtra::wildcard_params: the set of param names captured by a *name catch-all, computed once at add_route time from the path template.
  • At dispatch time, a param whose name is in that set is passed to the handler as str unconditionally, skipping value_for_path_param's coercion. Single-segment :name params are unaffected.

Testing

  • tests/test_path_param_coercion.py::test_wildcard_path_param_is_never_coerced — new, covers numeric/boolean/float-looking and multi-segment wildcard values.
  • tests/test_static.py::test_static_files_numeric_filename — new, reproduces the original StaticFiles 500.
  • cargo build --lib / cargo clippy --all-targets: clean, no warnings.
  • cargo test --lib: 26 passed.
  • Full suite: 170 passed (168 + 2 new), 1 skipped.
  • ruff check / ruff format --check: clean.

Closes #212

Every path param value, including a `*name` catch-all capturing an
arbitrary sub-path, went through the same int/float/bool schema-lite
coercion as a single-segment `:name` param. This broke StaticFiles
(mounted via app.mount(...) with a `*path` wildcard) on any file whose
name looked numeric or boolean: e.g. GET /static/42 arrived at the
handler as an int, and int has no .split("/"), so the route 500'd.

It also silently mistyped ownership/auth checks comparing a wildcard
path segment against a string ID.

Track which path param names come from a `*name` catch-all at route-
registration time (RouteExtra::wildcard_params) and skip coercion for
just those params at dispatch time. Single-segment `:name` coercion
(fully covered by the existing test_path_param_coercion.py suite) is
unchanged.

Closes #212

@ZhuchkaTriplesix ZhuchkaTriplesix left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

123

@ZhuchkaTriplesix
ZhuchkaTriplesix merged commit eb0d957 into dev Sep 29, 2026
17 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.

1 participant