如何组织Gorilla Mux的路由?

huangapple go评论68阅读模式
英文:

how to organize gorilla mux routes?

问题

你好!你想将路由声明拆分到多个文件中,这样做是可行的。你可以按照以下步骤进行操作:

  1. 创建一个名为routes的文件夹,用于存放你的路由文件。
  2. routes文件夹中创建多个文件,每个文件对应一个路由组。
  3. 在每个路由文件中,导入必要的包(如fmtnet/http等)和github.com/gorilla/mux
  4. 在每个路由文件中,定义对应的路由处理函数。
  5. main.go文件中,导入routes包,并在main函数中使用router对象来注册路由。

下面是示例代码:

// main.go
package main

import (
    "fmt"
    "github.com/gorilla/mux"
    "net/http"
    "NovAPI/routes"
)

func main() {
    router := mux.NewRouter().StrictSlash(true)

    // 注册路由
    routes.RegisterHelloRoute(router)
    routes.RegisterUserRoute(router)
    routes.RegisterRoute2(router)
    routes.RegisterRoute3(router)

    // 其他路由声明继续在这里添加

    http.ListenAndServe(":1128", router)
}
// routes/hello.go
package routes

import (
    "fmt"
    "net/http"
    "github.com/gorilla/mux"
)

func RegisterHelloRoute(router *mux.Router) {
    router.HandleFunc("/hello", func(res http.ResponseWriter, req *http.Request) {
        fmt.Fprintln(res, "Hello")
    })
}
// routes/user.go
package routes

import (
    "fmt"
    "net/http"
    "github.com/gorilla/mux"
)

func RegisterUserRoute(router *mux.Router) {
    router.HandleFunc("/user", func(res http.ResponseWriter, req *http.Request) {
        fmt.Fprintln(res, "User")
    })
}
// routes/route2.go
package routes

import (
    "fmt"
    "net/http"
    "github.com/gorilla/mux"
)

func RegisterRoute2(router *mux.Router) {
    router.HandleFunc("/route2", func(res http.ResponseWriter, req *http.Request) {
        fmt.Fprintln(res, "Route2")
    })
}
// routes/route3.go
package routes

import (
    "fmt"
    "net/http"
    "github.com/gorilla/mux"
)

func RegisterRoute3(router *mux.Router) {
    router.HandleFunc("/route3", func(res http.ResponseWriter, req *http.Request) {
        fmt.Fprintln(res, "Route3")
    })
}

你可以根据需要在routes文件夹中创建更多的路由文件,并在main.go中注册它们。这样,你的路由声明就会被拆分到多个文件中,使代码更加有组织性。希望对你有帮助!

英文:

i am using Gorilla Mux for writing a REST API and i am having trouble organizing my routes, currently all of my routes are defined in the main.go file like this

//main.go
package main

import (
    "NovAPI/routes"
    "fmt"
    "github.com/gorilla/mux"
    "net/http"
)

func main() {

    router := mux.NewRouter().StrictSlash(true)

    router.HandleFunc("/hello", func(res http.ResponseWriter, req *http.Request) {
        fmt.Fprintln(res, "Hello")
    })

    router.HandleFunc("/user", func(res http.ResponseWriter, req *http.Request) {
        fmt.Fprintln(res, "User")
    })

    router.HandleFunc("/route2", func(res http.ResponseWriter, req *http.Request) {
        fmt.Fprintln(res, "Route2")
    })

    router.HandleFunc("/route3", func(res http.ResponseWriter, req *http.Request) {
        fmt.Fprintln(res, "Route3")
    })

    // route declarations continue like this

    http.ListenAndServe(":1128", router)

}

so what i want to do is take out and split this route declaration into multiple files, how would i go about doing that? thanks in advance.

答案1

得分: 23

你可以将路由器模块化为不同的包,并将它们挂载到主路由器上。

对于以下问题的详细说明,你可以采用以下方法,使其具有相当的可扩展性(并且在某种程度上更容易进行测试)。

/api/router.go

package api

import (
	"net/http"

	"github.com/gorilla/mux"
)

func Router() *mux.Router {
	router := mux.NewRouter()
	router.HandleFunc("/", home)
	return router
}

func home(w http.ResponseWriter, req *http.Request) {
	w.Write([]byte("hello from API"))
}

/main.go

package main

import (
	"log"
	"net/http"
	"strings"

	"github.com/...yourPath.../api"
	"github.com/...yourPath.../user"
	"github.com/gorilla/mux"
)

func main() {
	router := mux.NewRouter()

	router.HandleFunc("/", home)
	mount(router, "/api", api.Router())
	mount(router, "/user", user.Router())

	log.Fatal(http.ListenAndServe(":8080", router))
}

