Skip to content

Commit fe38707

Browse files
committed
refactor: cleanup comments and docs
Signed-off-by: Christian Stewart <christian@paral.in>
1 parent ef3e914 commit fe38707

File tree

4 files changed

+21
-36
lines changed

4 files changed

+21
-36
lines changed

README.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,11 @@ func main() {
7878
ctx := context.Background()
7979
resp := &Responder{}
8080

81-
// path=/ responded with: Welcome!
81+
// path=/ responded with: Welcome!
8282
router.Serve(ctx, "/", resp)
83-
// path=/hello/world responded with: hello, world!
83+
// path=/hello/world responded with: hello, world!
8484
router.Serve(ctx, "/hello/world", resp)
85-
// path=/hello/reader responded with: hello, reader!
85+
// path=/hello/reader responded with: hello, reader!
8686
router.Serve(ctx, "/hello/reader", resp)
8787
}
8888
```
@@ -96,7 +96,7 @@ Some things to note when compared to typical HTTP request handlers:
9696

9797
### Named parameters
9898

99-
As you can see, `:name` is a *named parameter*. The values are accessible via `pathrouter.Params`, which is just a slice of `pathrouter.Param`s. You can get the value of a parameter either by its index in the slice, or by using the `ByName(name)` method: `:name` can be retrieved by `ByName("name")`.
99+
As you can see, `:name` is a *named parameter*. The values are accessible via `pathrouter.Params`, which is just a slice of `pathrouter.Param`s. You can get the value of a parameter either by its index in the slice, or by using the `ByName(name)` function: `:name` can be retrieved by `ByName("name")`.
100100

101101
When using a `http.Handler` (using `router.Handler` or `http.HandlerFunc`) instead of HttpRouter's handle API using a 3rd function parameter, the named parameters are stored in the `request.Context`. See more below under [Why doesn't this work with http.Handler?](#why-doesnt-this-work-with-httphandler).
102102

@@ -111,7 +111,7 @@ Pattern: /user/:user
111111
/user/ no match
112112
```
113113

114-
**Note:** Since this router has only explicit matches, you can not register static routes and parameters for the same path segment. For example you can not register the patterns `/user/new` and `/user/:user` for the same request method at the same time. The routing of different request methods is independent from each other.
114+
**Note:** Since this router has only explicit matches, you can not register static routes and parameters for the same path segment. For example you can not register the patterns `/user/new` and `/user/:user` at the same time.
115115

116116
### Catch-All parameters
117117

