Reputation: 193
I have an Handler like this:
type handler struct {
Services *domain.Services
Config *domain.Config
}
And then, a lot of new types (they can be twenty or more), like this:
type Handler1 handler
type Handler2 handler
And each one has a ServeHTTP
method. And I use this so they can access the Services and Config variables.
They are being used in routes like this:
r.Handle("/login", &h.Handler1{
Services: s,
Config: c,
})
My question is: should I create all of this structs or just create a function that injects the Services and Config into the request Context and then I access them using r.Context().Value()
?
I thought about doing this:
func handler1(w http.ResponseWriter, r *http.Request) {
s, c := r.Context().Value("services"), r.Context().Value("config")
// My code
}
r.HandleFunc("/login", inject(handler1, s, c))
What's the best/recommended?
Upvotes: 1
Views: 529
Reputation: 7755
As an alternative to creating all these handler types, you can have functions which return other functions (http.HandlerFunc). This way, you will create a closure and can access the parameters when the request arrives in the handler. For example:
package main
import (
"fmt"
"net/http"
)
func SomeHandler(conf SomeConfig, service SomeService) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "foobar config: %q", conf)
}
}
func main() {
// TODO: initialise your conf & service
http.HandleFunc("/somepath", SomeHandler(conf, service))
}
Upvotes: 2
Reputation: 334
You probably could create some kind of Router which will provide ServeHTTP and do mapping between your real handlers and route paths.
Something like this:
package main
import "net/http"
type Router struct {
routes map[string]func(rw http.ResponseWriter, r *http.Request)
}
func NewRouter() *Router {
var r Router
r.routes = make(map[string]func(rw http.ResponseWriter, r *http.Request))
return &r
}
func (router *Router) addRoute(path string, f func(rw http.ResponseWriter, r *http.Request)) {
router.routes[path] = f
}
func (router *Router) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
for route, serveHTTP := range router.routes {
if route == r.URL.Path {
serveHTTP(rw, r)
return
}
}
rw.WriteHeader(http.StatusNotFound)
}
func teapot(rw http.ResponseWriter, r *http.Request) {
rw.WriteHeader(http.StatusTeapot)
}
func ok(rw http.ResponseWriter, r *http.Request) {
rw.WriteHeader(http.StatusOK)
}
func main() {
r := NewRouter()
r.addRoute("/teapot", teapot)
r.addRoute("/ok", ok)
http.ListenAndServe("localhost:8080", r)
}
Upvotes: 0