Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

URL params are not available inside middleware on the root router #892

Open
dennisvanderweide opened this issue Jan 4, 2024 · 6 comments

Comments

@dennisvanderweide
Copy link

dennisvanderweide commented Jan 4, 2024

When I create a middleware to log the id URL parameter, which exists in the route I request, the value is always empty. I do get a value inside the handler itself

r := chi.NewRouter()

r.Use(func(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		id := chi.URLParam(r, "id")
		log.Println(id)
		h.ServeHTTP(w, r)
	})
})

r.Get("/test/{id}", func(w http.ResponseWriter, r *http.Request) {
	id := router.Param(r, "id").String()
	io.WriteString(w, id)
})

When I move this code to a Group, the URL param will become available inside the middleware.

r := chi.NewRouter()

r.Group(func(r chi.Router) {
	r.Use(func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			id := chi.URLParam(r, "id")
			log.Println(id)
			h.ServeHTTP(w, r)
		})
	})

	r.Get("/test/{id}", func(w http.ResponseWriter, r *http.Request) {
		id := router.Param(r, "id").String()
		io.WriteString(w, id)
	})
})

I think this behavior is quite strange and prone to errors

Tested with the latest version (5.0.11)

@erwinschaap
Copy link

I have the same issue

@sakthi-lucia0567
Copy link

This behavior is due to the way the chi router handles middleware and route patterns. When you register a middleware using r.Use() at the root level, the middleware is applied to all routes, including routes that do not have any URL parameters. As a result, when the middleware tries to extract the "id" parameter using chi.URLParam(r, "id"), it doesn't find it because the current route doesn't have an "id" parameter.

@dennisvanderweide
Copy link
Author

The behavior you describe would be what I would expect to be the behavior, but the problem is that when I execute an HTTP request for a route which does have an id parameter, it won't be able to find the parameter even though the route does contain a parameter.

@ning-kang
Copy link

ning-kang commented May 26, 2024

mx.URLParams gets populated only at the routeHTTP function which will not get the id param if your middleware is at the top level (* route). Try this instead:

v1Router := chi.NewRouter()
v1Router.Route("/test/{id}", func(r chi.Router) {
	r.Use(Middleware)
	r.Get("/", handler.getHandler)
	r.Patch("/", handler.updateHandler)
	r.Delete("/", handler.deleteHandler)
})

@jfcdigitalventures
Copy link

Thanks! That works but is super optimal. I need to repeat the middleware call for every endpoint group.

Example:

v1Router := chi.NewRouter()
v1Router.Route("/test/{id}", func(r chi.Router) {
	r.Use(Middleware)
	r.Get("/", handler.getHandler)
	r.Patch("/", handler.updateHandler)
	r.Delete("/", handler.deleteHandler)
})

v1Router := chi.NewRouter()
v1Router.Route("/another-test/{id}", func(r chi.Router) {
	r.Use(Middleware)
	r.Get("/", handler.getHandler)
	r.Patch("/", handler.updateHandler)
	r.Delete("/", handler.deleteHandler)
})

That is a problem because I want to ensure that the middleware (authZ) is called on every request. Do I miss anything here or is there a better way to get the URL params in the middleware (I need the params to make a call on the authZ).

@dennisvanderweide
Copy link
Author

When I create a middleware to log the id URL parameter, which exists in the route I request, the value is always empty. I do get a value inside the handler itself

r := chi.NewRouter()

r.Use(func(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		id := chi.URLParam(r, "id")
		log.Println(id)
		h.ServeHTTP(w, r)
	})
})

r.Get("/test/{id}", func(w http.ResponseWriter, r *http.Request) {
	id := router.Param(r, "id").String()
	io.WriteString(w, id)
})

When I move this code to a Group, the URL param will become available inside the middleware.

r := chi.NewRouter()

r.Group(func(r chi.Router) {
	r.Use(func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			id := chi.URLParam(r, "id")
			log.Println(id)
			h.ServeHTTP(w, r)
		})
	})

	r.Get("/test/{id}", func(w http.ResponseWriter, r *http.Request) {
		id := router.Param(r, "id").String()
		io.WriteString(w, id)
	})
})

I think this behavior is quite strange and prone to errors

Tested with the latest version (5.0.11)

@jfcdigitalventures You could wrap everything in a Group just like in my example here, but it's a workaround, not a fix.
I still think it's weird that a middleware on the root behaves different than middleware on every other level. My suggestion would be to fix this, so this behaviour will be the same whenever you use a middleware.

JRaspass added a commit to code-golf/code-golf that referenced this issue Sep 4, 2024
We must wrap the affected routes in a Group with the middleware applied
to that group, moving the middleware higher doesn't work. See
go-chi/chi#892 for details.

This lays the groundwork for future hole/lang renames like Lisp → Common
Lisp.

Updates #1318
Yewzir pushed a commit to Yewzir/code-golf that referenced this issue Dec 14, 2024
We must wrap the affected routes in a Group with the middleware applied
to that group, moving the middleware higher doesn't work. See
go-chi/chi#892 for details.

This lays the groundwork for future hole/lang renames like Lisp → Common
Lisp.

Updates code-golf#1318
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants