mbudge
mbudge

Reputation: 557

Go Gorilla Mux MiddlewareFunc with r.Use and returning errors

How do you set up Gorilla Mux r.Use to return errors down the middleware chain? https://godoc.org/github.com/gorilla/mux#Router.Use

Main.go

r := mux.NewRouter()

r.Use(LoggingFunc)
r.Use(AuthFunc)

Basic middleware

Starts with logging middleware which can catch and handle errors from further down the chain

type HandlerFunc func(w http.ResponseWriter, r *http.Request) error

func LoggingFunc(next HandlerFunc) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // Logging middleware

        defer func() {
            if err, ok := recover().(error); ok {
                w.WriteHeader(http.StatusInternalServerError)
            }
        }()

        err := next(w, r)
        if err != nil {
            // log error
        }
    })
}

The next middleware handles authentication and returns an error to the logging middleware.

func AuthFunc(next HandlerFunc) HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) error {

        if r.GET("JWT") == "" {
            return fmt.Errorf("No JWT")
        }

        return next(w, r)
    }
}

I keep getting errors like

  cannot use AuthFunc (type func(handlers.HandlerFunc) http.Handler) as type mux.MiddlewareFunc in argument to r.Use

Thanks

Upvotes: 0

Views: 4633

Answers (1)

Shalauddin Ahamad Shuza
Shalauddin Ahamad Shuza

Reputation: 3657

According to the mux.Use doc its argument type is MiddlewareFunc which return type is http.Handler not error type. You have to define which return type is http.HandlerFunc

type Middleware func(http.HandlerFunc) http.HandlerFunc

func main() {
    r := mux.NewRouter()

    //  execute middleware from right to left of the chain
    chain := Chain(SayHello, AuthFunc(), LoggingFunc())
    r.HandleFunc("/", chain)

    println("server listening :  8000")
    http.ListenAndServe(":8000", r)
}

// Chain applies middlewares to a http.HandlerFunc
func Chain(f http.HandlerFunc, middlewares ...Middleware) http.HandlerFunc {
    for _, m := range middlewares {
        f = m(f)
    }
    return f
}

func LoggingFunc() Middleware {
    return func(next http.HandlerFunc) http.HandlerFunc {
        return func(w http.ResponseWriter, r *http.Request) {
            // Loggin middleware

            defer func() {
                if _, ok := recover().(error); ok {
                    w.WriteHeader(http.StatusInternalServerError)
                }
            }()

            // Call next middleware/handler in chain
            next(w, r)
        }
    }
}

func AuthFunc() Middleware {
    return func(next http.HandlerFunc) http.HandlerFunc {
        return func(w http.ResponseWriter, r *http.Request) {

            if r.Header.Get("JWT") == "" {
                fmt.Errorf("No JWT")
                return
            }

            next(w, r)
        }
    }

}

func SayHello(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "Hello client")
}

It will execute the LogginFunc then AuthFunc and then SayHello method which is your desire method after passing all those middlewares.

Upvotes: 3

Related Questions