如何正确使控制器指向Golang中的路由?

时间:2019-02-25 13:54:36

标签: go

我是 Golang 的新手,需要帮助。我正试图在没有ORM的情况下创建REST API Web服务。

现在,我已成功连接到 PostgreSQL 数据库。在数据库中,我有一个名为factors的表。我想创建CRUD操作。问题出在控制器逻辑上。

main.go

package main

import (
    "github.com/gorilla/mux"
    "log"
    "net/http"
    "rest_api/configurations"
    "rest_api/controllers"
)

func main()  {
    db, err := configurations.PostgreSQLDatabase()
    if err != nil {
        log.Fatal(err)
    }

    router := mux.NewRouter()

    router.StrictSlash(true)

    subrouter := router.PathPrefix("/api").Subrouter()

    subrouter.HandleFunc("/factors", controllers.GetFactors(db)).Methods("GET")

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

models / factors.go

package models

type Factor struct {
    ID int `json:"id"`
    Name string `json:"name"`
}

GetFactors控制器的外观如何正确?有人可以告诉我。例如,我将db对象传递给GetFactors控制器,如下例所示。不幸的是,这似乎是不正确的。

controllers / factors.go

func GetFactors(db *sql.DB, w http.ResponseWriter, req *http.Request) {
    // some code
}

configurations / PostgreSQL.go

func PostgreSQLDatabase() (*sql.DB, error) {
    // Load environment variables from ".env" file.
    err := godotenv.Load(".env")
    if err != nil {
        log.Fatal(err)
    }

    // Initialize database-related variables.
    dbUser := os.Getenv("PostgreSQL_USER")
    dbPassword := os.Getenv("PostgreSQL_PASSWORD")
    dbHost := os.Getenv("PostgreSQL_HOST")
    dbName := os.Getenv("PostgreSQL_DB_NAME")
    dbURL := fmt.Sprintf("user=%s password=%s host=%s dbname=%s sslmode=disable", dbUser, dbPassword, dbHost, dbName)

    // Create PostgreSQL database connection pool.
    db, err := sql.Open("postgres", dbURL)
    if err != nil {
        return nil, err
    }

    // Ping PostgreSQL database to make sure it's alive.
    err = db.Ping()
    if err != nil {
        log.Fatal(err)
    } else {
        log.Println("Web service successfully connected to remote PostgreSQL database.")
    }

    return db, nil
}

3 个答案:

答案 0 :(得分:2)

没有正确的方法,它主要基于意见。

HandlerFunc函数的语义应该类似于func(w http.ResponseWriter, r *http.Request),为了传递数据库,您可以使用闭包,这是一个示例。

main.go

// ... some code here 
subrouter.HandleFunc("/factors", controllers.GetFactors(db)).Methods("GET")
// ... some code here

controllers / factors.go

func GetFactors(db *sql.DB) http.HandlerFunc {
  return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
    // some code
  })
}

另一个选择:

对此我不太确定,但是您可以根据需要进行调整。初始化Controller结构并将db传递给它:

main.go

// ... some code here 
db, err := configurations.PostgreSQLDatabase()
if err != nil {
    log.Fatal(err)
}
ctrl := controllers.Controller{DB: db}
subrouter.HandleFunc("/factors", ctrl.GetFactors).Methods("GET")
// ... some code here

表示Controller结构上的方法。 在控制器中定义一个结构

controllers / factors.go

type Controller struct {
  DB *PostgreSQLDatabase
}

func (c Controller) GetFactors(w http.ResponseWriter, req *http.Request) {
    // some code
    // c.DB.MySqlMethod()
}

答案 1 :(得分:1)

您的功能GetFactors必须看起来像:

func GetFactors(w http.ResponseWriter, r *http.Request) {}

在主文件中必须具有:

subrouter.HandleFunc("/factors", controllers.GetFactors).Methods("GET")

为了获得数据库连接,您必须在软件包GetDB中添加"rest_api/configurations"之类的功能。

"rest_api/configurations"中,您必须具有以下内容:

var db *PostgreSQLDatabase

func init() {
    var err error
    db, err = configurations.PostgreSQLDatabase()
    if err != nil {
        log.Fatal(err)
    }
}

func GetDB() *PostgreSQLDatabase {
  return db
}

答案 2 :(得分:1)

我要使用的一种模式是定义自己的Router结构,该结构以mux.Router作为字段,并封装诸如数据库连接,应用程序配置等内容。

我发现这样做可以使您在需要不同资源和开发进度的情况下轻松地更新您的路线。

首先创建一个路由器对象,该对象在创建时将与数据库建立连接,并使它可用于您要使用的所有路由。

router.go

package main

import (
    "net/http"
    "database/sql"

    "github.com/gorilla/mux"
)

type Router struct {
    router *mux.Router
    db *sql.DB
}

func NewRouter(db *sql.DB) (*Router, error) {
    router := mux.NewRouter()
    router.StrictSlash(true)
    subrouter := router.PathPrefix("/api").Subrouter()

    r := &Router{
        router: router,
        db: db,
    }

    subrouter.HandleFunc("/factors", r.GetFactors).Methods(http.MethodGet)

    return r, nil
}

func (r *Router) GetFactors(w http.ResponseWriter, req *http.Request) {
    // Now you can access your database via `r.db`
}

// Needed so we can pass our custom router to ListenAndServe.
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    r.router.ServeHTTP(w, req)
}

然后在main.go中,您可以简单地创建自定义路由器,并将其传递给数据库连接。然后,可以将自定义路由器直接传递到ListenAndServe

main.go

package main

import (
    "log"
    "net/http"
    "rest_api/configurations"
    "rest_api/controllers"
)

func main()  {
    db, err := configurations.PostgreSQLDatabase()
    if err != nil {
        log.Fatal(err)
    }

    router, err := NewRouter(db)
    if err != nil {
        log.Fatalf("error initializing router: %v", err)
    }

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

希望这会有所帮助。