func mount(r *mux.Router, path string, handler http.Handler) {
	r.PathPrefix(path).Handler(
		http.StripPrefix(
			strings.TrimSuffix(path, "/"),
			handler,
		),
	)
}

func home(w http.ResponseWriter, req *http.Request) {
	w.Write([]byte("Home"))
}

希望对你有所帮助!

英文:

You can modularize your routers independently into different packages, and mount them on the main router

Elaborating just a little on the following issue, you can come up with this approach, that makes it quite scalable (and easier to test, to some degree)

/api/router.go
<!-- language-all: go -->

package api

import (
    &quot;net/http&quot;

    &quot;github.com/gorilla/mux&quot;
)

func Router() *mux.Router {
    router := mux.NewRouter()
    router.HandleFunc(&quot;/&quot;, home)
    return router
}

func home(w http.ResponseWriter, req *http.Request) {
    w.Write([]byte(&quot;hello from API&quot;))
}

/main.go

package main

import (
    &quot;log&quot;
    &quot;net/http&quot;
    &quot;strings&quot;

    &quot;github.com/...yourPath.../api&quot;
    &quot;github.com/...yourPath.../user&quot;
    &quot;github.com/gorilla/mux&quot;
)

func main() {
    router := mux.NewRouter()

    router.HandleFunc(&quot;/&quot;, home)
    mount(router, &quot;/api&quot;, api.Router())
    mount(router, &quot;/user&quot;, user.Router())

    log.Fatal(http.ListenAndServe(&quot;:8080&quot;, router))
}

func mount(r *mux.Router, path string, handler http.Handler) {
    r.PathPrefix(path).Handler(
	    http.StripPrefix(
		    strings.TrimSuffix(path, &quot;/&quot;),
		    handler,
	    ),
    )
}

func home(w http.ResponseWriter, req *http.Request) {
    w.Write([]byte(&quot;Home&quot;))
}

答案2

得分: 13

这是一个示例的Go语言代码,它展示了如何使用gorilla/mux包创建一个简单的HTTP服务器。代码中定义了四个路由处理函数,分别对应不同的URL路径。你可以将这些处理函数放在其他文件或者其他包中。

如果你需要额外的依赖项,比如数据库,你可以使用构造函数技巧来避免使用全局变量。在示例代码中,可以看到NewHelloHandler函数接受一个*sql.DB参数,并返回一个处理函数。这样,你可以在处理函数中使用局部作用域的db变量,并且可以将其注入以进行测试。

请注意,这只是一个示例代码,具体的实现方式可能因项目需求而异。

英文:

What about something like this ?

//main.go
package main

import (
	&quot;NovAPI/routes&quot;
	&quot;fmt&quot;
	&quot;github.com/gorilla/mux&quot;
	&quot;net/http&quot;
)

func main() {

	router := mux.NewRouter().StrictSlash(true)

	router.HandleFunc(&quot;/hello&quot;, HelloHandler)
	router.HandleFunc(&quot;/user&quot;, UserHandler)
	router.HandleFunc(&quot;/route2&quot;, Route2Handler)
	router.HandleFunc(&quot;/route3&quot;, Route3Handler)
	// route declarations continue like this

	http.ListenAndServe(&quot;:1128&quot;, router)

}

func HelloHandler(res http.ResponseWriter, req *http.Request) {
	fmt.Fprintln(res, &quot;Hello&quot;)
}

func UserHandler(res http.ResponseWriter, req *http.Request) {
	fmt.Fprintln(res, &quot;User&quot;)
}

func Route2Handler(res http.ResponseWriter, req *http.Request) {
	fmt.Fprintln(res, &quot;Route2&quot;)
}

func Route3Handler(res http.ResponseWriter, req *http.Request) {
	fmt.Fprintln(res, &quot;Route3&quot;)
}

That way you can put your handlers in other files, or even other packages.

If you endup with additionnal dependencies like a database, you can even avoid the need of the global var using a constructor trick:

//main.go

func main() {
	db := sql.Open(…)
	
	//...
	
	router.HandleFunc(&quot;/hello&quot;, NewHelloHandler(db))
	
	//...
}

func NewHelloHandler(db *sql.DB) func(http.ResponseWriter, *http.Request) {
	return func(res http.ResponseWriter, req *http.Request) {
		// db is in the local scope, and you can even inject it to test your
		// handler
		fmt.Fprintln(res, &quot;Hello&quot;)
	}
}

答案3

得分: 6

我喜欢查看GitHub上的其他项目,以获取关于如何处理事务的想法。对于这些情况,我通常首先查看Docker仓库。他们的做法如下:

