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>
111 lines
3.4 KiB
Markdown
111 lines
3.4 KiB
Markdown
# lightmux
|
|
|
|
A small, idiomatic wrapper around Go 1.22+ `net/http.ServeMux` that adds method-named convenience methods, composable groups, and per-route middleware — without abandoning the stdlib pattern syntax.
|
|
|
|
## Installation
|
|
|
|
Requires Go 1.22 or later (uses `http.ServeMux`'s method+pattern syntax and `r.PathValue`).
|
|
|
|
```sh
|
|
go get git.juancwu.dev/juancwu/lightmux@v0.1.0
|
|
```
|
|
|
|
## Quick start
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"git.juancwu.dev/juancwu/lightmux"
|
|
)
|
|
|
|
func main() {
|
|
mux := lightmux.New()
|
|
|
|
mux.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
|
fmt.Fprintln(w, "hello from lightmux")
|
|
})
|
|
|
|
mux.Get("/users/{id}", func(w http.ResponseWriter, r *http.Request) {
|
|
id, err := strconv.Atoi(r.PathValue("id"))
|
|
if err != nil {
|
|
http.Error(w, "bad id", http.StatusBadRequest)
|
|
return
|
|
}
|
|
fmt.Fprintf(w, "user %d\n", id)
|
|
})
|
|
|
|
api := mux.Group("/api")
|
|
api.Get("/ping", func(w http.ResponseWriter, r *http.Request) {
|
|
fmt.Fprintln(w, "pong")
|
|
})
|
|
|
|
log.Fatal(http.ListenAndServe(":8080", mux))
|
|
}
|
|
```
|
|
|
|
## Groups
|
|
|
|
`Group` returns a sub-mux that shares the underlying ServeMux but carries its own prefix and middleware stack. Groups can be nested.
|
|
|
|
```go
|
|
api := mux.Group("/api", authMiddleware)
|
|
api.Get("/users/{id}", getUser)
|
|
|
|
v1 := api.Group("/v1")
|
|
v1.Get("/ping", pong) // registered as "GET /api/v1/ping"
|
|
```
|
|
|
|
Middleware is snapshotted into the child at `Group()` time. Calling `parent.Use(mw)` *after* a `Group()` does not retroactively wrap the child's routes — register middleware before creating groups, or pass it to `Group(prefix, mw...)` explicitly.
|
|
|
|
## Middleware
|
|
|
|
There are two ways to attach middleware: chain-style with `Use`, or per-route as a variadic tail.
|
|
|
|
```go
|
|
mux := lightmux.New()
|
|
mux.Use(authMiddleware) // applies to every route registered after
|
|
|
|
mux.Get("/admin", adminHandler, requireAdmin) // requireAdmin only on this route
|
|
```
|
|
|
|
Order is outer → inner: `Use`-order first, then per-route mws. The outermost middleware runs first on the request and last on the response.
|
|
|
|
Middleware values are plain `func(http.Handler) http.Handler`, so any stdlib-compatible middleware works without an adapter.
|
|
|
|
An opinionated set of middlewares (request logging, panic recovery, real-IP resolution) lives in a sibling module — see [lightmux-contrib](https://git.juancwu.dev/juancwu/lightmux-contrib):
|
|
|
|
```sh
|
|
go get git.juancwu.dev/juancwu/lightmux-contrib
|
|
```
|
|
|
|
```go
|
|
import (
|
|
"git.juancwu.dev/juancwu/lightmux-contrib/realip"
|
|
"git.juancwu.dev/juancwu/lightmux-contrib/recoverer"
|
|
"git.juancwu.dev/juancwu/lightmux-contrib/requestlog"
|
|
)
|
|
|
|
mux.Use(recoverer.New(), realip.New(), requestlog.New(nil))
|
|
```
|
|
|
|
## Path parameters
|
|
|
|
lightmux is a thin wrapper, so path parameters work the stdlib way:
|
|
|
|
```go
|
|
mux.Get("/items/{name}", func(w http.ResponseWriter, r *http.Request) {
|
|
fmt.Fprintln(w, r.PathValue("name"))
|
|
})
|
|
```
|
|
|
|
## Notes
|
|
|
|
- `mux.Get("/", h)` registers `"GET /"`, which is a stdlib **subtree** pattern — it matches every unmatched path. Use `"/{$}"` to match only the literal root.
|
|
- Bad route registrations (invalid prefix, conflicting wildcards) panic at startup, matching stdlib `http.ServeMux` behavior. The `recoverer` middleware in [lightmux-contrib](https://git.juancwu.dev/juancwu/lightmux-contrib) handles panics that occur *inside* request handlers.
|
|
- Group prefixes apply to the path only — they never inject a host. Routes can still carry an explicit host via `Handle("GET host.com/path", h)`.
|