(Golang)You've Been Calling It a Handler Wrong All Along

go dev.to

When routing in go, we attach a normal function to a router and call it a handler, for example :

package main

func home(w http.ResponseWriter, r *http.Request) {

     w.Write([]byte("Hello from Snippetbox")) 
}

func main(){
    mux := http.NewServeMux()
    mux.HandleFunc("/", home)
}
Enter fullscreen mode Exit fullscreen mode

Most of would just call that home is a handler without knowing how its orginally not a handler and is transformer into one.

To understand this, first we need to understand what is a handler?

A Handler is any object that has the ServeHTTP() method, but why? Let's see in the source code of go, inside the net/http package, in server.go we will see this:

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}
Enter fullscreen mode Exit fullscreen mode

which means, to be a Handler, that thing should contain the ServeHTTP() method with the exact signature as above.

But now the question arises, so why does my routes work?

Here's the answer :

it works because when we register the route like this:

mux.HandleFunc("/", home)
Enter fullscreen mode Exit fullscreen mode

HandleFunc() secretly wraps the home function inside http.HandlerFunc() which in turn attaches the ServeHTTP() method to the home function and makes it indirectly a "Handler"

type HandlerFunc func(ResponseWriter, *Request)

func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
    f(w, r) // just calls the home function
}
Enter fullscreen mode Exit fullscreen mode

So to wrap this is the total flow:

You might also get it that we can directly call the HandlerFunc() instead of HandleFunc(), yes we can but HandleFunc() is easer to write and does the same work internally.

This is how we can directly call the HandlerFunc() :

mux := http.NewServeMux()
mux.Handle("/", http.HandlerFunc(home))
Enter fullscreen mode Exit fullscreen mode

Furthermore, ServeMux itself is also a Handler, it has its own ServeHTTP() method, look at the source code :

Notice(line 2847), the *ServeMux in the receiver part of the function,that means ServerHTTP() belongs to ServeMux, making it a Handler too anddd that's why we can pass it directly to http.ListenAndServe()

notice, the second parameter of the ListenAndServe() function is a handler so the mux we pass in there to run our server is also a handler

err := http.ListenAndServe(":4000", mux)//mux is a handler!
Enter fullscreen mode Exit fullscreen mode

Next time you write mux.HandleFunc("/",home) - you'll know that home alone isn't really a handler, but http.HandlerFunc(home) is and that's exactly what Go creates behind the scenes:)

Thanks for reading till here, see you in the next post ;)

Read Full Tutorial open_in_new
arrow_back Back to Tutorials