Skip to content

Commit 4a671cb

Browse files
eh-steveAnonymouscoreydaley
authoredAug 24, 2023
Add GetVarNames() (#676)
**Summary of Changes** 1. Added `r.GetVarNames()` function to list all vars a route might need in order to call `r.URL()` --------- Co-authored-by: Anonymous <[email protected]> Co-authored-by: Corey Daley <[email protected]>
1 parent 85123bf commit 4a671cb

File tree

4 files changed

+101
-0
lines changed

4 files changed

+101
-0
lines changed
 

‎README.md

+13
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,19 @@ url, err := r.Get("article").URL("subdomain", "news",
366366
"id", "42")
367367
```
368368

369+
To find all the required variables for a given route when calling `URL()`, the method `GetVarNames()` is available:
370+
```go
371+
r := mux.NewRouter()
372+
r.Host("{domain}").
373+
Path("/{group}/{item_id}").
374+
Queries("some_data1", "{some_data1}").
375+
Queries("some_data2", "{some_data2}").
376+
Name("article")
377+
378+
// Will print [domain group item_id some_data1 some_data2] <nil>
379+
fmt.Println(r.Get("article").GetVarNames())
380+
381+
```
369382
### Walking Routes
370383

371384
The `Walk` function on `mux.Router` can be used to visit all of the routes that are registered on a router. For example,

‎example_route_vars_test.go

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package mux_test
2+
3+
import (
4+
"fmt"
5+
"github.com/gorilla/mux"
6+
)
7+
8+
// This example demonstrates building a dynamic URL using
9+
// required vars and values retrieve from another source
10+
func ExampleRoute_GetVarNames() {
11+
r := mux.NewRouter()
12+
13+
route := r.Host("{domain}").
14+
Path("/{group}/{item_id}").
15+
Queries("some_data1", "{some_data1}").
16+
Queries("some_data2_and_3", "{some_data2}.{some_data3}")
17+
18+
dataSource := func(key string) string {
19+
return "my_value_for_" + key
20+
}
21+
22+
varNames, _ := route.GetVarNames()
23+
24+
pairs := make([]string, 0, len(varNames)*2)
25+
26+
for _, varName := range varNames {
27+
pairs = append(pairs, varName, dataSource(varName))
28+
}
29+
30+
url, err := route.URL(pairs...)
31+
if err != nil {
32+
panic(err)
33+
}
34+
fmt.Println(url.String())
35+
}

‎mux_test.go

+34
Original file line numberDiff line numberDiff line change
@@ -2879,6 +2879,40 @@ func TestContextMiddleware(t *testing.T) {
28792879
r.ServeHTTP(rec, req)
28802880
}
28812881

2882+
func TestGetVarNames(t *testing.T) {
2883+
r := NewRouter()
2884+
2885+
route := r.Host("{domain}").
2886+
Path("/{group}/{item_id}").
2887+
Queries("some_data1", "{some_data1}").
2888+
Queries("some_data2_and_3", "{some_data2}.{some_data3}")
2889+
2890+
// Order of vars in the slice is not guaranteed, so just check for existence
2891+
expected := map[string]bool{
2892+
"domain": true,
2893+
"group": true,
2894+
"item_id": true,
2895+
"some_data1": true,
2896+
"some_data2": true,
2897+
"some_data3": true,
2898+
}
2899+
2900+
varNames, err := route.GetVarNames()
2901+
if err != nil {
2902+
t.Fatal(err)
2903+
}
2904+
2905+
if len(varNames) != len(expected) {
2906+
t.Fatalf("expected %d names, got %d", len(expected), len(varNames))
2907+
}
2908+
2909+
for _, varName := range varNames {
2910+
if !expected[varName] {
2911+
t.Fatalf("got unexpected %s", varName)
2912+
}
2913+
}
2914+
}
2915+
28822916
// mapToPairs converts a string map to a slice of string pairs
28832917
func mapToPairs(m map[string]string) []string {
28842918
var i int

‎route.go

+19
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,25 @@ func (r *Route) GetHostTemplate() (string, error) {
728728
return r.regexp.host.template, nil
729729
}
730730

731+
// GetVarNames returns the names of all variables added by regexp matchers
732+
// These can be used to know which route variables should be passed into r.URL()
733+
func (r *Route) GetVarNames() ([]string, error) {
734+
if r.err != nil {
735+
return nil, r.err
736+
}
737+
var varNames []string
738+
if r.regexp.host != nil {
739+
varNames = append(varNames, r.regexp.host.varsN...)
740+
}
741+
if r.regexp.path != nil {
742+
varNames = append(varNames, r.regexp.path.varsN...)
743+
}
744+
for _, regx := range r.regexp.queries {
745+
varNames = append(varNames, regx.varsN...)
746+
}
747+
return varNames, nil
748+
}
749+
731750
// prepareVars converts the route variable pairs into a map. If the route has a
732751
// BuildVarsFunc, it is invoked.
733752
func (r *Route) prepareVars(pairs ...string) (map[string]string, error) {

0 commit comments

Comments
 (0)
Please sign in to comment.