Go Middleware Vet

The http.Handler wrapper technique used in go middleware is a straightforward and elegant way to implement/extent your server functionality. Doing it wrong is far easier still.

Skip reading and check out what we made!

Why is it so hard to write a good http.Handler? Well http.HandlerFunc takes the http.ResponseWriter interface as an input, but secretly expects your instance of http.ResponseWrite to implement a couple other interfaces too and not always the same ones. It differs based on Go and Proto version.

Offending packages either stop entirely after implementing http.ResponseWriter or do not differentiate their implementation.

Why is this important? Let's take H2 Push, which is added in Go1.8 as an example. If your Go server supports HTTP2.0 and you are building against +Go1.8 you will have support for H2 Push by default. If however you also use a middleware handler that doesn't implement the http.Pusher interface, you will lose the ability to send any H2 Push Frames.

The composition of interfaces of an http.ResponseWriter has to match exactly across all used middleware handlers for a single request. Failing to do this might result in a loss of functionality, like H2 Push, or catastrophic failure. Conformance to io.ReaderFrom with an HTTP2.0 request is one of those more disastrous combinations.

When Go1.8 with support for H2 Push was announced we started looking how we could add it to our stack. We really like the cloudflare approach and started working on an http.Handler that took Link Headers and turned them into H2 Pushes. During development we noticed that incompatible middleware broke H2 Push and that our http.Handler broke the proxy. Third party middleware did not yet implement the http.Pusher interface and our middleware did implement the io.Reader interface, which it shouldn't for HTTP2.0 requests.

That is how Middleware Vet came to be. We suddenly had a need to easily and repeatedly test the middleware we use. A way to vet every http.Handler before it even goes to staging and re-test it daily it so we get notified when a breaking change is introduced.

We created a series of tests (with version specific build tags) to check the conformance of http.Handlers. Seperately we created a test runner application that runs these tests for commonly used middleware. These tests are run on Travis CI and the results are uploaded to Amazon S3. A call is made to our front-end after each run to update the results there.

The test package can be imported to validate your own middleware and you can also submit a PR to get listed on the overview. And yes we have shields for your readme.

Feedback and contributions are welcome.