praks5432
praks5432

Reputation: 7792

Golang pass arguments to gorilla router

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

Answers (2)

Machiel
Machiel

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

elithrar
elithrar

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:

  1. 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
    }
    
  2. 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

Related Questions