Context-Aware Handler Chains in Go (using Stack)
Note: As of Go 1.7+ the context package is now part of Go's standard library and you should use that to pass data between your handlers. Joe Shaw has made a good tutorial here. If you're using a Go version < 1.7 then the information below may still be useful.
I've written a package for chaining context-aware handlers in Go, called Stack (view it on Github). It was heavily inspired by Alice.
What do you mean by 'context-aware'?
If you're using a middleware pattern to process HTTP requests in Go, you may want to share some data or context between middleware handlers and your application handlers. For example you might want to:
- Use some middleware to create a CRSF token, and later render the token to a template in your application handler. Or perhaps...
- Authenticate a user in one middleware handler, and then pass the user details to a second middleware handler which checks if the user is authorised to access the resource.
There are a few packages that can help with this. Matt Silverlock has written a good article about some of the different approaches and tools – I won't rehash it here, instead I recommend giving it a read.
Why make another package?
Because none of the existing tools seemed ideal – at least to me. Gorilla Context is simple and very flexible, but relies on a global context map and you remembering to clear the context after each request. (It's still my favourite though). Goji provides request-scoped context, which is good, but it's part of a larger package and ties you into using the Goji router. The same is true of Gocraft/web, which also relies on reflection tricks under the hood that I struggle to wrap my head around.
I realised that the only time you need to worry about context is when you're chaining handlers together. So I looked at my favorite tool for chaining handlers, Alice, and began adapting that to create Stack.
I wanted the package to:
- Do a simple job, and then get out of the way.
- Provide a request-scoped context map.
- Let you create stackable, reusable, handler chains in the Alice style.
- Be as type-safe at compile time as it possibly could be.
- Be simple to understand and non-magic.
- Operate nicely with existing standards. In particular:
- The handler chain must satisfy the
http.Handlerinterface, so it can be used with the
- It should be compatible with the
func(http.Handler) http.Handlerpattern commonly used by third-party middleware packages.
The full documentation for Stack is here, but here's a quick example of how to use it: