mirror of
https://github.com/therootcompany/golib.git
synced 2026-01-27 23:18:05 +00:00
ref!(http/middleware): bump to v2 to use http.Handler rather than http.HandlerFunc
This commit is contained in:
parent
8136b7f4b9
commit
b559a25404
@ -8,8 +8,8 @@ A simple zero-cost middleware handler for Go's native `net/http` `ServeMux`. \
|
||||
Turns tedious this:
|
||||
|
||||
```go
|
||||
mux.HandleFunc("GET /api/version", logRequests(timeRequests(getVersion)))
|
||||
mux.HandleFunc("GET /api/data", logRequests(timeRequests(requireAuth(requireAdmin(getData)))))
|
||||
mux.Handle("GET /api/version", logRequests(timeRequests(http.HandlerFunc(getVersion))))
|
||||
mux.Handle("GET /api/data", logRequests(timeRequests(requireAuth(requireAdmin(http.HandlerFunc(getData))))))
|
||||
```
|
||||
|
||||
Into organizable this:
|
||||
@ -25,7 +25,7 @@ authMW.HandleFunc("GET /api/data", getData)
|
||||
Using stdlib this:
|
||||
|
||||
```go
|
||||
type Middleware func(http.HandlerFunc) http.HandlerFunc
|
||||
type Middleware func(http.Handler) http.Handler
|
||||
```
|
||||
|
||||
**Zero-cost** because each invocation of `mv.Handle(handler)` composes the function calls _exactly_ the same way as when done manually. \
|
||||
@ -49,12 +49,12 @@ import (
|
||||
func main() {
|
||||
mux := http.NewServeMux()
|
||||
|
||||
mw := middleware.New(logRequests, basicAuth)
|
||||
mux.HandleFunc("GET /api/data", mw.Handle(getData))
|
||||
mux.HandleFunc("POST /api/data", mw.Handle(postData))
|
||||
mw := middleware.WithMux(mux, recoverPanics, logRequests, basicAuth)
|
||||
mux.HandleFunc("GET /api/data", getData)
|
||||
mux.HandleFunc("POST /api/data", postData)
|
||||
|
||||
adminMW := mw.Use(requireAdmin)
|
||||
mux.HandleFunc("DELETE /api/data", adminMW.Handle(deleteData))
|
||||
adminMW.HandleFunc("DELETE /api/data", deleteData)
|
||||
|
||||
http.ListenAndServe(":8080", mux)
|
||||
}
|
||||
@ -62,16 +62,37 @@ func main() {
|
||||
|
||||
### Example Middleware
|
||||
|
||||
Middleware is any function that wraps and returns the built-in `http.HandlerFunc` handler type.
|
||||
Middleware is any function that wraps and returns the built-in `http.Handler` handler type.
|
||||
|
||||
```go
|
||||
type Middleware func(http.HandlerFunc) http.HandlerFunc
|
||||
type Middleware func(http.Handler) http.Handler
|
||||
```
|
||||
|
||||
#### Example: Panic handler
|
||||
|
||||
```go
|
||||
func recoverPanics(next http.Handler) http.Handler {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
if _err := recover(); _err != nil {
|
||||
err, ok := _err.(error)
|
||||
if !ok {
|
||||
err = fmt.Errorf("%v", _err)
|
||||
}
|
||||
api.InternalError(w, r, err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Example: Request logger
|
||||
|
||||
```go
|
||||
func logRequests(next http.HandlerFunc) http.HandlerFunc {
|
||||
func logRequests(next http.Handler) http.Handler {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
start := time.Now()
|
||||
@ -91,7 +112,7 @@ var creds = envauth.BasicCredentials{
|
||||
Password: os.Getenv("BASIC_AUTH_PASSWORD"),
|
||||
}
|
||||
|
||||
func basicAuth(next http.HandlerFunc) http.HandlerFunc {
|
||||
func basicAuth(next http.Handler) http.Handler {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
user, pass, _ := r.BasicAuth()
|
||||
@ -108,7 +129,7 @@ func basicAuth(next http.HandlerFunc) http.HandlerFunc {
|
||||
#### Example: Admin role checker
|
||||
|
||||
```go
|
||||
func requireAdmin(next http.HandlerFunc) http.HandlerFunc {
|
||||
func requireAdmin(next http.Handler) http.Handler {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Assume JWT in context with roles
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
module github.com/therootcompany/golib/http/middleware
|
||||
module github.com/therootcompany/golib/http/middleware/v2
|
||||
|
||||
go 1.24.6
|
||||
|
||||
@ -16,21 +16,22 @@ import (
|
||||
"slices"
|
||||
)
|
||||
|
||||
// Middleware receives and returns and http.HandlerFunc
|
||||
type Middleware func(http.HandlerFunc) http.HandlerFunc
|
||||
// Muxer can mux Handlers and HandleFuncs
|
||||
type Muxer interface {
|
||||
Handle(path string, handler http.Handler)
|
||||
HandleFunc(path string, handle func(w http.ResponseWriter, r *http.Request))
|
||||
}
|
||||
|
||||
// Middleware receives and returns and http.Handler
|
||||
type Middleware func(http.Handler) http.Handler
|
||||
|
||||
// MiddlewareChain enables inline chaining
|
||||
type MiddlewareChain struct {
|
||||
middlewares []Middleware
|
||||
}
|
||||
|
||||
// New creates a reusable MiddlewareChain with 0 or more middleware
|
||||
func New(middlewares ...Middleware) MiddlewareChain {
|
||||
return MiddlewareChain{middlewares: middlewares}
|
||||
}
|
||||
|
||||
// Handle composes middleware with the final handler
|
||||
func (c MiddlewareChain) Handle(handler http.HandlerFunc) http.HandlerFunc {
|
||||
func (c MiddlewareChain) Handle(handler http.Handler) http.Handler {
|
||||
if handler == nil {
|
||||
panic("mw.New(...).Use(...).Handle(-->this<--) requires a handler")
|
||||
}
|
||||
@ -48,20 +49,6 @@ func (c MiddlewareChain) Handle(handler http.HandlerFunc) http.HandlerFunc {
|
||||
return result
|
||||
}
|
||||
|
||||
// Use appends additional middleware to the chain
|
||||
func (c MiddlewareChain) Use(middlewares ...Middleware) MiddlewareChain {
|
||||
newMiddlewares := make([]Middleware, len(c.middlewares), len(c.middlewares)+len(middlewares))
|
||||
copy(newMiddlewares, c.middlewares)
|
||||
newMiddlewares = append(newMiddlewares, middlewares...)
|
||||
|
||||
return MiddlewareChain{middlewares: newMiddlewares}
|
||||
}
|
||||
|
||||
type Muxer interface {
|
||||
Handle(path string, handler http.Handler)
|
||||
HandleFunc(path string, handle func(w http.ResponseWriter, r *http.Request))
|
||||
}
|
||||
|
||||
// MiddlewareMux enables inline chaining
|
||||
type MiddlewareMux struct {
|
||||
middlewares []Middleware
|
||||
@ -89,15 +76,15 @@ func (c MiddlewareMux) With(middlewares ...Middleware) MiddlewareMux {
|
||||
}
|
||||
|
||||
func (c MiddlewareMux) Handle(path string, handler http.Handler) {
|
||||
c.mux.Handle(path, c.handle(handler.ServeHTTP))
|
||||
c.mux.Handle(path, c.handle(handler))
|
||||
}
|
||||
|
||||
func (c MiddlewareMux) HandleFunc(path string, handler http.HandlerFunc) {
|
||||
c.mux.HandleFunc(path, c.handle(handler))
|
||||
c.mux.Handle(path, c.handle(handler))
|
||||
}
|
||||
|
||||
// Handle composes middleware with the final handler
|
||||
func (c MiddlewareMux) handle(handler http.HandlerFunc) http.HandlerFunc {
|
||||
func (c MiddlewareMux) handle(handler http.Handler) http.Handler {
|
||||
if handler == nil {
|
||||
panic("mw.New(...).Use(...).Handle(-->this<--) requires a handler")
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user