具有多个子包的大猩猩多路复用路由中的循环导入问题
Cycle import issue in gorilla mux routing with multiple sub packages
这是我的项目结构
--main package
--|--child_package1
--|--child_package2
--|--child_package3
我有 main_package
中列出的 API 调用的所有路由和方法调用管理
来自 main_package.go 的路由器处理程序如下所示:
func Handlers(db *sql.DB, customeruploadFile string) *mux.Router {
router := mux.NewRouter()
router.HandleFunc("/api1", child_package1.method )
router.HandleFunc("/api2", child_package2.method)
router.HandleFunc("/api3", child_package3.mehtod)
fileHandler := http.FileServer(http.Dir("./client/compiled"))
router.PathPrefix("/").Handler(http.StripPrefix("/", fileHandler))
return router
}
问题是当我为子包编写测试用例时,我需要这个 Handlers 方法来创建测试服务器,为此我需要在 child_packages 中导入 main_package,然后很明显有循环导入正在发生,因为 child_packages 在 main_package 中导入。
任何人都可以建议我解决这个问题的最佳方法吗?
我假设您的 main_package
不是 Go 中的 main
包。我认为 child_packages 不应该在 main_package
之下,因为我们的目标是将每个包彼此分离。
这是我目前在我的项目中使用的模式,以避免依赖冲突:
project/
├── main_package
│ └── main_package.go
├── brokers
│ └── brokers.go
├── child_package1
│ └── child_package1.go
├── child_package2
│ └── child_package2.go
└── child_package3
└── child_package3.go
本质上,每个包都不应该处理自身以外的任何事情(或者至少尽可能少地处理)。 broker
将是任何两个包之间 "negotiates" 的唯一一方。
// main_package.go
package main_package
import (
"path/to/sql"
"path/to/mux"
"path/to/brokers"
)
// Never use selectors from packages directly
// but create a `Broker` object for each endpoint
var bk1 = brokers.New("/api1")
var bk2 = brokers.New("/api2")
var bk3 = brokers.New("/api3")
func Handlers(db *sql.DB, customeruploadFile string) *mux.Router {
router := mux.NewRouter()
// each broker has its own `MyHandler` function
router.HandleFunc("/api1", bk1.MyHandler)
router.HandleFunc("/api2", bk2.MyHandler)
router.HandleFunc("/api3", bk3.MyHandler)
fileHandler := http.FileServer(http.Dir("./client/compiled"))
router.PathPrefix("/").Handler(http.StripPrefix("/", fileHandler))
return router
}
brokers
包是通信的中央接口
// brokers.go
package brokers
import (
"path/to/child_package1"
"path/to/child_package2"
"path/to/child_package3"
"net/http"
)
type Broker interface {
MyHandler(http.ResponseWriter, *http.Request)
}
// Factory function to create a `Broker` instance
func New(uri string) Broker {
if uri == "/api1" {
return Broker( new(child_package1.Delegate) )
} else if uri == "/api2" {
return Broker( new(child_package2.Delegate) )
} else if uri == "/api3" {
return Broker( new(child_package3.Delegate) )
}
return nil
}
现在 child_packageX
不再与任何内部依赖分离,前提是
它公开了一个 "representative" 或 Delegate
object 来与经纪人交谈。
// child_package1.go
package child_package1
import "net/http"
type Delegate struct {
// Optional parameters can be carried by the Delegate
// to be used in the created Broker anywhere
}
func (d *Delegate) MyHandler(w http.ResponseWriter, r *http.Request) {
// Maybe return a JSON here
}
每个 child 都可以有自己的 MyHandler
为不同的 api 调用做不同的事情,而不必知道它们正在服务的端点。
// child_package2
package child_package2
import "net/http"
type Delegate struct {}
func (d *Delegate) MyHandler(w http.ResponseWriter, r *http.Request) {
// Maybe return an XML here
}
main_package
不导入所有 child_packageX
,只导入 broker
包。您可以编写一个导入 broker
包而不是实际包的测试,或者您甚至可以编写另一个代理进行测试。
package test
import (
"testing"
"path/to/main_package"
)
func TestMain(*testing.T) {
// test the routing in `main_package`
}
您不再测试处理函数的功能,而是测试代理公开的端点之一。这鼓励您编写通用处理程序函数并专注于更高级别的端点。
package test
import (
"testing"
"path/to/broker"
)
func TestGetJSONAlright(*testing.T) {
bk1 := brokers.New("/api1")
// test if I get JSON here
}
func TestGetXMLAlright(*testing.T) {
bk1 := brokers.New("/api2")
// test if I get XML here
}
在我看来,这是一个强大的模式,因为您可以编写更多 "generic" 处理程序并将它们插入到您想要的路由中。
这是我的项目结构
--main package --|--child_package1 --|--child_package2 --|--child_package3
我有 main_package
中列出的 API 调用的所有路由和方法调用管理来自 main_package.go 的路由器处理程序如下所示:
func Handlers(db *sql.DB, customeruploadFile string) *mux.Router {
router := mux.NewRouter()
router.HandleFunc("/api1", child_package1.method )
router.HandleFunc("/api2", child_package2.method)
router.HandleFunc("/api3", child_package3.mehtod)
fileHandler := http.FileServer(http.Dir("./client/compiled"))
router.PathPrefix("/").Handler(http.StripPrefix("/", fileHandler))
return router
}
问题是当我为子包编写测试用例时,我需要这个 Handlers 方法来创建测试服务器,为此我需要在 child_packages 中导入 main_package,然后很明显有循环导入正在发生,因为 child_packages 在 main_package 中导入。 任何人都可以建议我解决这个问题的最佳方法吗?
我假设您的 main_package
不是 Go 中的 main
包。我认为 child_packages 不应该在 main_package
之下,因为我们的目标是将每个包彼此分离。
这是我目前在我的项目中使用的模式,以避免依赖冲突:
project/
├── main_package
│ └── main_package.go
├── brokers
│ └── brokers.go
├── child_package1
│ └── child_package1.go
├── child_package2
│ └── child_package2.go
└── child_package3
└── child_package3.go
本质上,每个包都不应该处理自身以外的任何事情(或者至少尽可能少地处理)。 broker
将是任何两个包之间 "negotiates" 的唯一一方。
// main_package.go
package main_package
import (
"path/to/sql"
"path/to/mux"
"path/to/brokers"
)
// Never use selectors from packages directly
// but create a `Broker` object for each endpoint
var bk1 = brokers.New("/api1")
var bk2 = brokers.New("/api2")
var bk3 = brokers.New("/api3")
func Handlers(db *sql.DB, customeruploadFile string) *mux.Router {
router := mux.NewRouter()
// each broker has its own `MyHandler` function
router.HandleFunc("/api1", bk1.MyHandler)
router.HandleFunc("/api2", bk2.MyHandler)
router.HandleFunc("/api3", bk3.MyHandler)
fileHandler := http.FileServer(http.Dir("./client/compiled"))
router.PathPrefix("/").Handler(http.StripPrefix("/", fileHandler))
return router
}
brokers
包是通信的中央接口
// brokers.go
package brokers
import (
"path/to/child_package1"
"path/to/child_package2"
"path/to/child_package3"
"net/http"
)
type Broker interface {
MyHandler(http.ResponseWriter, *http.Request)
}
// Factory function to create a `Broker` instance
func New(uri string) Broker {
if uri == "/api1" {
return Broker( new(child_package1.Delegate) )
} else if uri == "/api2" {
return Broker( new(child_package2.Delegate) )
} else if uri == "/api3" {
return Broker( new(child_package3.Delegate) )
}
return nil
}
现在 child_packageX
不再与任何内部依赖分离,前提是
它公开了一个 "representative" 或 Delegate
object 来与经纪人交谈。
// child_package1.go
package child_package1
import "net/http"
type Delegate struct {
// Optional parameters can be carried by the Delegate
// to be used in the created Broker anywhere
}
func (d *Delegate) MyHandler(w http.ResponseWriter, r *http.Request) {
// Maybe return a JSON here
}
每个 child 都可以有自己的 MyHandler
为不同的 api 调用做不同的事情,而不必知道它们正在服务的端点。
// child_package2
package child_package2
import "net/http"
type Delegate struct {}
func (d *Delegate) MyHandler(w http.ResponseWriter, r *http.Request) {
// Maybe return an XML here
}
main_package
不导入所有 child_packageX
,只导入 broker
包。您可以编写一个导入 broker
包而不是实际包的测试,或者您甚至可以编写另一个代理进行测试。
package test
import (
"testing"
"path/to/main_package"
)
func TestMain(*testing.T) {
// test the routing in `main_package`
}
您不再测试处理函数的功能,而是测试代理公开的端点之一。这鼓励您编写通用处理程序函数并专注于更高级别的端点。
package test
import (
"testing"
"path/to/broker"
)
func TestGetJSONAlright(*testing.T) {
bk1 := brokers.New("/api1")
// test if I get JSON here
}
func TestGetXMLAlright(*testing.T) {
bk1 := brokers.New("/api2")
// test if I get XML here
}
在我看来,这是一个强大的模式,因为您可以编写更多 "generic" 处理程序并将它们插入到您想要的路由中。