echo icon indicating copy to clipboard operation
echo copied to clipboard

Is there any way for adding a group to echo.Echo or echo.Group?

Open JobberRT opened this issue 2 years ago • 6 comments

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

JobberRT avatar Sep 15 '22 08:09 JobberRT

I think maybe I could implement a copy of echo.Echo.Add() function but that may be too complex

JobberRT avatar Sep 15 '22 08:09 JobberRT

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 

JobberRT avatar Sep 15 '22 08:09 JobberRT

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 avatar Sep 15 '22 08:09 aldas

@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

JobberRT avatar Sep 15 '22 09:09 JobberRT

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 avatar Sep 15 '22 09:09 aldas

@aldas This also is a good way to achieve, I will try it out and comment the result! Thank for giving a advise!

JobberRT avatar Sep 15 '22 09:09 JobberRT

@JobberRT if you got this sorted out could you close this issue, please.

aldas avatar Oct 18 '22 08:10 aldas

@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

JobberRT avatar Oct 18 '22 09:10 JobberRT