Search code examples
resthttpgobackendmux

How to pass a parameter to a MiddlewareFunc?


I'm working on a small demo that tries to explain how a basic HTTP handler works, and I found the following example:

package main

func router() *mux.Router {
    router := mux.NewRouter()
    auth := router.PathPrefix("/auth").Subrouter()
    auth.Use(auth.ValidateToken)
    auth.HandleFunc("/api", middleware.ApiHandler).Methods("GET")
    return router
}

func main() {
    r := router()
    http.ListenAndServe(":8080", r)
}
package auth

func ValidateToken(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        var header = r.Header.Get("secret-access-token")

        json.NewEncoder(w).Encode(r)
        header = strings.TrimSpace(header)

        if header == "" {
            w.WriteHeader(http.StatusForbidden)
            json.NewEncoder(w).Encode("Missing auth token")
            return
        }

        if header != "SecretValue" {
            w.WriteHeader(http.StatusForbidden)
            json.NewEncoder(w).Encode("Auth token is invalid")
            return
        }


        json.NewEncoder(w).Encode(fmt.Sprintf("Token found. Value %s", header))
        next.ServeHTTP(w, r)
    })
}
package middleware

func ApiHandler(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode("SUCCESS!")
    return
}

Everything is understandable, but it pop-out to my mind two questions:

  • Why it doesn't require to send a parameter in this line: secure.Use(auth.ValidateToken)?
  • If I wanted to send an extra parameter to this auth.ValidateToken func, (example, a string, for which this header should be compared instead of "SecretValue"), how can this be done?

Thanks in advance, I'm kind of new at using golang and wanted to learn more.


Solution

  • auth.Use takes a function as argument, and auth.ValidateToken is the function you pass. If you want to send an argument to auth.ValidateToken, you can write a function that takes that argument, and returns a middleware function, like this:

    func GetValidateTokenFunc(headerName string) func(http.Handler) http.Handler {
      return func(next http.Handler) http.Handler {
         return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            var header = r.Header.Get(headerName)
            ...
         }
      }
    }
    

    Then you can do:

        auth.Use(auth.GetValidateTokenFunc("headerName"))