Handlers and HandlerFunc
http.Handler is a single method, ServeHTTP. HandlerFunc turns a plain function into one, which is all HandleFunc does for you.
type Handler interface { ServeHTTP(w http.ResponseWriter, r *http.Request) }A handler is anything that can answer a request. Go states that as an interface. An interface is a list of methods a value must have in order to be used in a given place. http.Handler lists exactly one method:
type Handler interface {
ServeHTTP(w http.ResponseWriter, r *http.Request)
}
Any type with that method is a handler. A router is a handler. A middleware is a handler. The server does not care which; it calls ServeHTTP on whatever it was given.
Why a type and not only functions
A handler written as a type can carry data. A struct with a database connection and a logger as fields, and a ServeHTTP method that uses them, keeps those dependencies out of global variables. That is how production services hand resources to the code that answers requests.
HandlerFunc
Most handlers need no fields, so declaring a type for each would be noise. http.HandlerFunc is a type whose underlying type is a function: type HandlerFunc func(ResponseWriter, *Request). It has a ServeHTTP method that simply calls the function itself. Converting a function to that type therefore produces a handler.
These two lines are the same thing:
mux.Handle("GET /a", http.HandlerFunc(myFunc))
mux.HandleFunc("GET /a", myFunc)
The second is shorthand. HandleFunc performs the conversion and then calls Handle.
What trips people up
http.HandlerFunc(myFunc) is a type conversion, not a function call. It does not run myFunc; it produces a value that can.
Example
package main
import (
"fmt"
"net/http"
"net/http/httptest"
)
// greeter is a handler with its own data. A ServeHTTP method is
// the only thing http.Handler requires.
type greeter struct {
name string
}
func (g greeter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "hello from %s", g.name)
}
func main() {
var h http.Handler = greeter{name: "api"}
// A plain function becomes a handler by conversion.
var f http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "hello from a function")
})
// httptest records a reply instead of sending it over a network.
for _, handler := range []http.Handler{h, f} {
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, httptest.NewRequest("GET", "/", nil))
fmt.Println(rec.Body.String())
}
}
// Output:
// hello from api
// hello from a functionWhen to use it
- Give handlers a database pool and a logger without package-level variables.
- Recognise http.HandlerFunc(...) in code you did not write and know it is a conversion.
- Pass a router, a middleware chain, or a single function to the same ListenAndServe argument.
More examples
A handler that carries its dependencies
Reach for a struct handler when the request needs something the handler does not create itself: a database pool, a cache client, a logger, a configuration value. The field is set once at start-up and the method reads it, so nothing is stored in a package-level variable and tests can build the struct with a fake.
type userHandler struct {
db *sql.DB
}
func (h userHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
var count int
err := h.db.QueryRow("SELECT count(*) FROM users").Scan(&count)
if err != nil {
http.Error(w, "database unavailable", http.StatusInternalServerError)
return
}
fmt.Fprintf(w, "%d users", count)
}
// In main:
// mux.Handle("GET /users/count", userHandler{db: db})A closure instead of a struct
The same dependency, passed by closure rather than by field. Declaring the return type as http.HandlerFunc rather than a bare func means the result already satisfies http.Handler, so it can go straight into Handle. Choose this when there is one handler; choose the struct when several handlers share the same set of dependencies.
// countUsers returns a handler that has captured db.
func countUsers(db *sql.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var count int
if err := db.QueryRow("SELECT count(*) FROM users").Scan(&count); err != nil {
http.Error(w, "database unavailable", http.StatusInternalServerError)
return
}
fmt.Fprintf(w, "%d users", count)
}
}
// In main:
// mux.Handle("GET /users/count", countUsers(db))Longhand: the adapter written out
Written out, the trick has no magic in it: a method can be declared on a function type, and that method calls the function. Reading this once makes http.HandlerFunc(f) stop looking like a special form and start looking like an ordinary conversion, which is what it is.
// This is all http.HandlerFunc is.
type myHandlerFunc func(http.ResponseWriter, *http.Request)
func (f myHandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request) {
f(w, r) // the method just calls the function
}
var h http.Handler = myHandlerFunc(greet) // same shape as http.HandlerFunc(greet)
Discussion