extract middlewares to lightmux-contrib

Removes pkg/middleware. The Logger, Recoverer, and RealIP middlewares
now live in the sibling lightmux-contrib module as the realip,
requestlog, and recoverer packages, each exposing a single New(...)
constructor.

The Middleware type alias moves to pkg/router. The splinter dependency
is dropped from go.mod; only errx remains.

BREAKING CHANGE: consumers must replace pkg/middleware imports with
the corresponding lightmux-contrib sub-packages. See README for the
new usage.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
juancwu 2026-04-26 14:02:54 +00:00
commit 22277186ae
15 changed files with 44 additions and 612 deletions

View file

@ -1,15 +1,11 @@
package router
import (
"net/http"
"git.juancwu.dev/juancwu/lightmux/pkg/middleware"
)
import "net/http"
// chain wraps h with groupMws followed by routeMws so that groupMws[0] is the
// outermost layer (runs first on request, last on response).
func chain(h http.Handler, groupMws, routeMws []middleware.Middleware) http.Handler {
all := make([]middleware.Middleware, 0, len(groupMws)+len(routeMws))
func chain(h http.Handler, groupMws, routeMws []Middleware) http.Handler {
all := make([]Middleware, 0, len(groupMws)+len(routeMws))
all = append(all, groupMws...)
all = append(all, routeMws...)
for i := len(all) - 1; i >= 0; i-- {

View file

@ -5,11 +5,9 @@ import (
"net/http/httptest"
"strings"
"testing"
"git.juancwu.dev/juancwu/lightmux/pkg/middleware"
)
func tagMW(log *[]string, tag string) middleware.Middleware {
func tagMW(log *[]string, tag string) Middleware {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
*log = append(*log, tag+":before")
@ -26,8 +24,8 @@ func TestChainOrder(t *testing.T) {
})
wrapped := chain(h,
[]middleware.Middleware{tagMW(&log, "g1"), tagMW(&log, "g2")},
[]middleware.Middleware{tagMW(&log, "r1"), tagMW(&log, "r2")},
[]Middleware{tagMW(&log, "g1"), tagMW(&log, "g2")},
[]Middleware{tagMW(&log, "r1"), tagMW(&log, "r2")},
)
req := httptest.NewRequest(http.MethodGet, "/", nil)

7
pkg/router/middleware.go Normal file
View file

@ -0,0 +1,7 @@
package router
import "net/http"
// Middleware is the standard func(http.Handler) http.Handler middleware shape,
// compatible with any stdlib-style middleware.
type Middleware = func(http.Handler) http.Handler

View file

@ -4,16 +4,12 @@
// underlying mux while carrying their own prefix and middleware stack.
package router
import (
"net/http"
"git.juancwu.dev/juancwu/lightmux/pkg/middleware"
)
import "net/http"
type Mux struct {
root *http.ServeMux
prefix string
middlewares []middleware.Middleware
middlewares []Middleware
}
func New() *Mux {
@ -21,16 +17,16 @@ func New() *Mux {
return &Mux{root: sm}
}
func (m *Mux) Use(mws ...middleware.Middleware) {
func (m *Mux) Use(mws ...Middleware) {
m.middlewares = append(m.middlewares, mws...)
}
// Group returns a child Mux that registers on the same underlying ServeMux but
// with its prefix appended and the parent's current middlewares snapshotted.
// Use() calls made on the parent after Group() do not propagate to the child.
func (m *Mux) Group(prefix string, mws ...middleware.Middleware) *Mux {
func (m *Mux) Group(prefix string, mws ...Middleware) *Mux {
validateGroupPrefix(prefix)
mwsCopy := make([]middleware.Middleware, 0, len(m.middlewares)+len(mws))
mwsCopy := make([]Middleware, 0, len(m.middlewares)+len(mws))
mwsCopy = append(mwsCopy, m.middlewares...)
mwsCopy = append(mwsCopy, mws...)
return &Mux{
@ -40,45 +36,45 @@ func (m *Mux) Group(prefix string, mws ...middleware.Middleware) *Mux {
}
}
func (m *Mux) Handle(pattern string, h http.Handler, mws ...middleware.Middleware) {
func (m *Mux) Handle(pattern string, h http.Handler, mws ...Middleware) {
full := buildPattern("", m.prefix, pattern)
m.root.Handle(full, chain(h, m.middlewares, mws))
}
func (m *Mux) HandleFunc(pattern string, fn http.HandlerFunc, mws ...middleware.Middleware) {
func (m *Mux) HandleFunc(pattern string, fn http.HandlerFunc, mws ...Middleware) {
m.Handle(pattern, fn, mws...)
}
func (m *Mux) method(method, path string, fn http.HandlerFunc, mws []middleware.Middleware) {
func (m *Mux) method(method, path string, fn http.HandlerFunc, mws []Middleware) {
full := buildPattern(method, m.prefix, path)
m.root.Handle(full, chain(fn, m.middlewares, mws))
}
func (m *Mux) Get(path string, fn http.HandlerFunc, mws ...middleware.Middleware) {
func (m *Mux) Get(path string, fn http.HandlerFunc, mws ...Middleware) {
m.method(http.MethodGet, path, fn, mws)
}
func (m *Mux) Post(path string, fn http.HandlerFunc, mws ...middleware.Middleware) {
func (m *Mux) Post(path string, fn http.HandlerFunc, mws ...Middleware) {
m.method(http.MethodPost, path, fn, mws)
}
func (m *Mux) Put(path string, fn http.HandlerFunc, mws ...middleware.Middleware) {
func (m *Mux) Put(path string, fn http.HandlerFunc, mws ...Middleware) {
m.method(http.MethodPut, path, fn, mws)
}
func (m *Mux) Patch(path string, fn http.HandlerFunc, mws ...middleware.Middleware) {
func (m *Mux) Patch(path string, fn http.HandlerFunc, mws ...Middleware) {
m.method(http.MethodPatch, path, fn, mws)
}
func (m *Mux) Delete(path string, fn http.HandlerFunc, mws ...middleware.Middleware) {
func (m *Mux) Delete(path string, fn http.HandlerFunc, mws ...Middleware) {
m.method(http.MethodDelete, path, fn, mws)
}
func (m *Mux) Options(path string, fn http.HandlerFunc, mws ...middleware.Middleware) {
func (m *Mux) Options(path string, fn http.HandlerFunc, mws ...Middleware) {
m.method(http.MethodOptions, path, fn, mws)
}
func (m *Mux) Head(path string, fn http.HandlerFunc, mws ...middleware.Middleware) {
func (m *Mux) Head(path string, fn http.HandlerFunc, mws ...Middleware) {
m.method(http.MethodHead, path, fn, mws)
}