refactor: Middleware to use chi's Use instead of custom plug chain#450
Conversation
Plugs registered via Plug() run inside handle(), which is only reached after chi has matched a (method, path) pair. This means they miss requests chi rejects at the routing layer — most visibly, OPTIONS preflights to paths that only register GET (chi returns 405 before any plug fires). Use() wraps each Plug as chi router middleware via mux.Use(), so it executes before route matching and sees every request, including those chi would otherwise reject with 405. Plug() is unchanged; all existing tests continue to pass. https://claude.ai/code/session_01Y1KRWLLr2YC6Sisy2w2ZAJ
Previously Plug appended to k.plugs, which were applied inside handle() — reached only after chi matched a (method, path) pair. This meant plugs missed any request chi rejected at the routing layer, most visibly OPTIONS preflights to paths that only register GET (chi returned 405 before any plug ran). Plug now wraps each middleware directly as chi router middleware via mux.Use(), so it fires before route matching on every request. The k.plugs field and its handle() loop are removed. Group is simplified accordingly: parent mux middleware already runs before chi's Mount hands off to the sub-router, so the manual parent-plug propagation loop is no longer needed. https://claude.ai/code/session_01Y1KRWLLr2YC6Sisy2w2ZAJ
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
- Remove double blank line in mux_test.go (gofumpt) - Replace deprecated reflect.Ptr with reflect.Pointer in jsonformat/formatter.go and cache/mem.go (govet inline) https://claude.ai/code/session_01Y1KRWLLr2YC6Sisy2w2ZAJ
This comment has been minimized.
This comment has been minimized.
Review summary
The refactor successfully simplifies the middleware plumbing by delegating to chi's Critical issues 🔴None Warnings 🟡1. No test for multiple The existing tests only exercise a single plug. With the new loop-based // Missing: register two plugs and assert both ran in order
app.Plug(plugA, plugB)2. No test that The old app.Plug(globalMiddleware)
app.Group("/api", func(sub *Kit) {
sub.Get("/ping", handler)
})
// assert globalMiddleware ran for GET /api/ping3. Unrelated files changed without explanation
Suggestions 🟢1. Document the context-propagation contract in the The middleware creates its own // Values stored via ctx.Set in a Plug are propagated to the route handler
// through the request context; they are visible via ctx.Get in the handler.2. Evaluate whether
|
Summary
This PR refactors the middleware system to leverage chi's built-in
Usemethod for global middleware instead of maintaining a separateplugsslice. This simplifies the codebase and ensures middleware runs before route matching, making it suitable for cross-cutting concerns like CORS and logging.Key Changes
plugsfield from theKitstruct and its initializationPlugmethod to directly register middleware with chi'sUseinstead of appending to a slicehandlemethod since middleware now runs at the chi router levelGroupmethod by removing the logic that manually applied parent plugs to sub-routers (no longer needed since plugs are registered globally on chi)Plugwith two test cases:Implementation Details
The
Plugmethod now wraps each middleware function to:This approach ensures middleware executes before route matching at the chi level, providing the expected behavior for global middleware while maintaining compatibility with the existing
HandlerandPlugfunction signatures.https://claude.ai/code/session_01Y1KRWLLr2YC6Sisy2w2ZAJ