go-router

Simple golang router.
This project is about simple http router that preserve http.Handler and
http.HanderFunc signature.
Every routing strategy (path.H.Compile, method.H.Compile,
segment.H.Compile) will produce http.HandlerFunc,
it can be mix with each other routing strategy.
It heavily use clousure and tail call, so it will be faster when
tail-cail-optimization implemented on golang. The routing decission tree is
precompute, so it should be faster.
see also https://pkg.go.dev/github.com/payfazz/go-middleware for middleware
see https://pkg.go.dev/github.com/payfazz/go-handler/v2 for alternative
signature of http handling
Host based routing
host package provide host based routing
example:
http.ListenAndServe(":8080", host.H{
"payfazz.com": handler1,
"api.payfazz.com": handler2,
}.C())
Method based routing
method pakcage provide method based routing, by itself method based routing is
not useful, but because it generate http.HandlerFunc you can mix it with
others
example:
http.ListenAndServe(":8080", path.H{
"/about": handler1,
"/data": method.H{
"GET": handler2,
"POST": handler3,
}.C(),
}.C())
Segment based routing
segment provide segment based routing
example:
http.ListenAndServe(":8080", segment.H{
"a": handler1,
"b": segment.H{
"c": handler2,
"d": handler3,
}.C(),
}.C())
Path based routing
path package is just tool to compose segment based routing.
h := path.H{
"/a": handler1,
"/b/c": handler2,
"/b/d": handler3,
}.C()
will be same with
h := segment.H{
"a": handler1,
"b": segment.H{
"c": handler2,
"d": handler3,
}.C(),
}.C()
path also provide parameter in path, because internally path use segment,
this parameter can be access via segment
http.ListenAndServe(":8080", path.H{
"a/:b/c/:d": func(w http.ResponseWriter, r *http.Request) {
b, _ := segment.Get(r, "b")
d, _ := segment.Get(r, "d")
// ...
},
}.C())
Quick Note
Routing is done by prefix segment matching, so
h := path.H{
"/a/b": handler1,
}.C()
will be still handling request to /a/b/c/d/e, if you need to only handle
/a/b you need to use segment.MustEnd middleware
h := path.H{
"/a/b": segment.MustEnd(handler1),
}.C()
This is intentionally, useful for path grouping
func main() {
http.ListenAndServe(":8080", root())
}
func root() http.HandlerFunc {
return path.H{
"/api": api(),
"/blog": blog(),
}.C()
}
func api() http.HandlerFunc {
return path.H{
"/order": orderHandler,
"/user": userHandler,
}.C()
}
request to /api/order will be handled by orderHandler
If you use https://pkg.go.dev/github.com/payfazz/go-middleware, you can easily
compose with another middleware, for example method.Must
h := path.H{
"/a/b": middleware.C(
segment.MustEnd,
method.Must("GET"),
handler1,
),
}.C()
TODO
- More documentation and examples
- create more testing
- make it faster by zero-allocation, current bottleneck:
- net/http.(*Request).WithContext
- strings.Split