Skip to content

Commit 10f71ea

Browse files
Corné de JongAlexVulaj
Corné de Jong
authored andcommittedJun 19, 2024
added route metadata with tests
1 parent 525206d commit 10f71ea

File tree

3 files changed

+136
-0
lines changed

3 files changed

+136
-0
lines changed
 

‎mux.go

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ var (
2424
// Do not run this function from `init()` in importable packages.
2525
// Changing this value is not safe for concurrent use.
2626
RegexpCompileFunc = regexp.Compile
27+
// ErrMetadataKeyNotFound is returned when the specified metadata key is not present in the map
28+
ErrMetadataKeyNotFound = errors.New("key not found in metadata")
2729
)
2830

2931
// NewRouter returns a new router instance.

‎route.go

+46
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ type Route struct {
2424
// Error resulted from building a route.
2525
err error
2626

27+
// The meta data associated with this route
28+
metadata map[any]any
29+
2730
// "global" reference to all named routes
2831
namedRoutes map[string]*Route
2932

@@ -125,6 +128,49 @@ func (r *Route) BuildOnly() *Route {
125128
return r
126129
}
127130

131+
// MetaData -------------------------------------------------------------------
132+
133+
// Metadata is used to set metadata on a route
134+
func (r *Route) Metadata(key any, value any) *Route {
135+
if r.metadata == nil {
136+
r.metadata = make(map[any]any)
137+
}
138+
139+
r.metadata[key] = value
140+
return r
141+
}
142+
143+
// GetMetadata returns the metadata map for route
144+
func (r *Route) GetMetadata() map[any]any {
145+
return r.metadata
146+
}
147+
148+
// MetadataContains returns whether or not the key is present in the metadata map
149+
func (r *Route) MetadataContains(key any) bool {
150+
_, ok := r.metadata[key]
151+
return ok
152+
}
153+
154+
// GetMetadataValue returns the value of a specific key in the metadata map. If the key is not present in the map mux.ErrMetadataKeyNotFound is returned
155+
func (r *Route) GetMetadataValue(key any) (any, error) {
156+
value, ok := r.metadata[key]
157+
if !ok {
158+
return nil, ErrMetadataKeyNotFound
159+
}
160+
161+
return value, nil
162+
}
163+
164+
// GetMetadataValueOr returns the value of a specific key in the metadata map. If the key is not present in the metadata the fallback value is returned
165+
func (r *Route) GetMetadataValueOr(key any, fallbackValue any) any {
166+
value, ok := r.metadata[key]
167+
if !ok {
168+
return fallbackValue
169+
}
170+
171+
return value
172+
}
173+
128174
// Handler --------------------------------------------------------------------
129175

130176
// Handler sets a handler for the route.

‎route_test.go

+88
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package mux
22

33
import (
4+
"errors"
45
"net/http"
6+
"reflect"
57
"regexp"
68
"sync"
79
"testing"
@@ -64,3 +66,89 @@ func testNewRouter(_ testing.TB, handler http.Handler) {
6466
r.Queries("orgID", "{orgID:[0-9]*?}")
6567
r.Host("{subdomain}.domain.com")
6668
}
69+
70+
func TestRouteMetadata(t *testing.T) {
71+
router := NewRouter()
72+
rw := NewRecorder()
73+
74+
expectedMap := make(map[any]any)
75+
expectedMap["key"] = "value"
76+
77+
router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
78+
route := CurrentRoute(r)
79+
metadata := route.GetMetadata()
80+
81+
if !reflect.DeepEqual(metadata, expectedMap) {
82+
println(metadata)
83+
t.Fatalf("Expected map does not equal the metadata map")
84+
}
85+
86+
}).Metadata("key", "value")
87+
88+
router.HandleFunc("/single-value", func(w http.ResponseWriter, r *http.Request) {
89+
route := CurrentRoute(r)
90+
value, err := route.GetMetadataValue("key")
91+
if err != nil {
92+
t.Fatalf("Expected metadata value to be present, but gave error: %s", err)
93+
}
94+
95+
stringValue, ok := value.(string)
96+
if !ok {
97+
t.Fatalf("Expected metadata value to be string, but was: %s", reflect.TypeOf(value))
98+
}
99+
100+
if stringValue != "value" {
101+
t.Fatalf("Expected metadata value to be '%s', but got '%s'", "value", stringValue)
102+
}
103+
104+
_, err = route.GetMetadataValue("key2")
105+
if err == nil {
106+
t.Fatalf("Expected metadata key not to be present and error, but error was nil")
107+
}
108+
109+
if !errors.Is(err, ErrMetadataKeyNotFound) {
110+
t.Fatalf("Expected error to be ErrMetadataKeyNotFound but got: %s", err)
111+
}
112+
113+
}).Metadata("key", "value")
114+
115+
router.HandleFunc("/single-value-fallback", func(w http.ResponseWriter, r *http.Request) {
116+
route := CurrentRoute(r)
117+
value := route.GetMetadataValueOr("key", "value-fallback")
118+
119+
stringValue, ok := value.(string)
120+
if !ok {
121+
t.Fatalf("Expected metadata value to be string, but was: %s", reflect.TypeOf(value))
122+
}
123+
124+
if stringValue != "value" {
125+
t.Fatalf("Expected metadata value to be '%s', but got '%s'", "value", stringValue)
126+
}
127+
128+
fallbackValue := route.GetMetadataValueOr("key2", "value2")
129+
fallbackStringValue, ok := fallbackValue.(string)
130+
if !ok {
131+
t.Fatalf("Expected metadata value to be string, but was: %s", reflect.TypeOf(value))
132+
}
133+
134+
if fallbackStringValue != "value2" {
135+
t.Fatalf("Expected metadata value to be '%s', but got '%s'", "value2", fallbackStringValue)
136+
}
137+
138+
}).Metadata("key", "value")
139+
140+
t.Run("get metadata map", func(t *testing.T) {
141+
req := newRequest("GET", "/")
142+
router.ServeHTTP(rw, req)
143+
})
144+
145+
t.Run("get metadata value", func(t *testing.T) {
146+
req := newRequest("GET", "/single-value")
147+
router.ServeHTTP(rw, req)
148+
})
149+
150+
t.Run("get metadata value or fallback", func(t *testing.T) {
151+
req := newRequest("GET", "/single-value-fallback")
152+
router.ServeHTTP(rw, req)
153+
})
154+
}

0 commit comments

Comments
 (0)
Please sign in to comment.