对于系统的路由,将所有处理程序定义在system_routes.go中,然后在system.go的NewRouter函数中初始化这些路由。

type systemRouter struct {
    backend Backend
    routes  []router.Route
}

func NewRouter(b Backend) router.Router {
    r := &systemRouter{
        backend: b,
    }

    r.routes = []router.Route{
        local.NewOptionsRoute("/", optionsHandler),
        local.NewGetRoute("/_ping", pingHandler),
        local.NewGetRoute("/events", r.getEvents),
        local.NewGetRoute("/info", r.getInfo),
        local.NewGetRoute("/version", r.getVersion),
        local.NewPostRoute("/auth", r.postAuth),
    }

    return r
}

// Routes return all the API routes dedicated to the docker system.
func (s *systemRouter) Routes() []router.Route {
    return s.routes
}

注意,systemRouter实现了router.Router接口,Routes函数返回一个[]router.Route,它们的处理程序定义为:

func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error

而不是Go标准的http处理程序:

func(w http.ResponseWriter, r *http.Request)

因此,他们有额外的代码将Docker API处理程序转换为Go HTTP处理程序,这在makeHttpHandler函数中实现。

最后,为了将这些路由添加到他们的mux路由器中,在他们的server.go中实现了其他几个函数来为他们的处理程序添加中间件

如果你认为这是你正在寻找的内容,请花些时间分析Docker代码中的路由。如果你需要我进一步解释或者我有遗漏的地方,请发表评论。

英文:

I like checking out other projects in github to grab ideas on how to do stuff, and for these cases I usually take a look first at the Docker repo. This is the way they do it:

For the system's routes, define all handlers in system_routes.go and then initialize those routes on a NewRouter function in system.go.

type systemRouter struct {
	backend Backend
	routes  []router.Route
}

func NewRouter(b Backend) router.Router {
	r := &amp;systemRouter{
		backend: b,
    }

    r.routes = []router.Route{
	    local.NewOptionsRoute(&quot;/&quot;, optionsHandler),
    	local.NewGetRoute(&quot;/_ping&quot;, pingHandler),
    	local.NewGetRoute(&quot;/events&quot;, r.getEvents),
    	local.NewGetRoute(&quot;/info&quot;, r.getInfo),
    	local.NewGetRoute(&quot;/version&quot;, r.getVersion),
    	local.NewPostRoute(&quot;/auth&quot;, r.postAuth),
    }

    return r
}

// Routes return all the API routes dedicated to the docker system.
func (s *systemRouter) Routes() []router.Route {
	return s.routes
}

Notice that systemRouter implements the router.Router interface and the Routes function returns a []router.Route, and their handlers are defined as

func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error

instead of Go's standard http handler:

func(w http.ResponseWriter, r *http.Request)

So there's extra code of theirs to convert a Docker API Handler to a Go HTTP Handler at the makeHttpHandler function.

And finally, to add those routes to their mux router, on their server.go they implement several other functions to add middleware to their handlers.

If this is something that you think it's what you are looking for, then take your time to analyze the Docker code for their routes, and if you need me to elaborate more or if I missed anything, post a comment.

答案4

得分: 1

由于我是一个语言模型,我无法直接运行代码。但是我可以帮助你翻译你提供的代码片段。以下是翻译的结果:

package main

import (
	"net/http"
	"github.com/user-name/repo-name/auth"
	"github.com/gorilla/mux"
)

func main() {
	r := mux.NewRouter()
	auth.Router(r)
	http.ListenAndServe(":8080", r)
}

然后在 auth 模块中,我们可以创建一个路由文件:

package auth

import "github.com/gorilla/mux"

func Router(r *mux.Router) {
	routes := r.PathPrefix("/auth").Subrouter()

	routes.HandleFunc("/register", Register)
}

希望这可以帮助到你!如果你有任何其他问题,请随时问我。

英文:

Since I am new to Go, I prefer a less verbose solution. In each module, we can create a Route function that expects a main route pointer and creates sub-routes to it. Our main.go file would be as follows

package main

import (
	&quot;net/http&quot;
	&quot;github.com/user-name/repo-name/auth&quot;
	&quot;github.com/gorilla/mux&quot;
)

func main() {
	r := mux.NewRouter()
	auth.Router(r)
	http.ListenAndServe(&quot;:8080&quot;, r)
}

then in auth module, we can create a route file

package auth

import &quot;github.com/gorilla/mux&quot;

func Router(r *mux.Router) {
	routes := r.PathPrefix(&quot;/auth&quot;).Subrouter()

	routes.HandleFunc(&quot;/register&quot;, Register)
}

huangapple
  • 本文由 发表于 2015年12月31日 22:53:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/34548039.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定