/apollo

Context-aware middleware chains for golang web applications

Primary LanguageGoOtherNOASSERTION

Apollo

GoDoc

Apollo is a middleware-chaining helper for Golang web applications using google's net/context package. Apollo is a fork of Alice, modified to support passing the ctx context.Context param through middleware and HTTP handlers.

Apollo is meant to chain handler functions with this signature:

func (context.Context, http.ResponseWriter, *http.Request)

Relevant and influential articles:

Usage

apollo.New(Middleware1, Middlware2, Middleware3).With(ctx).Then(App)

Integration with http.Handler middleware

Apollo provides a Wrap function to inject normal http.Handler-based middleware into the chain. The context will skip over the injected middleware and pass unharmed to the next context-aware handler in the chain.

apollo.New(ContextMW1, apollo.Wrap(NormalMiddlware), ContextMW2).With(ctx).Then(App)

Motivation

Given a handler:

func HandlerOne(w http.ResponseWriter, r *http.Request) {}

We can serve it using the following:

http.HandleFunc("/one", HandlerOne)
// or http.Handle("/one", http.HandlerFunc(HandlerOne))

However, given a handler that expects a net/context:

func HandlerAlpha(ctx context.Context, w http.ResponseWriter, r *http.Request) {}

We would need to create a wrapper along the lines of:

func withContext(ctx context.Context, fn func(context.Context, http.ResponseWriter, *http.Request)) http.HandlerFunc {
  return func(w http.ResponseWriter, r *http.Request) {
    fn(ctx, w, r)
  }
}

and serve with:

ctx := context.Background()
http.Handle("/alpha", withContext(ctx, HandlerAlpha))

With this pattern, we can build nested middleware/handler calls that can be used with any net/http compatible router/mux. However, we can't use Alice for chaining because we no longer conform to the http.Handler interface that Alice expects.

Apollo enables Alice-style chaining of context-aware middleware and handlers.