Reputation: 7792
So I have two files. In one I have initialize a gorilla router, and register handlers. In the other I define the handlers. The handlers are supposed to query a MYSQL database. Routes.go looks like this -
package main
import (
"net/http"
"github.com/gorilla/mux"
"database/sql"
_ "github.com/go-sql-driver/mysql"
"fmt"
)
type Route struct {
Name string
Method string
Pattern string
HandlerFunc http.HandlerFunc
}
type Routes[]Route
func NewRouter() *mux.Router {
db, err := sql.Open("mysql", "psanker:123@/education_data")
err = db.Ping()
if err != nil {
fmt.Println("Failed to prepare connection to database")
log.Fatal("Error:", err.Error())
}
defer db.Close()
router := mux.NewRouter().StrictSlash(true)
for _, route := range routes {
router.
Methods(route.Method).
Path(route.Pattern).
Name(route.Name).
Handler(route.HandlerFunc)
}
return router
}
var routes = Routes{
Route {
"Index",
"GET",
"/",
Index,
},
Route {
"getDistrict",
"GET",
"/district/{districtId}",
getDistrict,
DBConn &db,
},
Route {
"getDistricts",
"GET",
"/districts",
getDistricts,
},
}
My handlers.go file looks like this -
package main
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
"encoding/json"
)
func Index(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "WELCOME!")
}
func getDistrict(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
districtId := vars["districtId"]
fmt.Fprintln(w, "District id : ", districtId)
}
func getDistricts(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json;charset=UTF-8")
w.WriteHeader(http.StatusOK)
rows, err := db.Query("SELECT * from districts")
check(err)
var district District
for rows.Next() {
var id int64
test := "hey"
district = District{Id: id, Activities: test}
}
if err := json.NewEncoder(w).Encode(district); err != nil {
check(err)
}
}
I want to use one database connection for all of my handlers, how do I achieve this?
Upvotes: 1
Views: 1725
Reputation: 1515
Elithar's answer is the standard way of achieving this. If you want to inject a db connection in every handler, this is one way to solve it. You define your own handler and convert it back to what the router expects. Here is the example, I assume, that Elithar wanted to give.
func main() {
http.HandlerFunc(myDbHandler(Index, db))
}
type dbHandler func(w http.ResponseWriter, r *http.Request, db *sql.DB)
func myDbHandler(handler dbHandler, db *sql.DB) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
handler(w, r, db)
}
}
func Index(w http.ResponseWriter, r *http.Request, db *sql.DB) {
// handler code goes here
}
Upvotes: 1
Reputation: 24260
Go's sql.DB
type represents a connection pool and not a single connection. It is recommended that you create a pool on program initialization and either:
Create a global pool and just use it (the pool is safe for concurrent access)
var db *sql.DB
func main() {
var err error
db, err = sql.Open("connection string here")
if err != nil {
// handle it
}
// Rest of program/router/etc
}
func MyHandler(w http.ResponseWriter, r *http.Request) {
err := db.Query("...")
if err != nil {
// handle it
}
// Rest of handler
}
Create custom handler functions that satisfy http.Handler
and accept the pool or a struct containing the pool as an additional argument. I wrote about that here: https://elithrar.github.io/article/custom-handlers-avoiding-globals/
(I would provide another example but I'm on mobile; excuse the poor indentation)
Also look at sqlx to simplify your query into/from struct handling.
Upvotes: 2