go - 具有多个子包的 gorilla mux 路由中的循环导入问题

标签 go gorilla

这是我的项目结构

--main package
--|--child_package1
--|--child_package2
--|--child_package3

I have all the the routes and method call management for API calls listed in main_package

The router Handler from main_package.go looks like this:

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_packages 中导入的。 任何人都可以建议我解决这个问题的最佳方法吗?

最佳答案

我假设您的 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

本质上,每个包都不应该处理自身之外的任何事情(或者至少尽可能少地处理)。 经纪人将是在任意两个包之间进行“协商”的唯一一方。

// 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 包是通信的中央接口(interface)

// 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 不再与任何内部依赖项解耦,前提是 它公开一个“代表”或Delegate对象来与代理交谈。

// 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
}

每个子进程都可以拥有自己的 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
}

在我看来,这是一种强大的模式,因为您可以编写更多“通用”处理程序并将它们插入到您想要的路由中。

关于go - 具有多个子包的 gorilla mux 路由中的循环导入问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34222841/

相关文章:

http - 带有静态文件的 Go Gorilla mux 子路由器

string - 如何删除不可打印的字符

go - 无法通过 Upstart 启动 Golang Prog

渲染后返回语句的 Golang lint

go - 在gcp cloud函数中使用gorillamux

go - golang 中的 websocket 服务器打开文件过多错误

mongodb - 由于缺少 'ISODate',使用时间时 Golang + mgo 查询 mongodb 失败

google-app-engine - 在 App Engine 中创建签名 URL 时遇到问题

go - 编码为 CSV,然后在 golang 中 ZIP

file - Gorilla Golang Pathprefix 不提供文件