What routes is my http.ServeMux
listening for?
As I've been looking at adding Go 1.22+'s new net/http
routing to oapi-codegen so folks could use the new lightweight functionality built into the standard library, I found that I wanted to make sure that my routes were all configured correctly.
I found this StackOverflow answer by hsrv which worked prior to Go 1.22's release, but does not since the release of enhanced routing.
Note that as this relies on reflection and the use of internal, unexported fields, it's likely to break at any time, as we saw with the release of Go 1.22!
Pre-Go 1.22
The behaviour for pre-Go 1.22 is:
package main
import (
"fmt"
"net/http"
"reflect"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {})
mux.HandleFunc("/pets", func(w http.ResponseWriter, r *http.Request) {
})
m := reflect.ValueOf(mux).Elem().FieldByName("m")
keys := m.MapKeys()
fmt.Println("Listening for routes:")
for _, v := range keys {
fmt.Println(v)
}
}
When we run this, we can see:
$ go version
go version go1.21.7 linux/amd64
$ go run .
Listening for routes:
/
/pets
Go 1.22
The new behaviour found in Go 1.22 is:
package main
import (
"fmt"
"log"
"net/http"
"reflect"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) {})
mux.HandleFunc("GET /pets/{id}", func(w http.ResponseWriter, r *http.Request) {
log.Printf("Called pet %s", r.PathValue("id"))
})
m := reflect.ValueOf(mux).Elem().FieldByName("mux121")
keys := m.FieldByName("m").MapKeys()
fmt.Println("Listening for routes:")
for _, v := range keys {
fmt.Println(v)
}
}
We can see this with Go 1.22:
$ go version
go version go1.22.0 linux/amd64
$ go run .
Listening for routes:
GET /
GET /pets/{id}