Repository navigation
Conversation
A route path may now end with a single `*`, which matches any remaining path, so a webhook receiver can register `/webhooks/*` instead of one route per source. The matcher, the publish-time validation and the four SDK routers each share one set of predicates, so a pattern one of them accepts is one the others accept. Validation rejects `*` anywhere but the end, and rejects a wildcard route together with a route it would match for the same HTTP method, rather than letting one silently shadow the other.
paoValle
force-pushed
the
feat/6133-http-route-wildcard
branch
from
October 17, 2026 10:01
5d987c8 to
58a850d
Compare
Author
|
Rebased on Re-ran on the rebased tree:
The C# port applied cleanly as well; |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description of Changes
Part of #6133— this slice adds the trailing wildcard; the:parampart of the issue stays open.A route path may now end with a single
*, which matches any remaining path:ModuleDef::match_http_route) matches a wildcard route against any request path starting with the prefix before the*:/webhooks/*serves/webhooks/github,/webhooks/and/webhooks/a/b, but not/webhooks;*anywhere but the end, and rejects a wildcard route together with a route it would match for the same HTTP method —GET /webhooks/*plusPOST /webhooks/githubis accepted,GET /webhooks/*plusGET /webhooks/githubis not — so no request can be claimed by two routes;spacetimedb_lib::httpfor the schema validator and the Rust module router, and the same logic in the TypeScript, C# and C++ routers so a client-side check does not reject a path the host accepts;API and ABI breaking changes
None. A route path is still a string and
*was rejected before this change, so no module that publishes today changes behaviour, and the request/response ABI is untouched.Rollback safety impact
n/a — no ControlDB table, reducer, system table or on-disk format is written, cleared or changed. A module published with a wildcard route while this is deployed would, after a rollback, simply stop matching that route (the old matcher compares paths exactly) and the request would 404; nothing is stored or migrated.
Expected complexity level and risk
2. The change is a handful of pure predicates plus one branch in the matcher. What lifts it above trivial is that the same logic exists in four places (Rust validator, Rust router, TypeScript router, C#/C++ routers) and the interesting part is where they could disagree, which is why the predicates take the same shapes and the tests pin the same cases in Rust and in TypeScript.
Known, not touched here:
nest/Neststill refuses when an existing route's path starts with the nested prefix, which is stricter than the routing rule and now reachable with a wildcard (Get("/webhooks/*").Nest("/webhooks/", …)). That strictness predates this change and is identical in all three SDKs.Testing
What I ran:
cargo test -p spacetimedb-lib --lib→ 26 passed, 0 failedcargo test -p spacetimedb-schema --lib→ 199 passed, 0 failed (11 of them thehttp_routes_*cases, 6 of them new)cargo check -p spacetimedb --features unstable→ clean;cargo fmt --check→ cleanvitest run tests/http_handlers.test.ts→ 25 passed, 0 failed (3 new cases)*-position check makes 3 new schema tests fail; reverting the matcher'sroute_path_matchesmakes the matcher test fail; reverting the TypeScript predicates makes the 3 new TypeScript tests fail.The C# and C++ ports, which are the parts CI would otherwise be the first to compile:
crates/bindings-csharp/Runtimecompiles clean underdotnet test -warnaserror(net8.0), and the router tests pass — 10 passed, 0 failed — including the three added here.I ran that in a copy of
crates/bindings-csharpbecause on this machine (macOS arm64) thenet10.0target cannot restore: it referencesMicrosoft.DotNet.ILCompiler.LLVM10.0.0-*, which is not published forosx-arm64. Two things to know about that copy, both pre-existing:net10.0was removed fromTargetFrameworks, andRuntime.Tests/JwtClaimsTest.cswas excluded because it does not compile (error CS1729: 'JwtClaims' does not contain a constructor that takes 2 arguments) — which is very likely whyRuntime.Testsis not inSpacetimeSharpSATS.slnand therefore not built by thecsharp_testsjob. That is a separate gap and I did not touch it.clang++ -std=c++20 -fsyntax-only -I crates/bindings-cpp/includeon a translation unit including<spacetimedb/router.h>is clean (only the pre-existingimport_module/import_nameattribute warnings fromabi/abi.hon a non-wasm target). The C++ predicates were verified by reading against the Rust ones, not by a test run:crates/bindings-cpp/testshas no router tests.Still open, and a reviewer may want them:
crates/bindings-csharp/Runtime.Testsis not inSpacetimeSharpSATS.sln, so the tests I added there are not run by thecsharp_testsjob. Adding the project to the solution (after theJwtClaimsTest.csbreakage is fixed) is a separate change and I did not make it here.crates/smoketests/tests/cluster/http_routes.rshas no wildcard case, so the axumroute/*pathcapture into the matcher is covered only by the unit tests. Happy to add a wildcard module to the smoketests if you want the end-to-end path in this PR.