gogorilla

Why can't I chain a `Use()` with `HandleFunc()` while setting up middleware in Gorilla/mux?


I am trying to add a simple user ID validation middleware to a route like so:

api package contains:

func RegisterUserRoutes(router *mux.Router) {

    router.HandleFunc("/{id}/follower/{follower_id}", user.AddFollower).Methods("POST")
    router.HandleFunc("/{id}", user.EditUser).Methods("PUT")
    router.HandleFunc("/{id}", user.GetUserByID).Methods("GET")
    router.HandleFunc("/", user.GetUser).Methods("GET")
    router.HandleFunc("/{id}/blog", user.GetBlogs).Methods("GET")
    router.HandleFunc("/{id}/blog_feed", user.GetBlogFeed).Methods("GET")

    //Trying to add middleware here
    router.HandleFunc("/{id}", user.DeleteUserByID).Methods("DELETE").Subrouter().Use(middleware.ValidateUserID)

    router.HandleFunc("/{id}/follower/{follower_id}", user.RemoveFollower).Methods("DELETE")
}

main.go

userRouter := r.PathPrefix("/user").Subrouter()

//A global middleware that validates the JWT included with the request
userRouter.Use(middleware.AuthMiddleware)

api.RegisterUserRoutes(userRouter)

When I test the endpoint in Postman, I'm getting a 404 not found error. It seems chaining the Use() with a HandleFunc() renders Gorilla/mux unable to match the route altogether. How do I add middleware to specific routes with specific http methods?


Solution

  • //Trying to add middleware here
    router.HandleFunc("/{id}", user.DeleteUserByID).Methods("DELETE").Subrouter().Use(middleware.ValidateUserID)
    

    You are creating a Subrouter() but not adding any Routes, so, any request to the Subrouter will result in a Not Found, because there is nothing to find in the Subrouter. You could do something like the following (playground - simplifying a little):

    func RegisterUserRoutes(router *mux.Router) {
        r := router.Path("/{id}").Subrouter()
        r.Use(middlewareTwo)
        r.HandleFunc("", func(w http.ResponseWriter, _ *http.Request) { w.Write([]byte("test function 2\n")) })
    }
    

    The following would also work but the initial Handlefunc will not be called so it's a bit pointless (playground):

    func RegisterUserRoutes(router *mux.Router) {
        r := router.
            HandleFunc("/{id}", func(w http.ResponseWriter, _ *http.Request) { w.Write([]byte("first HandleFunc\n")) }).
            Methods("GET").
            Subrouter()
        r.Use(middlewareTwo)
        r.HandleFunc("", func(w http.ResponseWriter, _ *http.Request) { w.Write([]byte("not found handler2\n")) })
    }