codegangsta/martini — pull request #194 by BurntSushi (2014-03-04 22:09:53+00:00)
Title: fix: cannot access Routes service in middleware using Classic martini

Here is a small example showing the problem:

```go
package main

import (
"fmt"
"log"

"github.com/codegangsta/martini"
)

func main() {
m := martini.Classic()
m.Use(func(lg *log.Logger, routes martini.Routes) {
log.Println(routes.MethodsFor("/"))
})
m.Get("/", func(routes martini.Routes) string {
return fmt.Sprintf("%#v", routes.MethodsFor("/"))
})
m.Run()
}
```

From [the documentation](https://github.com/codegangsta/martini#service-injection), I'd expect this to log `[]string{"GET"}` and output it as a web page. Instead, I get a panic:

```
[andrew@Liger go] go run martini_routes.go
[martini] listening on :3000
[martini] Started GET /
[martini] PANIC: Value not found for type martini.Routes
/home/andrew/go/src/github.com/codegangsta/martini/martini.go:163 (0x43bea8)
(*context).run: panic(err)
/home/andrew/go/src/github.com/codegangsta/martini/martini.go:152 (0x43bdcb)
(*context).Next: c.run()
/home/andrew/go/src/github.com/codegangsta/martini/recovery.go:140 (0x43f9e6)
func.004: c.Next()
/usr/lib/go/src/pkg/runtime/asm_amd64.s:339 (0x423e32)
call32: CALLFN(call32, 32)
/usr/lib/go/src/pkg/reflect/value.go:474 (0x45f55b)
Value.call: call(fn, ptr, uint32(size))
/usr/lib/go/src/pkg/reflect/value.go:345 (0x45e64d)
Value.Call: return v.call("Call", in)
/home/andrew/go/src/github.com/codegangsta/inject/inject.go:102 (0x4a9924)
(*injector).Invoke: return reflect.ValueOf(f).Call(in), nil
/home/andrew/go/src/github.com/codegangsta/martini/martini.go:161 (0x43be72)
(*context).run: _, err := c.Invoke(c.handler())
/home/andrew/go/src/github.com/codegangsta/martini/martini.go:152 (0x43bdcb)
(*context).Next: c.run()
/home/andrew/go/src/github.com/codegangsta/martini/logger.go:16 (0x43f288)
func.001: c.Next()
/usr/lib/go/src/pkg/runtime/asm_amd64.s:340 (0x423e92)
call64: CALLFN(call64, 64)
/usr/lib/go/src/pkg/reflect/value.go:474 (0x45f55b)
Value.call: call(fn, ptr, uint32(size))
/usr/lib/go/src/pkg/reflect/value.go:345 (0x45e64d)
Value.Call: return v.call("Call", in)
/home/andrew/go/src/github.com/codegangsta/inject/inject.go:102 (0x4a9924)
(*injector).Invoke: return reflect.ValueOf(f).Call(in), nil
/home/andrew/go/src/github.com/codegangsta/martini/martini.go:161 (0x43be72)
(*context).run: _, err := c.Invoke(c.handler())
/home/andrew/go/src/github.com/codegangsta/martini/martini.go:69 (0x43b2f3)
(*Martini).ServeHTTP: m.createContext(res, req).run()
/usr/lib/go/src/pkg/net/http/server.go:1597 (0x495a4e)
serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
/usr/lib/go/src/pkg/net/http/server.go:1167 (0x493a57)
(*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
/usr/lib/go/src/pkg/runtime/proc.c:1394 (0x417620)
goexit: runtime·goexit(void)
[martini] Completed 500 Internal Server Error in 2.49905ms
```

If you remove the middleware, then `[]string{"GET"}` is shown as a web page, as expected.

From looking at the code, it seems like this is because the `martini.Routes` service is *only* injected when a route is handled. Since a middleware occurs independently of a route being handled, the `martini.Routes` service is never injected. Hence the panic.

So to fix it, I've simply injected the `martini.Routes` service in `martini.Classic`. I don't think this solution is ideal, since this means the only way to use the `martini.Routes` service in middleware is to call `martini.Classic`. As an **alternative**, what if the `martini.Routes` service was exposed like the `Logger`, `Recovery` and `Static` services?

I think this is related to #176.