I want to wire RecoverWrap
to all handlers of martini routes to make any panic
be finished by code inside RecoverWrap
.
I tried to do it like m.Use(RecoverWrap)
but do not know how to do it exactly, it fails on compile.
package main
import (
"errors"
"github.com/go-martini/martini"
"net/http"
)
func main() {
m := martini.Classic()
//m.Use(RecoverWrap)
m.Get("/", func() {
panic("some panic")
})
m.Run()
}
func RecoverWrap(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
var err error
defer func() {
r := recover()
if r != nil {
switch t := r.(type) {
case string:
err = errors.New(t)
case error:
err = t
default:
err = errors.New("Unknown error")
}
http.Error(w, "Something goes wrong", http.StatusInternalServerError)
}
}()
h.ServeHTTP(w, req)
})
}
Middleware handlers in Martini do not get to "wrap" other handler calls, so http.Handler is not found by the injector.
What you can do is use context.Next():
package main
import (
"errors"
"github.com/go-martini/martini"
"net/http"
)
func main() {
m := martini.Classic()
m.Use(RecoverWrap)
m.Get("/", func() {
panic("some panic")
})
m.Run()
}
func RecoverWrap(c martini.Context, w http.ResponseWriter) {
var err error
defer func(w http.ResponseWriter) {
r := recover()
if r != nil {
switch t := r.(type) {
case string:
err = errors.New(t)
case error:
err = t
default:
err = errors.New("Unknown error")
}
http.Error(w, "Something goes wrong", http.StatusInternalServerError)
}
}(w)
c.Next()
}
You will have to make sure that your error handler is the first middleware registered, or those handlers running before will not be caught.
Actually, the same method is implemented in martini.Recovery:
https://github.com/go-martini/martini/blob/6241001738f6e1b1ea7c4a4089195e1b0681609a/recovery.go#L115