I can come up with a couple of approaches to do this.
Context transfer
you can change the signature first to accept the context
type appHandler func(http.ResponseWriter, *http.Request, context.Context) *appError func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if e := fn(w, r, nil); e != nil { // e is *appError, not os.Error. http.Error(w, e.Message, e.Code) } }
Now I assume that AuthHandler has to do with authenticating and setting up a user in the context of an object.
What you can do is create another type handler that sets the context. like this
type authHandler func(http.ResponseWriter, *http.Request, context.Context) *appError func (fn authHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
So you can use it as follows
func init() { http.Handle("/view", appHandler(viewRecord))
This is the complete code.
package main import ( "fmt" "net/http" "code.google.com/p/go.net/context" ) type appError struct { Error error Message string Code int } type key int const userIdKey key = 0 type appHandler func(http.ResponseWriter, *http.Request, context.Context) *appError func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if e := fn(w, r, nil); e != nil { // e is *appError, not os.Error. http.Error(w, e.Message, e.Code) } } type authHandler func(http.ResponseWriter, *http.Request, context.Context) *appError func (fn authHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // setup authentication here uid := 1 // setup the context the way you want parent := context.TODO() ctx := context.WithValue(parent, userIdKey, uid) if e := fn(w, r, ctx); e != nil { // e is *appError, not os.Error. http.Error(w, e.Message, e.Code) } } func viewRecord(w http.ResponseWriter, r *http.Request, c context.Context) *appError { if c == nil { fmt.Fprintf(w, "User are not logged in") } else { uid := c.Value(userIdKey) fmt.Fprintf(w, "User logged in with uid: %d", uid) } return nil } func init() { http.Handle("/view", appHandler(viewRecord)) // viewRecord is an appHandler function http.Handle("/viewAuth", authHandler(viewRecord)) // viewRecord is an authHandler function } func main() { http.ListenAndServe(":8080", nil) }
create map context
Instead of passing context, you create
var contexts map[*http.Request]context.Context
and get the context in view using contexts[r] .
But because the card is not thread safe, access to the card must be protected by the mutex.
And guess what, this is what the gorilla context does for you, and I think itβs better suited to
https://github.com/gorilla/context/blob/master/context.go#l20-28
this is the full code
package main import ( "fmt" "net/http" "github.com/gorilla/context" ) type appError struct { Error error Message string Code int } type key int const userIdKey key = 0 type appHandler func(http.ResponseWriter, *http.Request) *appError func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if e := fn(w, r); e != nil { // e is *appError, not os.Error. http.Error(w, e.Message, e.Code) } } type authHandler func(http.ResponseWriter, *http.Request) *appError func (fn authHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // setup authentication here uid := 1 context.Set(r, userIdKey, uid) if e := fn(w, r); e != nil { // e is *appError, not os.Error. http.Error(w, e.Message, e.Code) } } func viewRecord(w http.ResponseWriter, r *http.Request) *appError { if uid, ok := context.GetOk(r, userIdKey); !ok { fmt.Fprintf(w, "User are not logged in") } else { fmt.Fprintf(w, "User logged in with uid: %d", uid) } return nil } func init() { http.Handle("/view", appHandler(viewRecord)) // don't require authentication http.Handle("/viewAuth", authHandler(viewRecord)) // require authentication } func main() { http.ListenAndServe(":8080", nil) }
you can also choose a wrapper function instead of a type function for auth
func AuthHandler(h appHandler) appHandler { return func(w http.ResponseWriter, r *http.Request) *appError { // setup authentication here uid := 1 context.Set(r, userIdKey, uid) return h(w, r) } } func init() { http.Handle("/view", appHandler(viewRecord)) // don't require authentication http.Handle("/viewAuth", appHandler(AuthHandler(viewRecord))) // require authentication }