How do I pass arguments to my handler

MartinElvar picture MartinElvar · Oct 6, 2014 · Viewed 29.1k times · Source

I am trying to pass my database object along to my handlers, instead of having a global object. But I don't know if this is possible, I'm using Gorilla Mux package, and I can see that it takes a closure as a second param.

// https://github.com/gorilla/mux/blob/master/mux.go#L174
// HandleFunc registers a new route with a matcher for the URL path.
// See Route.Path() and Route.HandlerFunc().
func (r *Router) HandleFunc(path string, f func(http.ResponseWriter,
    *http.Request)) *Route {
    return r.NewRoute().Path(path).HandlerFunc(f)
}

Which then defines the params i can use, ideally i would like to have a third param like this.

// In my main
router.HandleFunc("/users/{id}", showUserHandler).Methods("GET")

func showUserHandler(w http.ResponseWriter, r *http.Request, db *gorm.DB) {
    fmt.Fprintf(w, "We should fetch the user with id %s", vars["id"])
}

Is there a workaround? Or do I need a global db object? I am new to Go, so please explain a potential answer in detail.

Answer

OneOfOne picture OneOfOne · Oct 6, 2014

Welcome to Go.

It is acceptable to have global variables and specially database objects.

However, there are few ways to workaround that if you prefer not to, for example you can create a struct and define your showHandler on it.

type Users struct {
    db *gorm.DB
}

func (users *Users) showHandler(w http.ResponseWriter, r *http.Request) {
    //now you can use users.db
}
func (users *Users) addHandler(w http.ResponseWriter, r *http.Request) {
    //now you can use users.db
}

// setup
users := &Users{db: createDB()}
router.HandleFunc("/users/{id}", users.showHandler).Methods("GET")
router.HandleFunc("/users/new", users.addHandler)
//etc

Another approach is creating a wrapper function:

db := createDB()
router.HandleFunc("/users/{id}", func(w http.ResponseWriter, r *http.Request) {
    showUserHandler(w, r, db)
}).Method("GET")