echo
echo copied to clipboard
Apply Middleware to a path (group, route, etc.)
Issue Description
Hey guys, I just switched from gin to echo, and I am having an issue. How do I apply a middleware to a specific group (route). I couldn't find any reference to this in the docs either.
Expected behaviour
MIddleware should only be applied to the userGroup ("/users/*")
Actual behaviour
MIddleware is applied to all routes
userGroup := e.Group("/users")
{
userGroup.Use(middleware.CheckPermissions)
userGroup.GET("/:id", userController.GetByID)
}
e.GET("/self", userController.GetSelf)
Third argument for route can be middleware(s)
https://github.com/labstack/echo/blob/b065180250530e6434de09ae5a2e4443dc7cb210/echo.go#L412
same way can be used for group also https://github.com/labstack/echo/blob/b065180250530e6434de09ae5a2e4443dc7cb210/echo.go#L552
As aldas said you just need to pass the middleware as additional argument to the group function:
e := echo.New()
e.GET("/self", userController.GetSelf)
// Guard group /users with middleware.CheckPermissions
userGroup := e.Group("/users", middleware.CheckPermissions)
userGroup.GET("/:id", userController.GetByID)
Please close if that works for you.
I can't reproduce the issue as I am able to use a middleware to a specific group. I am using echo v4 (github.com/labstack/echo/v4).
e := echo.New()
...
// Unauthenticated routes
publicRoutes := e.Group("/v1")
{
publicRoutes.GET("/login", func(c echo.Context) error {
return c.HTML(http.StatusOK, login)
})
}
// Restricted routes
protectedRoutes := e.Group("/v1")
{
config := middleware.JWTConfig{
KeyFunc: handlers.GetKey, // https://github.com/labstack/echo/issues/1731
}
protectedRoutes.Use(middleware.JWTWithConfig(config))
protectedRoutes.POST("/auth", handlers.Login)
user := protectedRoutes.Group("/user")
{
user.GET("/:id", handlers.GetUser)
user.POST("", handlers.CreateUser)
user.PUT("", handlers.UpdateUser)
user.DELETE("/:id", handlers.DeleteUser)
}
}
Another example can be found on: https://echo.labstack.com/cookbook/jwt
e := echo.New()
// Middleware
e.Use(middleware.Logger())
e.Use(middleware.Recover())
// Login route
e.POST("/login", login)
// Unauthenticated route
e.GET("/", accessible)
// Restricted group
r := e.Group("/restricted")
r.Use(middleware.JWT([]byte("secret")))
r.GET("", restricted)
@BubbaJoe I guess with the comments it should work for you. So please let us know and close if you get it working.
Nice! it works here too 🚀
I have a strange behaviour with version 4.5.0
the Middleware is only applied if there is an exact match of the url defined in the Group, it is not working.
r := e.Group("/restricted")
doing a call with url /restricted works but /restricted/test does not
Could you provide example? For some cases with routes the order how routing is set up is important.
When group is created it registers prefix and prefix* routes with 404handler with given middlewares.
https://github.com/labstack/echo/blob/7f502b1ff10913aeab28abab64f2bf45952c768d/group.go#L21-L30
For example modify this to reproduce your problematic situation:
func main() {
e := echo.New()
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, c.Path())
})
g := e.Group("/group")
g.Use(middleware.JWT([]byte("secret")))
g.GET("/test", func(c echo.Context) error {
return c.String(http.StatusOK, c.Path())
})
if err := e.Start(":8088"); err != http.ErrServerClosed {
log.Fatal(err)
}
}
I have done further tests. I used oapi-codegen to generate from an OpenAPI spec all the routes and I suspect the problem may be caused there. I have not created the routes directly from Echo.
If I specify the exact path of the route, the Middleware applied by the Group does not get applied, but if I specify a different path the Middleware is invoked correctly.
This is from the generated code in the web app
func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
wrapper := ServerInterfaceWrapper{
Handler: si,
}
router.POST(baseURL+"/test/:id/", wrapper.PostTest)
}
and this is the code from the webapp
e := echo.New()
e.Use(middleware.Recover())
api.RegisterHandlersWithBaseURL(e, a, "/v1")
e.Group("/v1", firebaseAuthMidl)
A note, if the Middleware is global, it works well
This user has a similar issue https://github.com/deepmap/oapi-codegen/issues/55
api.RegisterHandlersWithBaseURL(e, a, "/v1")
e.Group("/v1", firebaseAuthMidl)
These two things are completely different. Group in Echo is basically helper that sets prefix and middlewares to routes when you add them though group instance. Every route that is added out of group is different. They do not share middlewares.
maybe something like that works
g := e.Group("/v1", firebaseAuthMidl)
api.RegisterV1Routes(g, a)
where RegisterV1Routes is:
func RegisterV1Routes(router EchoRouter, si ServerInterface) {
wrapper := ServerInterfaceWrapper{
Handler: si,
}
router.POST("/:id", wrapper.PostTest) // this path will be `/v1/:id`
}
in that case you are adding that post route to group and that group should have /v1 and /v1/* ANY routes registered with 404 handler.
No further comments, closing.