Somewhat inspired by this article last week, I'm toying with refactoring an application I have to more explicitly pass context (DB pools, session stores, etc) to my handlers.

However, one issue I'm having is that without a global templates map, the ServeHTTP method on my custom handler type (as to satisfy http.Handler ) can no longer access the map to render a template.

I need to either retain the global templates variable, or re-define my custom handler type as a struct.

Is there a better way to achieve this?

func.go

package main import ( "fmt" "log" "net/http" "html/template" "github.com/gorilla/sessions" "github.com/jmoiron/sqlx" "github.com/zenazn/goji/graceful" "github.com/zenazn/goji/web" ) var templates map[string]*template.Template type appContext struct { db *sqlx.DB store *sessions.CookieStore } type appHandler func(w http.ResponseWriter, r *http.Request) (int, error) func (ah appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // templates must be global for us to use it here status, err := ah(w, r) if err != nil { log.Printf("HTTP %d: %q", status, err) switch status { case http.StatusNotFound: // Would actually render a "http_404.tmpl" here... http.NotFound(w, r) case http.StatusInternalServerError: // Would actually render a "http_500.tmpl" here // (as above) http.Error(w, http.StatusText(status), status) default: // Would actually render a "http_error.tmpl" here // (as above) http.Error(w, http.StatusText(status), status) } } } func main() { // Both are 'nil' just for this example context := &appContext{db: nil, store: nil} r := web.New() r.Get("/", appHandler(context.IndexHandler)) graceful.ListenAndServe(":8000", r) } func (app *appContext) IndexHandler(w http.ResponseWriter, r *http.Request) (int, error) { fmt.Fprintf(w, "db is %q and store is %q", app.db, app.store) return 200, nil }

struct.go

package main import ( "fmt" "log" "net/http" "html/template" "github.com/gorilla/sessions" "github.com/jmoiron/sqlx" "github.com/zenazn/goji/graceful" "github.com/zenazn/goji/web" ) type appContext struct { db *sqlx.DB store *sessions.CookieStore templates map[string]*template.Template } // We need to define our custom handler type as a struct type appHandler struct { handler func(w http.ResponseWriter, r *http.Request) (int, error) c *appContext } func (ah appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { status, err := ah.handler(w, r) if err != nil { log.Printf("HTTP %d: %q", status, err) switch status { case http.StatusNotFound: // Would actually render a "http_404.tmpl" here... http.NotFound(w, r) case http.StatusInternalServerError: // Would actually render a "http_500.tmpl" here // (as above) http.Error(w, http.StatusText(status), status) default: // Would actually render a "http_error.tmpl" here // (as above) http.Error(w, http.StatusText(status), status) } } } func main() { // Both are 'nil' just for this example context := &appContext{db: nil, store: nil} r := web.New() // A little ugly, but it works. r.Get("/", appHandler{context.IndexHandler, context}) graceful.ListenAndServe(":8000", r) } func (app *appContext) IndexHandler(w http.ResponseWriter, r *http.Request) (int, error) { fmt.Fprintf(w, "db is %q and store is %q", app.db, app.store) return 200, nil }

Is there a cleaner way to pass the context instance to ServeHTTP ?

Note that go build -gcflags=-m shows that neither option appears to be worse in teams of heap allocation: the &appContext literal escapes to the heap (as expected) in both cases, although my interpretation is that the struct-based option does pass a second pointer (to context ) on each request—correct me if I'm wrong here as I'd love to get a better understanding of this.

I'm not wholly convinced that globals are bad in package main (i.e. not a lib) provided they are safe to use in that manner (read only/mutexes/a pool), but I do like clarity having to explicitly pass context provides.