-
Release v0.9.0 Stable
released this
2026-03-18 18:05:57 -06:00 | 2 commits to main since this releasev0.9.0
code.nochebuena.dev/go/httpmwOverview
httpmwprovides standalonenet/httpmiddleware functions for transport-layer concerns:
panic recovery, CORS, request ID injection, and structured request logging. Each function
is independent; no authentication or identity logic is included (seehttpauth-firebase
for that).This is the initial stable release. The API has been designed through multiple architecture
reviews and validated end-to-end via the todo-api POC. It is versioned v0.9.0 rather than
v1.0.0 because it has not yet been exercised across all production edge cases, and minor
API refinements may follow.What's Included
Recover() func(http.Handler) http.Handler
— catches panics from inner handlers, captures the stack trace, and writes 500; requires
no logger injectionCORS(origins []string) func(http.Handler) http.Handler
— setsAccess-Control-Allow-*headers for matching origins; responds 204 to OPTIONS
preflight requests; pass[]string{"*"}for developmentRequestID(generator func() string) func(http.Handler) http.Handler
— generates a request ID using the provided function (e.g.uuid.NewString), injects it
into the context vialogz.WithRequestID, and sets theX-Request-IDresponse headerRequestLogger(logger Logger) func(http.Handler) http.Handler
— logs method, path, status code, latency, and request ID after the inner handler returns;
useslogger.Errorfor 5xx responses andlogger.Infofor all othersLoggerinterface — duck-typed; satisfied bylogz.Logger:type Logger interface { Info(msg string, args ...any) Error(msg string, err error, args ...any) With(args ...any) Logger }StatusRecorder— exportedhttp.ResponseWriterwrapper that captures the written status
code; useful for custom logging middleware
Installation
go get code.nochebuena.dev/go/httpmw@v0.9.0import "code.nochebuena.dev/go/httpmw" // Recommended middleware order (outermost first): mux.Use(httpmw.Recover()) mux.Use(httpmw.RequestID(uuid.NewString)) mux.Use(httpmw.RequestLogger(logger)) mux.Use(httpmw.CORS([]string{"https://example.com"}))Design Highlights
Direct
logzimport for context helpers.RequestIDuseslogz.WithRequestIDand
RequestLoggeruseslogz.GetRequestIDto store and retrieve the request ID in the
context. These helpers use an unexported context key; re-implementing the key inhttpmw
would break interoperability withlogz.Logger.WithContextdownstream. This is a
documented exception to the global ADR-001 duck-type rule — Logger injection is still
duck-typed, but context key access requires the direct import.Recoverrequires no configuration. It captures the stack trace viadebug.Stack
internally but does not currently log it. The stack is retained for future logger injection.
This keepsRecoverusable with zero setup.CORS is allowlist-based. Allowed methods (
GET, HEAD, PUT, PATCH, POST, DELETE, OPTIONS)
and allowed headers (Content-Type, Authorization, X-Request-ID) are package-wide constants.
Per-route configuration is not supported.No middleware is installed by default. The package exports functions; the application
chooses which middleware to use and in what order.Known Limitations & Edge Cases
Logger.WithreturnsLogger(thehttpmwinterface type), notlogz.Logger. A
caller that implementsLoggerand callsWithmust ensure their implementation returns
a value that also satisfies the interface. Wrapping alogz.Loggerdirectly requires a
thin adapter struct at the call site.Recoverdoes not log panics in the current release. Panic information is captured but
discarded. If panic logging is required, wrapRecoverwith a custom middleware that logs
first, or wait for logger injection to be added.- No rate-limiting middleware is included by design. Rate limiting belongs at the
infrastructure layer (reverse proxy, API gateway) or in a dedicated module. - No authentication or RBAC middleware is included by design. See
httpauth-firebase. - CORS headers are package-wide constants. Per-route CORS configuration requires the
router's built-in support. RequestIDmust run beforeRequestLoggerin the middleware chain. If the order is
reversed, request IDs will be empty in log records.
v0.9.0 → v1.0.0 Roadmap
- Add optional logger injection to
Recoverso panics are logged with the stack trace. - Evaluate whether
Logger.Withshould returnanyor be removed from the interface to
eliminate the adapter requirement at call sites. - Consider exposing the CORS allowed methods and headers as
Configfields. - Validate behaviour under high concurrency for
StatusRecorder(ensure no data races
when the writer is used concurrently).
Downloads