dryb38654 2019-02-25 13:54
浏览 52
已采纳

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

I am new in Golang and need some help. I am tring to create REST API web service without ORM.

Right now I am successfully connected to PostgreSQL database. In database I have table which called factors. I want to create CRUD operations. The problem is with controllers logic.

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"`
}

How correctly looks like the GetFactors controller? Can someone show me please. For instance I pass db object to GetFactors controller as in the example below. Unfortunately it seems like it's incorrect.

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条回答 默认 最新

  • dongmi4035 2019-02-25 18:03
    关注

    A pattern I like to use is to define your own Router struct that has a mux.Router as a field as well as encapsulates things like your database connection, application config and etc.

    I find doing it this way makes it easily update your routes when they require different resources and development proceeds.

    First create a router object that takes in the database connection on creation and makes it available to all routes you wish to use.

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

    Then in main.go you can simply create your custom router, passing it your database connection. Then the custom router can be passed directly to 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))
    }
    

    Hopefully this helps.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥20 要这个数学建模编程的代码 并且能完整允许出来结果 完整的过程和数据的结果
  • ¥15 html5+css和javascript有人可以帮吗?图片要怎么插入代码里面啊
  • ¥30 Unity接入微信SDK 无法开启摄像头
  • ¥20 有偿 写代码 要用特定的软件anaconda 里的jvpyter 用python3写
  • ¥20 cad图纸,chx-3六轴码垛机器人
  • ¥15 移动摄像头专网需要解vlan
  • ¥20 access多表提取相同字段数据并合并
  • ¥20 基于MSP430f5529的MPU6050驱动,求出欧拉角
  • ¥20 Java-Oj-桌布的计算
  • ¥15 powerbuilder中的datawindow数据整合到新的DataWindow