Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add GetVarNames() #676

Merged
merged 4 commits into from
Aug 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,19 @@ url, err := r.Get("article").URL("subdomain", "news",
"id", "42")
```

To find all the required variables for a given route when calling `URL()`, the method `GetVarNames()` is available:
```go
r := mux.NewRouter()
r.Host("{domain}").
Path("/{group}/{item_id}").
Queries("some_data1", "{some_data1}").
Queries("some_data2", "{some_data2}").
Name("article")

// Will print [domain group item_id some_data1 some_data2] <nil>
fmt.Println(r.Get("article").GetVarNames())

```
### Walking Routes

The `Walk` function on `mux.Router` can be used to visit all of the routes that are registered on a router. For example,
Expand Down
35 changes: 35 additions & 0 deletions example_route_vars_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package mux_test

import (
"fmt"
"github.com/gorilla/mux"
)

// This example demonstrates building a dynamic URL using
// required vars and values retrieve from another source
func ExampleRoute_GetVarNames() {
r := mux.NewRouter()

route := r.Host("{domain}").
Path("/{group}/{item_id}").
Queries("some_data1", "{some_data1}").
Queries("some_data2_and_3", "{some_data2}.{some_data3}")

dataSource := func(key string) string {
return "my_value_for_" + key
}

varNames, _ := route.GetVarNames()

pairs := make([]string, 0, len(varNames)*2)

for _, varName := range varNames {
pairs = append(pairs, varName, dataSource(varName))
}

url, err := route.URL(pairs...)
if err != nil {
panic(err)
}
fmt.Println(url.String())
}
34 changes: 34 additions & 0 deletions mux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2879,6 +2879,40 @@ func TestContextMiddleware(t *testing.T) {
r.ServeHTTP(rec, req)
}

func TestGetVarNames(t *testing.T) {
r := NewRouter()

route := r.Host("{domain}").
Path("/{group}/{item_id}").
Queries("some_data1", "{some_data1}").
Queries("some_data2_and_3", "{some_data2}.{some_data3}")

// Order of vars in the slice is not guaranteed, so just check for existence
expected := map[string]bool{
eh-steve marked this conversation as resolved.
Show resolved Hide resolved
"domain": true,
"group": true,
"item_id": true,
"some_data1": true,
"some_data2": true,
"some_data3": true,
}

varNames, err := route.GetVarNames()
if err != nil {
t.Fatal(err)
}

if len(varNames) != len(expected) {
t.Fatalf("expected %d names, got %d", len(expected), len(varNames))
}

for _, varName := range varNames {
eh-steve marked this conversation as resolved.
Show resolved Hide resolved
if !expected[varName] {
t.Fatalf("got unexpected %s", varName)
}
}
}

// mapToPairs converts a string map to a slice of string pairs
func mapToPairs(m map[string]string) []string {
var i int
Expand Down
19 changes: 19 additions & 0 deletions route.go
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,25 @@
return r.regexp.host.template, nil
}

// GetVarNames returns the names of all variables added by regexp matchers
// These can be used to know which route variables should be passed into r.URL()
coreydaley marked this conversation as resolved.
Show resolved Hide resolved
func (r *Route) GetVarNames() ([]string, error) {
if r.err != nil {
return nil, r.err
}

Check warning on line 736 in route.go

View check run for this annotation

Codecov / codecov/patch

route.go#L735-L736

Added lines #L735 - L736 were not covered by tests
var varNames []string
if r.regexp.host != nil {
varNames = append(varNames, r.regexp.host.varsN...)
}
if r.regexp.path != nil {
varNames = append(varNames, r.regexp.path.varsN...)
}
for _, regx := range r.regexp.queries {
varNames = append(varNames, regx.varsN...)
}
return varNames, nil
}

// prepareVars converts the route variable pairs into a map. If the route has a
// BuildVarsFunc, it is invoked.
func (r *Route) prepareVars(pairs ...string) (map[string]string, error) {
Expand Down
Loading