Skip to content

Commit fd0ff0e

Browse files
feat(mux): add 1.22-style path value support (#901)
1 parent 60b4f5f commit fd0ff0e

File tree

4 files changed

+112
-0
lines changed

4 files changed

+112
-0
lines changed

mux.go

+4
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,10 @@ func (mx *Mux) routeHTTP(w http.ResponseWriter, r *http.Request) {
452452

453453
// Find the route
454454
if _, _, h := mx.tree.FindRoute(rctx, method, routePath); h != nil {
455+
if supportsPathValue {
456+
setPathValue(rctx, r)
457+
}
458+
455459
h.ServeHTTP(w, r)
456460
return
457461
}

path_value.go

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//go:build go1.22
2+
// +build go1.22
3+
4+
package chi
5+
6+
import "net/http"
7+
8+
// supportsPathValue is true if the Go version is 1.22 and above.
9+
//
10+
// If this is true, `net/http.Request` has methods `SetPathValue` and `PathValue`.
11+
const supportsPathValue = true
12+
13+
// setPathValue sets the path values in the Request value
14+
// based on the provided request context.
15+
func setPathValue(rctx *Context, r *http.Request) {
16+
for i, key := range rctx.URLParams.Keys {
17+
value := rctx.URLParams.Values[i]
18+
r.SetPathValue(key, value)
19+
}
20+
}

path_value_fallback.go

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//go:build !go1.22
2+
// +build !go1.22
3+
4+
package chi
5+
6+
import "net/http"
7+
8+
// supportsPathValue is true if the Go version is 1.22 and above.
9+
//
10+
// If this is true, `net/http.Request` has methods `SetPathValue` and `PathValue`.
11+
const supportsPathValue = false
12+
13+
// setPathValue sets the path values in the Request value
14+
// based on the provided request context.
15+
//
16+
// setPathValue is only supported in Go 1.22 and above so
17+
// this is just a blank function so that it compiles.
18+
func setPathValue(rctx *Context, r *http.Request) {
19+
}

path_value_test.go

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//go:build go1.22
2+
// +build go1.22
3+
4+
package chi
5+
6+
import (
7+
"net/http"
8+
"net/http/httptest"
9+
"strings"
10+
"testing"
11+
)
12+
13+
func TestPathValue(t *testing.T) {
14+
testCases := []struct {
15+
name string
16+
pattern string
17+
method string
18+
pathKeys []string
19+
requestPath string
20+
expectedBody string
21+
}{
22+
{
23+
name: "Basic path value",
24+
pattern: "/hubs/{hubID}",
25+
method: "GET",
26+
pathKeys: []string{"hubID"},
27+
requestPath: "/hubs/392",
28+
expectedBody: "392",
29+
},
30+
{
31+
name: "Two path values",
32+
pattern: "/users/{userID}/conversations/{conversationID}",
33+
method: "POST",
34+
pathKeys: []string{"userID", "conversationID"},
35+
requestPath: "/users/Gojo/conversations/2948",
36+
expectedBody: "Gojo 2948",
37+
},
38+
}
39+
40+
for _, tc := range testCases {
41+
t.Run(tc.name, func(t *testing.T) {
42+
r := NewRouter()
43+
44+
r.Handle(tc.method+" "+tc.pattern, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
45+
pathValues := []string{}
46+
for _, pathKey := range tc.pathKeys {
47+
pathValue := r.PathValue(pathKey)
48+
if pathValue == "" {
49+
pathValue = "NOT_FOUND:" + pathKey
50+
}
51+
52+
pathValues = append(pathValues, pathValue)
53+
}
54+
55+
body := strings.Join(pathValues, " ")
56+
57+
w.Write([]byte(body))
58+
}))
59+
60+
ts := httptest.NewServer(r)
61+
defer ts.Close()
62+
63+
_, body := testRequest(t, ts, tc.method, tc.requestPath, nil)
64+
if body != tc.expectedBody {
65+
t.Fatalf("expecting %q, got %q", tc.expectedBody, body)
66+
}
67+
})
68+
}
69+
}

0 commit comments

Comments
 (0)