Skip to content

Instantly share code, notes, and snippets.

@rogerwelin
Last active August 20, 2019 10:19
Show Gist options
  • Select an option

  • Save rogerwelin/4c664fca4ec1bc3144fccd0d1f159b80 to your computer and use it in GitHub Desktop.

Select an option

Save rogerwelin/4c664fca4ec1bc3144fccd0d1f159b80 to your computer and use it in GitHub Desktop.
Http middlewares in Go
package main
import (
"fmt"
"log"
"net/http"
"time"
"github.com/gorilla/mux"
)
// MiddlewareInterceptor intercepts an HTTP handler invocation
type MiddlewareInterceptor func(http.ResponseWriter, *http.Request, http.HandlerFunc)
// MiddlewareHandlerFunc builds on top of http.HandlerFunc, and exposes API to intercept with MiddlewareInterceptor
type MiddlewareHandlerFunc http.HandlerFunc
// MiddlewareChain is a slice of interceptors that will be invoked in their index order
type MiddlewareChain []MiddlewareInterceptor
// Intercept returns back a continuation that will call install middleware to intercept the continuation call
func (cont MiddlewareHandlerFunc) Intercept(mw MiddlewareInterceptor) MiddlewareHandlerFunc {
return func(writer http.ResponseWriter, request *http.Request) {
mw(writer, request, http.HandlerFunc(cont))
}
}
// Handler allows hooking multiple middleware in single call
func (chain MiddlewareChain) Handler(handler http.HandlerFunc) http.Handler {
current := MiddlewareHandlerFunc(handler)
for i := len(chain) - 1; i >= 0; i-- {
mv := chain[i]
current = current.Intercept(mv)
}
return http.HandlerFunc(current)
}
func NewReqIDInterceptor() MiddlewareInterceptor {
return func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
if r.Header.Get("X-Request-Id") == "" {
r.Header.Set("X-Request-Id", "123abc")
log.Println(r.Header)
}
next(w, r)
}
}
func ElapsedTimeInterceptor() MiddlewareInterceptor {
return func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
startTime := time.Now()
defer func() {
endTime := time.Now()
elapsedTime := endTime.Sub(startTime)
log.Println("Elapsed time:", elapsedTime)
}()
next(w, r)
}
}
func indexHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "some work here")
}
func main() {
// Chain of middleware to be invoked in order of their index
middlewareChain := MiddlewareChain{
NewReqIDInterceptor(),
ElapsedTimeInterceptor(),
}
router := mux.NewRouter()
// Invoke all middlewares for indexHandler
router.Path("/").Methods("GET").Handler(middlewareChain.Handler(indexHandler))
srv := &http.Server{
Addr: "0.0.0.0:8000",
Handler: router,
}
if err := srv.ListenAndServe(); err != nil {
fmt.Println(err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment