Is there any way for adding a group to echo.Echo or echo.Group?
Issue Description
Hello everyone! Me and my team is now working for building a web api server, and we both have different apis. So I would like to divide different api by using echo.Group. I want to write a interface and let all developer implement it for their own need, And below is how I wanted(not actual code, won't work!)
main.go
var(
SubGroupSlice = make([]*echo.Group, 0)
)
func main() {
web := echo.New()
for _, g := range SubGroupSlice {
web.Group(g)
}
web.Start("0.0.0.0:80)
}
type CustomGroup interface{
AddGroup()
}
custom_group.go
func init(){
group := &MyGroup{ group: &echo.Group{} }
group.Build()
group.AddGroup()
}
type MyGroup struct {
group *echo.Group
}
func (g *MyGroup) Build() {
g.group.Use(XXX)
g.Get("/XXX", func(){ XXX })
}
func (g *MyGroup) AddGroup() {
SubGroupSlice = SubGroupSlice.append(g.group)
}
I know there's no such a echo.Echo.Group(g *echo.Group) function, so I want to know if there's any way to achieve this. This allow us to easily extend the web server without interfering existing code, and since init will executed before main(), all added group will be available.
Checklist
- [ Y ] Dependencies installed
- [ Y ] No typos
- [ Y ] Searched existing issues and docs
Expected behaviour
Some workaround to achieve this behavior
Actual behaviour
I haven't found any
Steps to reproduce
Null
Working code to debug
Null
Version/commit
Echo V4.9.0
I think maybe I could implement a copy of echo.Echo.Add() function but that may be too complex
And If it's no possible to achieve with echo.Echo, echo.Group will also help, I could just use this workaround shown below:
web := echo.New()
apiGroups := web.Group("/api")
// same as upper code
I do not think this will work - have you tested these inits? I think init is run before main() so the Echo instance that you are adding routes from groups would not exist yet.
anyway - you really should avoid using init() functions as they make your code harder to test and their execution order could cause problems for you. See https://www.google.com/search?q=golang+init+function+bad+practice
@aldas Yes, init() has many shortcomings but I would like no to change the add group part of codes every time I add a new group. I now expose the echo.Echo instance, and every subGroup's init() will do a concurrency for-loop to wait for the echo.Echo instance to create
I personally think you are doing it way too complicated way. I usually have "RegisterRoutes" function in package and I call it where Echo resides and if there are subgroup then they will be called inside their parent "RegisterRoutes" function
main.go
func main() {
e := echo.New()
root := e.Group("/api")
users.RegisterRoutes(root)
if err := e.Start(":8080"); err != http.ErrServerClosed {
e.Logger.Fatal(err)
}
}
Inside users package
func RegisterRoutes(parent *echo.Group) {
group := parent.Group("/users")
group.Use(middleware.RequestID())
group.GET("/:id", func(c echo.Context) error {
return c.JSON(http.StatusOK, map[string]string{"uid": "abc123"})
})
// Register /users/files/ routes
//files.RegisterRoutes(group)
}
Inside files package that is under users package
func RegisterRoutes(parent *echo.Group) {
group := parent.Group("/files")
group.GET("/report", func(c echo.Context) error {
return c.String(http.StatusOK, "ok")
})
}
In that way you can test your stuff normally and do not rely on global state and complexity that init brings
@aldas This also is a good way to achieve, I will try it out and comment the result! Thank for giving a advise!
@JobberRT if you got this sorted out could you close this issue, please.
@aldas Sorry, I've figured it out, forget to close this issue... My solution is to learn golang's init function and understand it, then I found a way to properly use the func init() to achieve my goal