Go Routes Signature Return Types
Created on April 18, 2025
programming/golang
When you setup your routes, you return *http.ServeMux
. If you wrap mux
into middleware, you return http.Handler
.
// without middleware:
func (app *application) routes() *http.ServeMux {
...
return mux
}
// with middleware:
func (app *application) routes() http.Handler {
...
return commonHeaders(mux)
}
Here is the sample middleware:
func commonHeaders(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Server", "Go")
next.ServeHTTP(w, r)
})
}
In your main, you use app.routes() either way like this:
func main() {
var err error
app := &application{}
...
log.Print("Starting web server, listening on port 8873")
err = http.ListenAndServe(":8873", app.routes())
log.Fatal(err)
}
So what does http.ListenAndServe
expect as second arg if it can either be a *http.ServeMux
or a http.Handler
? Let’s find out!
Here is the source code:
// ListenAndServe listens on the TCP network address addr and then calls
// [Serve] with handler to handle requests on incoming connections.
// Accepted connections are configured to enable TCP keep-alives.
//
// The handler is typically nil, in which case [DefaultServeMux] is used.
//
// ListenAndServe always returns a non-nil error.
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
}
So then, what is a Handler
? 🤔
// A Handler responds to an HTTP request.
//
// [Handler.ServeHTTP] should write reply headers and data to the [ResponseWriter]
// and then return. Returning signals that the request is finished; it
// is not valid to use the [ResponseWriter] or read from the
// [Request.Body] after or concurrently with the completion of the
// ServeHTTP call.
//
// Depending on the HTTP client software, HTTP protocol version, and
// any intermediaries between the client and the Go server, it may not
// be possible to read from the [Request.Body] after writing to the
// [ResponseWriter]. Cautious handlers should read the [Request.Body]
// first, and then reply.
//
// Except for reading the body, handlers should not modify the
// provided Request.
//
// If ServeHTTP panics, the server (the caller of ServeHTTP) assumes
// that the effect of the panic was isolated to the active request.
// It recovers the panic, logs a stack trace to the server error log,
// and either closes the network connection or sends an HTTP/2
// RST_STREAM, depending on the HTTP protocol. To abort a handler so
// the client sees an interrupted response but the server doesn't log
// an error, panic with the value [ErrAbortHandler].
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
Alright, so this must mean that both the *http.ServeMux
and http.Handler
must have the ServeHTTP method.