1

Instead of writing every route under main(), like

func main() {
    e := echo.New()
    e.GET("/api", sayHello)
    e.GET("/api/music", getMusic)
    e.GET("/api/user/:id", getDetail)
    e.POST("/api/user", addUser)
    // ...
}

How can I import these all sub-routes from a file called api.go, and use those in the main function? Similar to

import "./API"
func main() {
    e := echo.New()
    e.UseSubroute(API.Routes) // <-- similar to this
    // ...
}
Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Valorad
  • 726
  • 1
  • 10
  • 20
  • 1
    Files are not importable, in Go you can only import packages. And also do not use relative imports. I would suggest you follow the recommendations from here: https://golang.org/doc/code.html – mkopriva Oct 01 '19 at 13:50
  • @mkopriva Here `api.go` is included in the package: `package API` – Valorad Oct 01 '19 at 13:55
  • 1
    I would also suggest you consider renaming your package (https://golang.org/doc/effective_go.html#package-names). That said, you can declare a function in your `API` package that takes `*echo.Echo` as its argument and does all the route-to-handler registering. – mkopriva Oct 01 '19 at 13:58
  • About package, I moved the source code to `src/`, ran `go mod init`, upload to Github, then I could use a canonical name starting with `github.com/username/myapp/API`. This feels terrible and very unnatural IMO, but this is Go, isn't it lol. – Valorad Oct 03 '19 at 03:32
  • with `go mod` *it is not* necessary to have your package in `src/`, without `go mod` *it is* necessary that your package is located in `$GOPATH/src`, however *it is not* necessary to upload your package to github. And also, although it is a convention when using GOPATH, *it is not* necessary that your package is located in `$GOPATH/src/github.com/user/repo`, something like `$GOPATH/src/api` and then `import "api"` will work as well. – mkopriva Oct 03 '19 at 06:10

3 Answers3

10

What you can do is use the echo.Group and pass it to the api package, and initialize the routes handler there.

package api

import (
    "github.com/labstack/echo"
)

func UseSubroute(group *echo.Group)  {
    group.GET("/", sayHello)
    group.GET("/music", getMusic)
    group.GET("/user/:id", getDetail)
    group.POST("/user", addUser)
}

and in the main you can just import your api package.

package main

import (
    "github.com/labstack/echo"
    "your-repo/path-to/api" // your api package
)

func main() {
    e := echo.New()
    apiGroup := e.Group("/api")
    api.UseSubroute(apiGroup)
    // ...
}
Andy
  • 449
  • 5
  • 13
2

The Echo object does not have this method. I think you need the code?

API.go:

package main

import "github.com/labstack/echo"

func UseSubroute(echo *echo.Echo)  {
    echo.GET("/api", sayHello)
    echo.GET("/api/music", getMusic)
    echo.GET("/api/user/:id", getDetail)
    echo.POST("/api/user", addUser)
}

main.go:

package main

import "github.com/labstack/echo"

func main() {
    e := echo.New()
    UseSubroute(e)
}

These two files need to be placed in the same directory.

Do you need it?

Valorad
  • 726
  • 1
  • 10
  • 20
Artikell
  • 74
  • 6
  • Thanks. This works for now. There is still a problem though when trying to achieve the same to `/api/user/xxx`. After all, it would be ugly to write `func UseSubroute()` in every sub-route file. – Valorad Oct 03 '19 at 03:25
1

Based on @Andy 's idea, I come up with a solution, that supports detachable nested routes.

The current folder structure is as follows:

.
├── routes
│   ├── index.go
│   └── music.go
└── server.go

...where server.go is the project main entry, belongs to the main package, while index.go and music.go belong to routes package.

The endpoints are

"/api"       -> index.go
"/api/music" -> music.go

First in index.go we define a function for using routes at this level.

func UseRoute(group *echo.Group, routes func(group *echo.Group)) {
    routes(group)
}

Then,

in server.go

func main() {
    e := echo.New()
    apiGroup := e.Group("/api")
    routes.ActivateIndex(mainGroup)
}

in index.go

var mainGroup *echo.Group
func ActivateIndex(g *echo.Group) {
    mainGroup = g
    UseRoute(mainGroup, IndexRoutes)

    // sub routes
    musicGroup := mainGroup.Group("/music")
    ActivateMusic(musicGroup)
}

and in music.go

var musicGroup *echo.Group
func ActivateMusic(g *echo.Group) {
    musicGroup = g
    UseRoute(musicGroup, MusicRoutes)
}

Note: IndexRoutes, MusicRoutes etc. are functions that specify endpoints at this level.

e.g.

func IndexRoutes(group *echo.Group) {
    group.GET("/", sayHello)
    group.GET("/user/:id", getDetail)
    group.POST("/user", addUser)
}

In this way, the routes can be defined in different .go files, making the business logic clearer.

For example, to extend the nested level, we can create another ActivateHiphop function in hiphop.go, also import the new sub-routes at ActivateMusic function from music.go, so that "/api/music/hiphop" can be pointed to hiphop.go.

p.s. To add more routes in /api level, just create more endpoints in IndexRoutes function.

Valorad
  • 726
  • 1
  • 10
  • 20