0

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

1
  • 2
    AuthFunc should return http.Handler and not HandlerFunc type Commented Jan 30, 2019 at 15:43

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.