Understanding Golang Handlers
In Golang, any object can act as an HTTP handler if it implements the ServeHTTP
method with the following signature:
ServeHTTP(http.ResponseWriter, *http.Request)
However, manually creating an object just to implement this method would be annoying af. Instead, it's common practice to write handlers as regular functions. For example:
func getHome(w http.ResponseWriter, *http.Request) {
w.Write([]byte("home"))
}
At first glance, this looks like a handler, but technically, it isn't — there's no ServeHTTP()
method. To convert this function into a real handler, we can use the http.HandlerFunc
adapter:
mux := http.NewServeMux()
mux.Handle("/", http.HandlerFunc(getHome))
The http.HandlerFunc
adapter automatically adds a ServeHTTP()
method to the getHome()
function. When called, this method simply executes the original getHome()
function, making it conform to the http.Handler
interface:
// When you do:
http.HandlerFunc(getHome)
// you end up with a ServeHTTP that calls getHome(w, r)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
getHome(w, r);
}
Alternatively, you can simplify this even further using mux.HandleFunc
, which combines the function-to-handler conversion and handler registration into a single step:
mux := http.NewServeMux()
// turns getHome into an actuall handler and registers it at the same time
mux.HandleFunc("/", getHome)
Finally, it's important to note that the mux itself is an http.Handler
. When the server receives an HTTP request, it calls the mux's ServeHTTP()
method, whose primary job is to route the request to the appropriate handler based on the URL path and request method.
Ultimately, a Golang web application can be thought of as a chain of ServeHTTP()
methods. Each link in this chain processes the request in some way and passes it along to the next handler, until the request reaches the end of the chain.