I love Go. I love it’s simplicity, it’s static typing, it’s speed, it’s networking capabilities and how you can get libraries from GitHub with just one command without any further setup. But Go alone is often not enough, and you need something more, and that is where Gorilla Mux comes into place. The nature of Go often means you’re writing quite a bit more code than with other languages, but you get simplicity in return for that. To prevent some code from becoming way too big, I’ve been searching for an easy way of writing middleware for Gorilla, but most of the Google results involved implementing http.Handler or a different interface, which in my opinion is way too unwieldy when you can also use a very powerful feature of the Go programming language: the closure.

So what is middleware anyway?

In general, middleware is defined as software that sits between two other types of software, but in this context it means easily reusable pieces of code for HTTP request handling. You could for example think of setting certain headers, handling authentication, handling authorization, basically the stuff you need to do in every request, but don’t want to rewrite into every request handler. So let’s get started with a simple Gorilla Mux server:

package main

import (
  "fmt"
  "net/http"
  "github.com/gorilla/mux"
)

func indexHandler(res http.ResponseWriter, req *http.Request) {
  fmt.Fprint(res, "Hello, World!")
}

func main() {
  r := mux.NewRouter()
  r.HandleFunc("/", indexHandler)
  http.Handle("/", r)
  http.ListenAndServe(":8000", nil)
}

Let’s say we would like to implement some kind of security protocol, which sends a password through the Super-Duper-Safe-Security header. So, you’d implement a function to check for this header:

func checkSecurity(req *http.Request) (err error) {
  header := req.Header.Get("Super-Duper-Safe-Security")
  if header != "password" {
    err = errors.New("Invalid password")
    return
  }
  return
}

And we’d change the indexHander function:

func indexHandler(res http.ResponseWriter, req *http.Request) {
  if err := checkSecurity(req); err != nil {
    fmt.Fprint(res, err.Error())
    res.WriteHeader(http.StatusUnauthorized)
    return
  }
  fmt.Fprint(res, "Hello, World!")
}

So, that’s not too bad is it? It’s five extra lines of code, and with some smart rewriting we could minimize it to 4 (as you’ll always need an if statement to check whether the function should return). However, say we’d also want to check whether the user is authorized to do what he or she wants to do, and we want to log the request, and we want to add some response headers, we have four additional functions, which leads to 16 additional lines per HTTP hander. That’s a bit much if you ask me.

But how should we do it then?

We’ll use chainable closures to implement middleware behaviour. For these closures to be chainable, they have to accept another closure as the next one to execute. For illustration’s sake, I’ll add another security header, Even-Safer-Security, of which the password is only known at runtime, and put it in another handler. Let’s begin simple, with some middleware that doesn’t require any parameters:

func checkSecurityA(next httpHandlerFunc) httpHandlerFunc {
  return func(res http.ResponseWriter, req *http.Request) {
    header := req.Header.Get("Super-Duper-Safe-Security")
    if header != "password" {
      fmt.Fprint(res, "Invalid password")
      res.WriteHeader(http.StatusUnauthorized)
      return
    }
    next(res, req)
  }
}

Although it might be a little bit more complex than the old function, its way easier to use:

func indexHandler(res http.ResponseWriter, req *http.Request) {
  fmt.Fprint(res, "Hello, World!")
}

func main() {
  r := mux.NewRouter()
  r.HandleFunc("/", checkSecurityA(indexHandler))
  http.Handle("/", r)
  http.ListenAndServe(":8000", nil)
}

As you see, indexHandler doesn’t even have to care about the security protocol, and it’s extremely easy to see which handlers use what middleware as you don’t have to go to their function implementation everytime to check that.

Implementing Even-Safer-Security

So, our next piece of middleware requires a parameter, which is extremely easy to do because of the power of Go. You can just pass parameters into the enclosing middleware function that can be used in the handers they return:

func checkSecurityB(password string, next httpHandlerFunc) httpHandlerFunc {
  return func(res http.ResponseWriter, req *http.Request) {
    header := req.Header.Get("Even-Safer-Security")
    if header !=  password {
      fmt.Fprint(res, "Invalid password")
      res.WriteHeader(http.StatusUnauthorized)
      return
    }
    next(res, req)
  }
}

And using it is just as straightforward:

func main() {
  r := mux.NewRouter()
  r.HandleFunc("/", checkSecurityA(checkSecurityB("SaferPassword1234", (indexHandler))))
  http.Handle("/", r)
  http.ListenAndServe(":8000", nil)
}

Note how checkSecurityA and checkSecurityB can easily be chained by passing one as a parameter to the other. You can check out the entire source code here on Github Gist

And like that you see how we can use the power of Go and closures to create a very easy to use middleware system.