0

I can't seem to work out how to use middleware and Http Router properly together.

My code is:

type appContext struct {
  db *mgo.Database
}

func main(){
  c := appContext{session.DB("db-name")}
  commonHandlers := alice.New(context.ClearHandler, basicAuthHandler)

  router := NewRouter()
  router.Post("/", commonHandlers.ThenFunc(c.final))

  http.ListenAndServe(":5000", router)
}

The final middleware is:

func (c *appContext) final(w http.ResponseWriter, r *http.Request) {
  log.Println("Executing finalHandler")
  w.Write([]byte("TESTING"))
}

but I want my basicAuthHandler to be part of the commonHandlers. It also needs the context so that I can query the db.

I have tried this:

func (c *appContext) basicAuthHandler(w http.ResponseWriter, r *http.Request) {
  var app App
  err := c.db.C("apps").Find(bson.M{"id":"abcde"}).One(&app)
  if err != nil {
    panic(err)
  }

  //do something with the app
}

but I get the error undefined: basicAuthHandler. I understand why I'm getting the error but I don't know how to avoid it. How can I provide the context to the basicAuthHandler and still use it in the commonHandlers list for Alice?

Zoyd
  • 3,449
  • 1
  • 18
  • 27
tommyd456
  • 10,443
  • 26
  • 89
  • 163

1 Answers1

1

Your middleware needs to have the signature

func(http.Handler) http.Handler

This way your middleware is wrapping handlers, not just providing a final handler. You need to accept an http.Handler, do whatever processing needs to be done, and call ServeHTTP on the next handler in the chain. Your basicAuthHandler example could look like this:

func (c *appContext) basicAuthHandler(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        var app App
        err := c.db.C("apps").Find(bson.M{"id": "abcde"}).One(&app)
        if err != nil {
            panic(err)
        }
        h.ServeHTTP(w, r)

    })
}

(though you don't want to panic in your app, and should provide a better error response)

JimB
  • 104,193
  • 13
  • 262
  • 255
  • Yeah I tried that but then I get: `cannot use c.basicAuthHandler (type func(http.ResponseWriter, *http.Request)) as type alice.Constructor in argument to alice.New` – tommyd456 May 19 '15 at 17:10
  • @tommyd456: sorry, I didn't look at what `alice` was, and thought your function signature was correct. `alice.New` takes an `alice.Contructor` as arguments – JimB May 19 '15 at 17:17
  • So is it not possible to do what I want to do? – tommyd456 May 19 '15 at 17:20
  • Sure, you just need to create a function matching the signature of `type Constructor func(http.Handler) http.Handler`. You can use `http.HandlerFunc` to convert functions to handlers if you need (or you can use `http.Handlers` instead). You want your middleware to be wrapper of a handler, no a final handler itself. I'll come back and try to explain in an answer if I have time. – JimB May 19 '15 at 17:24
  • Appreciate your help but do the handlers on the first line need to be `http.Handler`? – tommyd456 May 19 '15 at 18:33
  • The first line of the second code sample in your response that is. – tommyd456 May 19 '15 at 18:41