Ario
Ario

Reputation: 1940

Get a list of routes and params in Golang HTTP or Gorilla package

When I write a simple web application like this:

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
}

func main() {
    http.HandleFunc("/about", handler)
    http.ListenAndServe(":8080", nil)
}

How can I find the list of routes and params which I defined in my web app? e.g find "/about" in this example.

EDIT 1: How can get this one params and route?

gorilla.HandleFunc(`/check/{id:[0-9]+}`, func(res http.ResponseWriter, req *http.Request) {
    res.Write([]byte("Regexp works :)"))
})

Upvotes: 3

Views: 10907

Answers (4)

Carson
Carson

Reputation: 8098

http.ServeMux has a lowercase field called pattern []pattern where the str might be what you're looking for. Unfortunately, because the field is lowercase, accessing it isn't as straightforward. However, you can still obtain it using reflect.

package main

import (
    "fmt"
    "net/http"
    "reflect"
)

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

func main() {
    http.HandleFunc("/about", EmptyHandler)
    http.HandleFunc("GET /bar/is/{type}/{animal}", EmptyHandler)
    var mux *http.ServeMux
    mux = http.DefaultServeMux

    patterns := reflect.ValueOf(mux).Elem().FieldByName("patterns")
    for i := 0; i < patterns.Len(); i++ {
        // pattern *http.pattern
        pattern := patterns.Index(i).Elem()
        strField := pattern.FieldByName("str").String()
        fmt.Println(strField)
    }
}

output

/about
GET /bar/is/{type}/{animal}

playground

mux.pattern

Upvotes: 0

hsrv
hsrv

Reputation: 1570

With Go 1.22, or when using GO 1.21 with GODEBUG=httpmuxgo121=1:

You could use http.DefaultServeMux (type ServeMux) and examine it. With reflect package you can ValueOf the default multiplexer and extract m attribute which is a map of your routes.

v := reflect.ValueOf(http.DefaultServeMux).Elem()
fmt.Printf("routes: %v\n", v.FieldByName("mux121").FieldByName("m"))

With Go 1.21 or below:

You could use http.DefaultServeMux (type ServeMux) and examine it. With reflect package you can ValueOf the default multiplexer and extract m attribute which is a map of your routes.

v := reflect.ValueOf(http.DefaultServeMux).Elem()
fmt.Printf("routes: %v\n", v.FieldByName("m"))

upd:

if you use net/http than you should implement extracting params before any request is actually done by yourself; otherwise you have access to params with r.URL.Query()

if you use gorilla/mux than as elithrar mentioned you should use Walk:

func main:

r := mux.NewRouter()
r.HandleFunc("/path/{param1}", handler)

err := r.Walk(gorillaWalkFn)
if err != nil {
    log.Fatal(err)
}

func gorillaWalkFn:

func gorillaWalkFn(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
    path, err := route.GetPathTemplate()
    return nil
}

the path variable contains your template:

"/path/{param1}"

but you should extract params manually.

Upvotes: 8

user4466350
user4466350

Reputation:

An answer to improve i guess.

it provides the missing piece of code to extract parameters from the route path template string.


var pathTemplateRegex = regexp.MustCompile(`\{(\\?[^}])+\}`)

func getRouteParams(router *mux.Router, route string) []string {
    r := router.Get(route)
    if r == nil {
        return nil
    }
    t, _ := r.GetPathTemplate()
    params := pathTemplateRegex.FindAllString(t, -1)
    for i, p := range params {
        p = strings.TrimPrefix(p, "{")
        p = strings.TrimSuffix(p, "}")
        if strings.ContainsAny(p, ":") {
            p = strings.Split(p, ":")[0]
        }
        params[i] = p
    }
    return params
}

Upvotes: 1

never do
never do

Reputation: 31

You can see list of routes in HTTP package.

http.HandleFunc("/favicon.ico", func(res http.ResponseWriter, req *http.Request) {
    http.ServeFile(res, req, "favicon.ico")
})
http.HandleFunc(`/check`, func(res http.ResponseWriter, req *http.Request) {
    res.Write([]byte("Regexp works :)"))
})

httpMux := reflect.ValueOf(http.DefaultServeMux).Elem()
finList := httpMux.FieldByIndex([]int{1})
fmt.Println(finList)

Upvotes: 3

Related Questions