Skip to content

Instantly share code, notes, and snippets.

@gbbr
Created September 11, 2017 08:14
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save gbbr/85448fc35bf1a008363a4f5da469fa4d to your computer and use it in GitHub Desktop.
Save gbbr/85448fc35bf1a008363a4f5da469fa4d to your computer and use it in GitHub Desktop.
package main
import (
"fmt"
"log"
"net/http"
)
func init() {
log.SetFlags(log.Lshortfile)
}
// middleware provides a convenient mechanism for filtering HTTP requests
// entering the application. It returns a new handler which performs various
// operations and finishes with calling the next HTTP handler.
type middleware func(http.HandlerFunc) http.HandlerFunc
// chainMiddleware provides syntactic sugar to create a new middleware
// which will be the result of chaining the ones received as parameters.
func chainMiddleware(mw ...middleware) middleware {
return func(final http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
last := final
for i := len(mw) - 1; i >= 0; i-- {
last = mw[i](last)
}
last(w, r)
}
}
}
func withLogging(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
log.Printf("Logged connection from %s", r.RemoteAddr)
next.ServeHTTP(w, r)
}
}
func withTracing(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
log.Printf("Tracing request for %s", r.RequestURI)
next.ServeHTTP(w, r)
}
}
func home(w http.ResponseWriter, r *http.Request) {
log.Println("reached home")
fmt.Fprintf(w, "welcome")
}
func main() {
mw := chainMiddleware(withLogging, withTracing)
http.Handle("/", mw(home))
log.Fatal(http.ListenAndServe(":8080", nil))
}
@nurali
Copy link

nurali commented Dec 28, 2018

@gbbr thanks for smallest middleware chaining example.

One minor feedback, in chainMiddleware, for each new request, the for_loop will get executed. We can avoid this by taking for_loop just one level up (outer func) so that on every new request this loop will not run. This for_loop run once when new handler is registered. Every time new request arrives, it just call last and the magic of middleware chaining will happen. Here is modified version link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment