gogo-gormgo-chi

Access DB instance from go-chi route handlers


I am trying to build a REST API with go-chi and Gorm.

I am not sure how I should pass the Gorm DB instance to the route handlers.

Or if I should create one instance per handler, which does not sound right to me.

Should I use middleware, dependency injection or other? What would be recommended pattern here?

package main

import (
    "encoding/json"
    "fmt"
    "github.com/go-chi/chi/v5"
    "log"
    "net/http"
    "os"
    "time"
)

func main() {
    r := chi.NewRouter()

    r.Get("/", indexHandler)


    port := os.Getenv("PORT")
    if port == "" {
        port = "8080"
        log.Printf("Defaulting to port %s", port)
    }

    db := Connect()
    migrations(db)
    logStartServer(port)
    log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), r))
}

func logStartServer(port string) {
    log.Printf("Listening on port %s", port)
    log.Printf("Open http://localhost:%s in the browser", port)
}

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

    //How can I access db here?
    //result := db.Find(&users)

    policy := InsurancePolicy{ValidFrom: time.Now()}
    err := json.NewEncoder(w).Encode(policy)

    if err != nil {
        w.WriteHeader(http.StatusInternalServerError)
    }
}


Solution

  • Use methods instead of functions. This allows you to pass any information needed by the handlers using the receiver of those methods:

    type MyHandler struct {
      DB *gorm.DB
    }
    
    func (m MyHandler) IndexHandler(w http.ResponseWriter, r *http.Request) {
      // Use m.DB here
    }
    

    In main:

    handler:=mypkg.MyHandler{DB:gormDB}
    r.Get("/", handler.IndexHandler)
    

    In some cases, a closure makes more sense.

    func GetIndexHandler(db *gorm.DB) func(http.ResponseWriter,*http.Request) {
       return func(w http.ResponseWriter,req *http.Request) {
         // Implement index handler here, using db
       }
    }
    
    func main() {
      ...
      r.Get("/", GetIndexHandler(db))