Skip to content

fix(routing): match trailing-slash paths for Express compatibility#183

Merged
VikramAditya33 merged 1 commit into
mainfrom
fix/routing
May 20, 2026
Merged

fix(routing): match trailing-slash paths for Express compatibility#183
VikramAditya33 merged 1 commit into
mainfrom
fix/routing

Conversation

@VikramAditya33
Copy link
Copy Markdown
Collaborator

@VikramAditya33 VikramAditya33 commented May 20, 2026

Auto-registers a trailing-slash variant for all simple routes (e.g. /api → also registers /api/). Derived routes are tagged with trailingSlash: true so they stay hidden from getRoutes() / getRouteCount(). Explicit HEAD overrides now also update the trailing-slash variant if one exists.

uWebSockets.js uses exact-path routing, so /api/ returned 404 even though /api worked. Express treats both as the same route by default.

Fixes #182

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • Fixed 404 errors when accessing routes with trailing slashes.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

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.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 94c3b409-8466-4e67-a724-81f32cba304b

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

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/routing

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.

Copy link
Copy Markdown

@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: 1

🧹 Nitpick comments (1)
src/http/routing/route-registry.spec.ts (1)

100-100: ⚡ Quick win

Strengthen this assertion to validate both HEAD paths, not just call count.

This prevents false positives if two calls happen for the wrong routes.

✅ Suggested assertion upgrade
       expect(mockUwsApp.head).toHaveBeenCalledTimes(2);
+      expect(mockUwsApp.head).toHaveBeenNthCalledWith(1, '/items/:id', expect.any(Function));
+      expect(mockUwsApp.head).toHaveBeenNthCalledWith(2, '/items/:id/', expect.any(Function));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/http/routing/route-registry.spec.ts` at line 100, Replace the loose
call-count assertion on mockUwsApp.head with explicit assertions that the
correct HEAD routes were registered: for each expected HEAD path used in this
spec (e.g., the route path constants or the array/variable that lists HEAD
routes), add expect(mockUwsApp.head).toHaveBeenCalledWith('<expectedPath>',
expect.any(Function)) (or the equivalent matcher) for each path instead of only
checking toHaveBeenCalledTimes(2); this ensures mockUwsApp.head was invoked with
each specific route path and a handler function.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/http/routing/route-registry.ts`:
- Around line 425-433: The current companion registration only adds
trailing-slash variants for non-trailing uwsPath, so routes registered with a
trailing slash (uwsPath ending with '/') don't get a non-trailing companion;
update the logic in the route registry to also handle the reverse case: when
uwsPath.endsWith('/') && uwsPath !== '/', compute a nonTrailingPath (strip the
trailing slash), build a companion key using normalizedMethod and that
nonTrailingPath, check this.routes.has(companionKey) and if absent set
this.routes.set(companionKey, { ...routeInfo, trailingSlash: false }) and call
uwsMethodFn.call(this.uwsApp, nonTrailingPath, createHandler(companionKey));
keep existing behavior for the original branch so both directions are covered
and duplicates are avoided.

---

Nitpick comments:
In `@src/http/routing/route-registry.spec.ts`:
- Line 100: Replace the loose call-count assertion on mockUwsApp.head with
explicit assertions that the correct HEAD routes were registered: for each
expected HEAD path used in this spec (e.g., the route path constants or the
array/variable that lists HEAD routes), add
expect(mockUwsApp.head).toHaveBeenCalledWith('<expectedPath>',
expect.any(Function)) (or the equivalent matcher) for each path instead of only
checking toHaveBeenCalledTimes(2); this ensures mockUwsApp.head was invoked with
each specific route path and a handler function.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c8c161b0-4007-4a8c-ba6d-4b1d3aa10410

📥 Commits

Reviewing files that changed from the base of the PR and between d358f73 and 5157d30.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • src/http/routing/route-registry.spec.ts
  • src/http/routing/route-registry.ts

Comment thread src/http/routing/route-registry.ts
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 20, 2026

uWestJS Benchmark Results

Scenario Express req/s Fastify req/s uWestJS req/s Express throughput Fastify throughput uWestJS throughput uWestJS vs Express uWestJS vs Fastify
compression 6.17k 4.92k 7.43k 3.24 MB/s 2.52 MB/s 3.41 MB/s 1.20x 1.51x
headers 21.73k 33.60k 65.97k 4.04 MB/s 6.28 MB/s 10.38 MB/s 3.04x 1.96x
hello-world 21.80k 38.05k 95.63k 3.62 MB/s 6.39 MB/s 9.48 MB/s 4.39x 2.51x
json-response 21.74k 35.47k 66.11k 5.93 MB/s 9.71 MB/s 16.14 MB/s 3.04x 1.86x
mixed-response 20.86k 35.37k 68.35k 4.81 MB/s 8.20 MB/s 13.82 MB/s 3.28x 1.93x
post-json 20.60k 17.60k 32.21k 3.81 MB/s 4.80 MB/s 5.47 MB/s 1.56x 1.83x
query-params 18.15k 32.40k 69.53k 4.00 MB/s 7.17 MB/s 9.35 MB/s 3.83x 2.15x
route-params 21.51k 37.02k 67.99k 4.90 MB/s 8.47 MB/s 13.55 MB/s 3.16x 1.84x
static-file 26.16k 32.81k 63.60k 259.62 MB/s 325.18 MB/s 629.37 MB/s 2.43x 1.94x
streaming-upload 185.81 175.25 186.86 41.37 KB/s 36.62 KB/s 36.13 KB/s 1.01x 1.07x
streaming-with-content-length 739.05 734.27 756.01 3.61 GB/s 3.59 GB/s 3.69 GB/s 1.02x 1.03x
streaming-without-content-length 630.53 630.42 746.97 3.08 GB/s 3.08 GB/s 3.65 GB/s 1.18x 1.18x

@VikramAditya33 VikramAditya33 merged commit dbae482 into main May 20, 2026
4 checks passed
@VikramAditya33 VikramAditya33 deleted the fix/routing branch May 20, 2026 16:02
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.

trailing slash routes return 404

1 participant