@@ -127,7 +127,7 @@ Pattern: /src/*filepath
127127

128128
## How does it work?
129129

130-
The router relies on a tree structure which makes heavy use of *common prefixes*, it is basically a *compact* [*prefix tree*](https://en.wikipedia.org/wiki/Trie) (or just [*Radix tree*](https://en.wikipedia.org/wiki/Radix_tree)). Nodes with a common prefix also share a common parent. Here is a short example what the routing tree for the `GET` request method could look like:
130+
The router relies on a tree structure which makes heavy use of *common prefixes*, it is basically a *compact* [*prefix tree*](https://en.wikipedia.org/wiki/Trie) (or just [*Radix tree*](https://en.wikipedia.org/wiki/Radix_tree)). Nodes with a common prefix also share a common parent. Here is a short example what the routing tree could look like:
131131

132132
```
133133
Priority Path Handle
@@ -145,7 +145,7 @@ Priority Path Handle
145145

146146
Every `*<num>` represents the memory address of a handler function (a pointer). If you follow a path trough the tree from the root to the leaf, you get the complete route path, e.g `\blog\:post\`, where `:post` is just a placeholder ([*parameter*](#named-parameters)) for an actual post name. Unlike hash-maps, a tree structure also allows us to use dynamic parts like the `:post` parameter, since we actually match against the routing patterns instead of just comparing hashes. [As benchmarks show](https://github.com/julienschmidt/go-http-routing-benchmark), this works very well and efficient.
147147

148-
Since URL paths have a hierarchical structure and make use only of a limited set of characters (byte values), it is very likely that there are a lot of common prefixes. This allows us to easily reduce the routing into ever smaller problems. Moreover the router manages a separate tree for every request method. For one thing it is more space efficient than holding a method->handle map in every single node, it also allows us to greatly reduce the routing problem before even starting the look-up in the prefix-tree.
148+
Since URL paths have a hierarchical structure and make use only of a limited set of characters (byte values), it is very likely that there are a lot of common prefixes. This allows us to easily reduce the routing into ever smaller problems.
149149

150150
For even better scalability, the child nodes on each tree level are ordered by priority, where the priority is just the number of handles registered in sub nodes (children, grandchildren, and so on..). This helps in two ways:
151151

@@ -173,3 +173,7 @@ definitely could be, just pass http.ResponseWriter as the response type.
173173
This repository is a fork of [julienschmidt/httprouter].
174174

175175
[julienschmidt/httprouter]: https://github.com/julienschmidt/httprouter
176+
177+
## License
178+
179+
BSD-3

example/example.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ func main() {
3131

3232
ctx := context.Background()
3333
resp := &Responder{}
34+
35+
// path=/ responded with: Welcome!
3436
router.Serve(ctx, "/", resp)
37+
// path=/hello/world responded with: hello, world!
3538
router.Serve(ctx, "/hello/world", resp)
39+
// path=/hello/reader responded with: hello, reader!
3640
router.Serve(ctx, "/hello/reader", resp)
3741
}

router.go

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,7 @@ type RouterConfig[W any] struct {
8989
// Enables automatic redirection if the current route can't be matched but a
9090
// handler for the path with (without) the trailing slash exists.
9191
// For example if /foo/ is requested but a route only exists for /foo, the
92-
// client is redirected to /foo with http status code 301 for GET requests
93-
// and 308 for all other request methods.
92+
// client is redirected to /foo
9493
RedirectTrailingSlash bool
9594

9695
// RedirectFixedPath configures the router to fix the current request path, if no
@@ -106,7 +105,7 @@ type RouterConfig[W any] struct {
106105
// NotFound is called when no matching route is found.
107106
NotFound Handle[W]
108107

109-
// Function to handle panics recovered from http handlers.
108+
// Function to handle panics recovered from handlers.
110109
// If nil, no recover() will be called (panics will throw).
111110
// The fourth parameter is the error from recover().
112111
PanicHandler func(ctx context.Context, reqPath string, rw W, panicErr interface{})
@@ -160,13 +159,7 @@ func (r *Router[W]) putParams(ps *Params) {
160159
}
161160
}
162161

163-
// AddHandler registers a new request handle with the given path and method.
164-
//
165-
// This function is intended for bulk loading and to allow the usage of less
166-
// frequently used, non-standardized or custom methods (e.g. for internal
167-
// communication with a proxy).
168-
//
169-
// NOTE: this function is NOT concurrency safe.
162+
// AddHandler registers a new request handle with the given path.
170163
func (r *Router[W]) AddHandler(path string, handle Handle[W]) {
171164
if handle == nil {
172165
return
@@ -283,5 +276,6 @@ func (r *Router[W]) Serve(ctx context.Context, reqPath string, wr W) (bool, erro
283276
if r.conf.NotFound == nil {
284277
return false, nil
285278
}
279+
286280
return r.conf.NotFound(ctx, reqPath, nil, wr)
287281
}

router_test.go

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,30 +7,13 @@ package pathrouter
77

88
import (
99
"context"
10-
"net/http"
1110
"reflect"
1211
"sync/atomic"
1312
"testing"
1413

1514
"github.com/pkg/errors"
1615
)
1716

18-
type mockResponseWriter struct{}
19-
20-
func (m *mockResponseWriter) Header() (h http.Header) {
21-
return http.Header{}
22-
}
23-
24-
func (m *mockResponseWriter) Write(p []byte) (n int, err error) {
25-
return len(p), nil
26-
}
27-
28-
func (m *mockResponseWriter) WriteString(s string) (n int, err error) {
29-
return len(s), nil
30-
}
31-
32-
func (m *mockResponseWriter) WriteHeader(int) {}
33-
3417
func TestParams(t *testing.T) {
3518
ps := Params{
3619
Param{"param1", "value1"},
@@ -152,7 +135,7 @@ func TestRouterNotFoundHandler(t *testing.T) {
152135
return true, nil
153136
}
154137

155-
router := NewWithConfig[struct{}](routerConf)
138+
router := NewWithConfig(routerConf)
156139
router.AddHandler("/path", handlerFunc)
157140

158141
// Test custom not found handler
@@ -172,7 +155,7 @@ func TestRouterPanicHandler(t *testing.T) {
172155
routerConf.PanicHandler = func(ctx context.Context, reqPath string, rw struct{}, panicErr interface{}) {
173156
panicHandled = true
174157
}
175-
router := NewWithConfig[struct{}](routerConf)
158+
router := NewWithConfig(routerConf)
176159

177160
router.AddHandler("/user/:name", func(ctx context.Context, reqPath string, p Params, rw struct{}) (bool, error) {
178161
panic("oops!")

0 commit comments

Comments
 (0)