Created
February 14, 2024 16:40
-
-
Save alexaandru/747f9d7bdfb1fa35140b359bf23fa820 to your computer and use it in GitHub Desktop.
Chi-like syntactic sugar layer on top of stdlib http.ServeMux
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Chi-like syntactic sugar layer on top of stdlib http.ServeMux. | |
package main | |
import ( | |
"net/http" | |
"slices" | |
) | |
type ( | |
middleware func(http.Handler) http.Handler | |
router struct { | |
*http.ServeMux | |
chain []middleware | |
} | |
) | |
func NewRouter(mx ...middleware) *router { | |
return &router{ServeMux: &http.ServeMux{}, chain: mx} | |
} | |
func (r *router) Use(mx ...middleware) { | |
r.chain = append(r.chain, mx...) | |
} | |
func (r *router) Group(fn func(r *router)) { | |
fn(&router{ServeMux: r.ServeMux, chain: slices.Clone(r.chain)}) | |
} | |
func (r *router) Get(path string, fn http.HandlerFunc, mx ...middleware) { | |
r.handle(http.MethodGet, path, fn, mx) | |
} | |
func (r *router) Post(path string, fn http.HandlerFunc, mx ...middleware) { | |
r.handle(http.MethodPost, path, fn, mx) | |
} | |
func (r *router) Put(path string, fn http.HandlerFunc, mx ...middleware) { | |
r.handle(http.MethodPut, path, fn, mx) | |
} | |
func (r *router) Delete(path string, fn http.HandlerFunc, mx ...middleware) { | |
r.handle(http.MethodDelete, path, fn, mx) | |
} | |
func (r *router) Head(path string, fn http.HandlerFunc, mx ...middleware) { | |
r.handle(http.MethodHead, path, fn, mx) | |
} | |
func (r *router) Options(path string, fn http.HandlerFunc, mx ...middleware) { | |
r.handle(http.MethodOptions, path, fn, mx) | |
} | |
func (r *router) handle(method, path string, fn http.HandlerFunc, mx []middleware) { | |
r.Handle(method+" "+path, r.wrap(fn, mx)) | |
} | |
func (r *router) wrap(fn http.HandlerFunc, mx []middleware) (out http.Handler) { | |
out, mx = http.Handler(fn), append(slices.Clone(r.chain), mx...) | |
slices.Reverse(mx) | |
for _, m := range mx { | |
out = m(out) | |
} | |
return | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"log" | |
"net/http" | |
) | |
func mid(i int) middleware { | |
return func(next http.Handler) http.Handler { | |
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | |
fmt.Println("mid", i, "start") | |
next.ServeHTTP(w, r) | |
fmt.Println("mid", i, "done") | |
}) | |
} | |
} | |
func someHandler(w http.ResponseWriter, r *http.Request) { | |
fmt.Println("[the handler ran here]") | |
fmt.Fprintln(w, "Hello world of", r.URL.Path) | |
} | |
func main() { | |
r := NewRouter(mid(0)) | |
r.Group(func(r *router) { | |
r.Use(mid(1), mid(2)) | |
r.Get("/foo", someHandler) | |
}) | |
r.Group(func(r *router) { | |
r.Use(mid(3)) | |
r.Get("/bar", someHandler, mid(4)) | |
r.Get("/baz", someHandler, mid(5)) | |
}) | |
r.Post("/foobar", someHandler) | |
log.Fatal(http.ListenAndServe(":3000", r)) | |
} |
https://github.com/eltimn/todo-plus/blob/main/pkg/router/router.go
I figured that out after I posted this. I ended up using
r.ServeMux.Handle
on line 54 and then passedr.ServeMux
toListenAndServe
, but your original code works fine.Anyway, thanks for posting this. I built a working example with error handling: https://github.com/eltimn/todo-plus/blob/main/cmd/server/router/router.go
https://github.com/eltimn/todo-plus/blob/main/pkg/router/router.go updated link
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You're most welcome!