Reputation: 3663
I was thinking of ways to do routing with the standard library. Is it valid to have a handler function that will call other handler functions depending on the request type? e.g.
func main() {
m := http.NewServeMux()
m.HandleFunc("/books", books)
// ...
}
func books(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "GET":
getBooks(w, r)
case "POST":
createBook(w, r)
}
}
Is this good practice? I didn't want to declare a custom handler since I find functions to be a bit cleaner.
Upvotes: 5
Views: 635
Reputation: 5898
This is valid, as mentioned in the other answers handlers are just functions.
The thing that changes is the request method; it might worth considering an implementation with a map. This could be more extensible as the number of handlers you need change.
type BookController struct {
routes map[string]http.HandlerFunc
}
func (b BookController) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// beware this very basic example will panic if there's not a registered handler for r.Method
// but I assume you'd have to do handling of missing method logic in your default switch anyway
b.routes[r.Method].ServeHTTP(w, r)
}
And to register them:
m := http.NewServeMux()
b := BookController{}
b.routes = map[string]http.HandlerFunc{
"GET": getBooks,
"POST": createBooks,
}
m.Handle("/books", b)
Slightly more boiler plate, but might allow for easier adding / removing of handlers later.
Upvotes: 2
Reputation: 27822
Yes, this is perfectly valid; handlers are just functions so there is no reason it shouldn't be. In fact, this is how middleware is usually implemented.
There is nothing "magic" about handler functions at all. As long as you're writing to the correct file descriptor (w http.ResponseWriter
) anything goes.
That doesn't mean that using this pattern is necessarily a good idea for all applications – routing libraries exist for a reason – but for smaller programs it will work just fine.
Upvotes: 5
Reputation: 4917
It's completely valid to have a
HandlerFunc
call anotherHandlerFunc
.
In fact that's how you would implement middleware using the standard lib.
Here's a Post by Mat Ryer (amazing guy btw) that explains in some further detail what he calls
"http.Handler wrapper technique"
The way you want to use HandlerFunc
s reminds me of Laravel's Resource Controllers, which I think are pretty neat. But using them carelessly could become an unnecessary overhead.
I would suggest you perhaps give julienschmidt/httprouter library a try.
It's pretty fast and easy to use.
Upvotes: 3