<p><pre><code> > a painless and even fun process
</code></pre>
This claim might be a little too optimistic. I'd like to challenge you (everyone) to associate a User object with an http.Request. Example code in Node.js/ExpressJS:<p><pre><code> function auth(req, res, next) {
req.User = User("username");
next();
}
</code></pre>
This is such a simple example of a useful piece of middleware, yet it is so difficult to implement in Go in a 'painless and fun' way.<p>I would prefer to avoid contention on a global mutex.<p>I would prefer to keep the compatibility with http.Handler and http.HandlerFunc.<p>Good luck!
The request context is I think the most annoying part of go http handling.<p>Oh you want to wrap your handler with something that does db.Begin()/db.Commit()? Well you need to stuff that tx somewhere...<p>so then your options are a global map[*http.Request]interface{} with mutexes or pass it as an arg. Passing it in as an arg means you either lose compile time type checking because you use reflect or lose the ability to add more middlewares that build up request context. The map[]interface{} also loses compile time type checking for the most part unless you do something per type of context, with more mutexes.<p>The second option is the sanest, but means either reflect if you have more than one context arg to build out (sql.Tx + cache + oauth grant + whatever else maybe?) or you have some common context object that may or may not use everything every request and your just adding more context members all the time that may or may not be initialized for that particular request.<p>Sometimes I miss the dynamic typing and/or compile time type templating.
I find the use of httptest.ResponseRecorder as well as the proposed context pattern not very elegant.<p>Just because go's HTTP entry point is an http.HandlerFunc, doesn't mean your middleware need to implement that same method. I'd prefer:<p><pre><code> type Middleware func(context *Context) Response
type Context struct {
Req *http.Request
Token string
}
type Response interface {
Status() int
....
}
</code></pre>
No global variable, and definitely no contention against that global.<p>(note, I'd make the middlewares nesteable, passing a next middleware to each middleware, but that wasn't covered in the article).
In the Ruby community, the Rack interface has done a lot to enable Web middleware to work together. It would be great if there were an analogous interface for Go's net/http.