Skip to content

Commit

Permalink
feat(mux): add 1.22-style path value support (#901)
Browse files Browse the repository at this point in the history
  • Loading branch information
angelofallars committed Feb 17, 2024
1 parent 60b4f5f commit fd0ff0e
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 0 deletions.
4 changes: 4 additions & 0 deletions mux.go
Expand Up @@ -452,6 +452,10 @@ func (mx *Mux) routeHTTP(w http.ResponseWriter, r *http.Request) {

// Find the route
if _, _, h := mx.tree.FindRoute(rctx, method, routePath); h != nil {
if supportsPathValue {
setPathValue(rctx, r)
}

h.ServeHTTP(w, r)
return
}
Expand Down
20 changes: 20 additions & 0 deletions path_value.go
@@ -0,0 +1,20 @@
//go:build go1.22
// +build go1.22

package chi

import "net/http"

// supportsPathValue is true if the Go version is 1.22 and above.
//
// If this is true, `net/http.Request` has methods `SetPathValue` and `PathValue`.
const supportsPathValue = true

// setPathValue sets the path values in the Request value
// based on the provided request context.
func setPathValue(rctx *Context, r *http.Request) {
for i, key := range rctx.URLParams.Keys {
value := rctx.URLParams.Values[i]
r.SetPathValue(key, value)
}
}
19 changes: 19 additions & 0 deletions path_value_fallback.go
@@ -0,0 +1,19 @@
//go:build !go1.22
// +build !go1.22

package chi

import "net/http"

// supportsPathValue is true if the Go version is 1.22 and above.
//
// If this is true, `net/http.Request` has methods `SetPathValue` and `PathValue`.
const supportsPathValue = false

// setPathValue sets the path values in the Request value
// based on the provided request context.
//
// setPathValue is only supported in Go 1.22 and above so
// this is just a blank function so that it compiles.
func setPathValue(rctx *Context, r *http.Request) {
}
69 changes: 69 additions & 0 deletions path_value_test.go
@@ -0,0 +1,69 @@
//go:build go1.22
// +build go1.22

package chi

import (
"net/http"
"net/http/httptest"
"strings"
"testing"
)

func TestPathValue(t *testing.T) {
testCases := []struct {
name string
pattern string
method string
pathKeys []string
requestPath string
expectedBody string
}{
{
name: "Basic path value",
pattern: "/hubs/{hubID}",
method: "GET",
pathKeys: []string{"hubID"},
requestPath: "/hubs/392",
expectedBody: "392",
},
{
name: "Two path values",
pattern: "/users/{userID}/conversations/{conversationID}",
method: "POST",
pathKeys: []string{"userID", "conversationID"},
requestPath: "/users/Gojo/conversations/2948",
expectedBody: "Gojo 2948",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
r := NewRouter()

r.Handle(tc.method+" "+tc.pattern, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
pathValues := []string{}
for _, pathKey := range tc.pathKeys {
pathValue := r.PathValue(pathKey)
if pathValue == "" {
pathValue = "NOT_FOUND:" + pathKey
}

pathValues = append(pathValues, pathValue)
}

body := strings.Join(pathValues, " ")

w.Write([]byte(body))
}))

ts := httptest.NewServer(r)
defer ts.Close()

_, body := testRequest(t, ts, tc.method, tc.requestPath, nil)
if body != tc.expectedBody {
t.Fatalf("expecting %q, got %q", tc.expectedBody, body)
}
})
}
}

0 comments on commit fd0ff0e

Please sign in to comment.