Skip to content

Commit

Permalink
Add Find to Routes interface (#872)
Browse files Browse the repository at this point in the history
* Add Find to Routes interface

* Add example of using Routes.Find

* Rename find-pattern example

* And find_pattern middleware

* Refactor find-pattern example to use official FindPattern middleware

* Remove middleware.FindPattern for now

---------

Co-authored-by: jriddle <[email protected]>
Co-authored-by: Vojtech Vitek <[email protected]>
  • Loading branch information
3 people authored Sep 18, 2024
1 parent 39703bc commit 1089a7c
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 4 deletions.
4 changes: 4 additions & 0 deletions chi.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ type Routes interface {
// the method/path - similar to routing a http request, but without
// executing the handler thereafter.
Match(rctx *Context, method, path string) bool

// Find searches the routing tree for the pattern that matches
// the method/path.
Find(rctx *Context, method, path string) string
}

// Middlewares type is a slice of standard middleware handlers with methods
Expand Down
22 changes: 18 additions & 4 deletions mux.go
Original file line number Diff line number Diff line change
Expand Up @@ -363,19 +363,33 @@ func (mx *Mux) Middlewares() Middlewares {
// Note: the *Context state is updated during execution, so manage
// the state carefully or make a NewRouteContext().
func (mx *Mux) Match(rctx *Context, method, path string) bool {
return mx.Find(rctx, method, path) != ""
}

// Find searches the routing tree for the pattern that matches
// the method/path.
//
// Note: the *Context state is updated during execution, so manage
// the state carefully or make a NewRouteContext().
func (mx *Mux) Find(rctx *Context, method, path string) string {
m, ok := methodMap[method]
if !ok {
return false
return ""
}

node, _, h := mx.tree.FindRoute(rctx, m, path)
node, _, _ := mx.tree.FindRoute(rctx, m, path)

if node != nil && node.subroutes != nil {
rctx.RoutePath = mx.nextRoutePath(rctx)
return node.subroutes.Match(rctx, method, rctx.RoutePath)
return node.subroutes.Find(rctx, method, rctx.RoutePath)
}

if node != nil {
e := node.endpoints[m]
return e.pattern
}

return h != nil
return ""
}

// NotFoundHandler returns the default Mux 404 responder whenever a route
Expand Down
68 changes: 68 additions & 0 deletions mux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1814,6 +1814,74 @@ func TestMuxMatch(t *testing.T) {
}
}

func TestMuxMatch_HasBasePath(t *testing.T) {
r := NewRouter()
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-Test", "yes")
w.Write([]byte(""))
})

tctx := NewRouteContext()

tctx.Reset()
if r.Match(tctx, "GET", "/") != true {
t.Fatal("expecting to find match for route:", "GET", "/")
}
}

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

tctx := NewRouteContext()

tctx.Reset()
if r.Match(tctx, "GET", "/") != false {
t.Fatal("not expecting to find match for route:", "GET", "/")
}
}

func TestMuxFind(t *testing.T) {
r := NewRouter()
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-Test", "yes")
w.Write([]byte(""))
})
r.Get("/hi", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-Test", "yes")
w.Write([]byte("bye"))
})
r.Route("/articles", func(r Router) {
r.Get("/{id}", func(w http.ResponseWriter, r *http.Request) {
id := URLParam(r, "id")
w.Header().Set("X-Article", id)
w.Write([]byte("article:" + id))
})
})
r.Route("/users", func(r Router) {
r.Head("/{id}", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-User", "-")
w.Write([]byte("user"))
})
r.Get("/{id}", func(w http.ResponseWriter, r *http.Request) {
id := URLParam(r, "id")
w.Header().Set("X-User", id)
w.Write([]byte("user:" + id))
})
})

tctx := NewRouteContext()

tctx.Reset()
if r.Find(tctx, "GET", "/users/1") == "/users/{id}" {
t.Fatal("expecting to find match for route:", "GET", "/users/1")
}

tctx.Reset()
if r.Find(tctx, "HEAD", "/articles/10") == "/articles/{id}" {
t.Fatal("not expecting to find match for route:", "HEAD", "/articles/10")
}
}

func TestServerBaseContext(t *testing.T) {
r := NewRouter()
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
Expand Down

0 comments on commit 1089a7c

Please sign in to comment.