Middleware is a popular word used in the computing landscape nowadays, but do we even know what it means? According to Google, middleware is "software that acts as a bridge between an operating system or database and applications, especially on a network". Many web frameworks provide the idea of middleware in their HTTP layers and Go is no exception. As with our router we built in a previous article, making Go middleware is just as easy as implementing the ServeHTTP method in the net/http package.

package main

import (

type middleware struct {
  mux      http.Handler // for the router/mux. (Gorilla, httprouter, etc)
  handlers []http.HandlerFunc // middleware funcs to run.

func main() {
  mux := http.NewServeMux() // create a new http mux (router)
  mux.HandleFunc("/", barHandler) // add a route.
  m := New() // create some middleware
  m.Add(fooHandler, foo2Handler) // add our middleware functions.
  m.AddMux(mux) // add our router.
  http.ListenAndServe(":8080", m) // let's run this thing.

// Inits a new middleware chain.
func New() *middleware {
  return &middleware{handlers: make([]http.HandlerFunc, 0, 0)}

// Add adds a variable number of handlers using variadic arguments.
func (m *middleware) Add(h ...http.HandlerFunc) {
  m.handlers = append(m.handlers, h...)

// AddMux adds our mux to run.
func (m *middleware) AddMux(mux http.Handler) {
  m.mux = mux

// So we can satisfy the http.Handler interface.
func (m *middleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  for _, h := range m.handlers {
    h.ServeHTTP(w, r)
  m.mux.ServeHTTP(w, r)

func fooHandler(rw http.ResponseWriter, r *http.Request) {
  fmt.Println("running foo.")

func foo2Handler(rw http.ResponseWriter, r *http.Request) {
  fmt.Println("running foo 2.")

func barHandler(rw http.ResponseWriter, r *http.Request) {
  fmt.Println("running bar.")
  fmt.Fprint(rw, "bar!\n")

That's all there is to it! Like I said above, the magic all has to do with the ServeHTTP which satisfies the http.Handler interface. Obviously there a bunch of additions we do to this to make it production worth (move it into it's own package, add ways to stop the middleware chain at a certain point, convenience methods, etc), but all in all this should give us a basic idea of how middleware is setup in Go. As always, questions and comments are welcomed.

Blog Logo

Austin Cherry