🔥 feat: add SkipUnmatchedRoutes config option#4411
Conversation
|
Thanks for opening this pull request! 🎉 Please check out our contributing guidelines. If you need help or want to chat with us, join us on Discord https://gofiber.io/discord |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
WalkthroughAdds ChangesSkipUnmatchedRoutes Feature
Sequence DiagramsequenceDiagram
participant Client
participant Handler as defaultRequestHandler/customRequestHandler
participant Config as app.config.SkipUnmatchedRoutes
participant RouteChecker as App.routeExists
participant Middleware as middleware chain
participant Endpoint as matched endpoint route
Client->>Handler: incoming HTTP request
Handler->>Config: read SkipUnmatchedRoutes
alt SkipUnmatchedRoutes == true
Handler->>RouteChecker: routeExists(method, path)
alt routeExists == false
Handler->>Handler: return 404 StatusNotFound
else routeExists == true
Handler->>Middleware: enter middleware chain
Middleware->>Endpoint: execute matched endpoint
end
else SkipUnmatchedRoutes == false
Handler->>Middleware: enter middleware chain
Middleware->>Endpoint: scan & execute matched endpoint
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Possibly related issues
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
router_test.go (1)
2570-2665: ⚡ Quick winAdd a custom-context variant for
SkipUnmatchedRoutesto cover both handler paths.These tests validate the default handler path well, but they don’t explicitly assert behavior through
newCustomApp()/custom request handling. Adding one matched + one unmatched subtest there would guard against regressions incustomRequestHandlertoo.Based on learnings from provided context:
SkipUnmatchedRoutesshort-circuit logic is present in both default and custom handlers (router.go:449-502).🤖 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 `@router_test.go` around lines 2570 - 2665, Add companion subtests to Test_App_SkipUnmatchedRoutes that exercise the custom-context path by creating an app via newCustomApp() (or the equivalent factory used in custom request handling) and invoking its Test helper with both a matched route ("/users") and an unmatched route ("/notfound" or case/strict variants) while SkipUnmatchedRoutes is true; assert middlewareCalled semantics match the existing default-app cases so the short-circuit logic in customRequestHandler (and related code handling SkipUnmatchedRoutes) is covered and won’t regress.
🤖 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.
Nitpick comments:
In `@router_test.go`:
- Around line 2570-2665: Add companion subtests to Test_App_SkipUnmatchedRoutes
that exercise the custom-context path by creating an app via newCustomApp() (or
the equivalent factory used in custom request handling) and invoking its Test
helper with both a matched route ("/users") and an unmatched route ("/notfound"
or case/strict variants) while SkipUnmatchedRoutes is true; assert
middlewareCalled semantics match the existing default-app cases so the
short-circuit logic in customRequestHandler (and related code handling
SkipUnmatchedRoutes) is covered and won’t regress.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: f733da5b-bbe5-4e94-bbd5-fc8bf48a7b6b
📒 Files selected for processing (3)
app.gorouter.gorouter_test.go
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4411 +/- ##
=======================================
Coverage 91.33% 91.34%
=======================================
Files 132 133 +1
Lines 13193 13250 +57
=======================================
+ Hits 12050 12103 +53
- Misses 724 727 +3
- Partials 419 420 +1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
@muzzii255 pls check linter errors |
|
@muzzii255 pls add something in the markdown docs for this feature |
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
@ReneWerner87 done |
|
@gaby pls check |
gaby
left a comment
There was a problem hiding this comment.
I think we need to do the changes in next(), else we are checking the whole router twice for every requests. That defeats the purpose of this feature.
| } | ||
|
|
||
| // routeExists checks if a non-middleware route matches the given method and path. | ||
| func (app *App) routeExists(methodInt, treeHash int, detectionPath, path string) bool { |
There was a problem hiding this comment.
We don't need this function, it is going through the whole tree for every request.
There was a problem hiding this comment.
yes, but i does not trigger the middlewares, its an extra check to save db and cache queries, on unmatched routes it saves the 1/alloc and faster, but adds same amount if on matched routes, its an opt in feature tho
| } | ||
|
|
||
| // routeExists checks if a non-middleware route matches the given method and path. | ||
| func (app *App) routeExists(methodInt, treeHash int, detectionPath, path string) bool { |
There was a problem hiding this comment.
The way this is implemented, when SkipUnmatchedRoutes is enabled we are calling route.match twice. Here and in next() for every single request.
There was a problem hiding this comment.
The tree walk before middleware is the whole point of SkipUnmatchedRoutes — without it, any middleware registered via Group() fires on requests that never match a route, which is exactly the behavior this flag is meant to prevent. Moving the logic into route.match doesn't change that: by the time next() gets to the per-route comparison, the group middleware has already run.
i tried caching this extra tree walk, but the params paths still creates the overhead and saves like 5-10ns on total benchmark not worth it.
When |
|
@gaby @ReneWerner87 i tried multiple approach like defering the middlewares when |
|
any approach will add an extra lookup on the tree except rewriting the tree, right now i am using a middleware from the PR #4406 on my codebase, it will be easier for me to just use the fiber's internal tree. |
|
@muzzii255 I think in next() we can check. IsMatched() and if false call c.SendString(not found) |
let me test it |
in next() function this loop executes the middlewares before isMatched() is called, i can try defering the middleware execute by appending the handler to a slice, iterate and execute the middleware after if c.isMatched check |
@gaby Do you mean inside next() do the endpoint scan first (before the main loop runs any middleware), and return ErrNotFound if nothing matches? Because checking IsMatched after the loop is too late — middleware has already executed by then, which defeats the feature. |
Description
Adds a
SkipUnmatchedRoutesconfig option that short-circuits requests to unregistered paths — returning 404 immediately without running through the middleware chain. Useful for cutting unnecessary processing from bots, scanners, and bad URLs.Fixes # (issue)
#4403
Changes introduced
SkipUnmatchedRoutes on app.Config, adds extra lookup costing 150-200ns on matched routes but saving same on unmatched routes
List the new features or adjustments introduced in this pull request. Provide details on benchmarks, documentation updates, changelog entries, and if applicable, the migration guide.