This sample explores the idea that middlewares can be injected into an http.Handler
instead of wrapping it.
The current model is:
type mwf func(http.Handler) http.Handler
func oldRecoverer(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if e := recover(); e != nil {
http.Error(w, fmt.Sprint(e), http.StatusInternalServerError)
}
}()
h.ServeHTTP(w, r)
})
}
⋮
http.ListenAndServe(":8000", oldRecoverer(myHandler))
Under the injection model, the body of the handler calls the middleware as follows:
func myHandler(w http.ResponseWriter, r *http.Request) {
defer recoverer(&w, &r)()
⋮
}
⋮
http.ListenAndServe(":8000", myHandler)
The key advantage of this approach is that it gives handlers fine-grained control over middleware execution. Each handler can:
- Cherry-pick middlewares or add extra middlewares to a common set.
- Run code before middlewares.
- Conditionally run middlewares.
- Set a breakpoint at the start of a specific handler and step into its middlewares.
The mwf.wrap
method is a conventional middleware function. Going the other way (convert an existing middleware to an mwf
) isn't possible.