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:
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:
And we’d change the
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:
Although it might be a little bit more complex than the old function, its way easier to use:
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.
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:
And using it is just as straightforward:
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.