The first code smell we encounter when writing a web application in Go is code duplication. Before processing the request, we will often need to log the request, convert app errors into HTTP 500 errors, authenticate users, etc. And we need to do most of these things for each handler.

Basics reminder

We create a very simple app from scratch with the net/httppackage of the standard library:

import (
  "net/http"
  "fmt"
)

func handler(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "Welcome!")
}

func main() {
  http.HandleFunc("/", handler)
  http.ListenAndServe(":8080", nil)
}

We have a function with 2 args: a response writer and a request. In addition to having a function, we can implement the http.Handler interface to any struct.

type handler struct {}

func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Welcome!")
}

func main() {
  http.Handle("/", handler)
  http.ListenAndServe(":8080", nil)
}

Any struct with the method ServeHTTP(http.ResponseWriter, *http.Request) will be implementing http.Handler and will be usable with the Go muxer (http.Handle(pattern, handler) function).

Adding logging

We now want to add a simple log of the time spent to process each request:

func indexHandler(w http.ResponseWriter, r *http.Request) {
  t1 := time.Now()
  fmt.Fprintf(w, "Welcome!")
  t2 := time.Now()
  log.Printf("[%s] %q %v\\n", r.Method, r.URL.String(), t2.Sub(t1))
}

func main() {
  http.HandleFunc("/", indexHandler)
  http.ListenAndServe(":8080", nil)
}

Easy enough. Here's what it will output:

[GET] / 1.43ms
[GET] /about 1.98ms

Now we add a second handler because, let's face it, there are not many apps with only one route.

func aboutHandler(w http.ResponseWriter, r *http.Request) {
  t1 := time.Now()
  fmt.Fprintf(w, "You are on the about page.")
  t2 := time.Now()
  log.Printf("[%s] %q %v\\n", r.Method, r.URL.String(), t2.Sub(t1))
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
  t1 := time.Now()
  fmt.Fprintf(w, "Welcome!")
  t2 := time.Now()
  log.Printf("[%s] %q %v\\n", r.Method, r.URL.String(), t2.Sub(t1))
}

func main() {
  http.HandleFunc("/about", aboutHandler)
  http.HandleFunc("/", indexHandler)
  http.ListenAndServe(":8080", nil)
}

Code duplication detected! We could create a function with a closure. But if we have multiple functions like that, it will become as bad as callback spaghetti in Javascript. We don't want that.

Chaining handlers

We want something like the middleware systems of Rack, Ring, Connect.js and other similar solutions. What we would like is to chain multiple handlers. We already have this kind of handlers in the standard library: http.StripPrefix(prefix, handler)and http.TimeoutHandler(handler, duration, message). They both take a handler as one of their arguments and they both return a handler. So we can write a handler and pass another handler to it.

loggingHandler(recoverHandler(indexHandler))

So a middleware would be something like func (http.Handler) http.Handler This way we pass a handler and returns a handler. At the end we have one handler and can be called with http.Handle(pattern, handler)

func main() {
  http.Handle("/", loggingHandler(recoverHandler(indexHandler)))
  http.ListenAndServe(":8080", nil)
}