Rene Nochebuena 32831d5a06 docs(httpmw): correct tier from 3 to 2 and fix logz tier ref
httpmw only depends on logz (Tier 1), placing it at Tier 2.
The previous docs incorrectly stated both the module tier (3) and
the logz tier (0).
2026-03-19 06:55:59 -06:00
2026-03-18 19:35:13 -06:00

httpmw

net/http middleware for transport-layer concerns: panic recovery, CORS, request ID injection, and structured request logging.

Overview

Four composable func(http.Handler) http.Handler middleware functions:

Middleware Responsibility
Recover() Catches panics; writes 500; captures stack trace
RequestID(generator) Generates a unique ID; injects it via logz.WithRequestID; sets X-Request-ID header
RequestLogger(logger) Logs method, path, status, latency, and request ID after each request
CORS(origins) Sets CORS headers; short-circuits OPTIONS with 204

No authentication or identity logic lives here — see httpauth-firebase for that.

Install

go get code.nochebuena.dev/go/httpmw

Usage

// Recommended order — outermost middleware first
mux.Use(httpmw.Recover())
mux.Use(httpmw.RequestID(uuid.NewString))
mux.Use(httpmw.RequestLogger(logger))
mux.Use(httpmw.CORS([]string{"https://example.com"}))

Pass []string{"*"} to CORS to allow any origin (development only).

Middleware

Recover

mux.Use(httpmw.Recover())

Wraps the handler in a defer/recover. On panic, writes 500 Internal Server Error and captures debug.Stack(). No logger is required.

RequestID

mux.Use(httpmw.RequestID(uuid.NewString))

Calls generator() on every request, stores the ID with logz.WithRequestID, and writes it to the X-Request-ID response header. Must run before RequestLogger so the ID is in context when the logger reads it.

RequestLogger

mux.Use(httpmw.RequestLogger(logger))

Logs method, path, status, latency, and request_id after the inner handler returns. Uses logger.Error for 5xx responses and logger.Info for all others.

CORS

mux.Use(httpmw.CORS([]string{"https://app.example.com", "https://admin.example.com"}))

Sets Access-Control-Allow-Origin, Access-Control-Allow-Methods, and Access-Control-Allow-Headers for matching origins. OPTIONS requests are short-circuited with 204 No Content.

Allowed methods: GET, HEAD, PUT, PATCH, POST, DELETE, OPTIONS Allowed headers: Content-Type, Authorization, X-Request-ID

Logger interface

RequestLogger accepts any value satisfying the Logger interface — satisfied by logz.Logger via duck typing:

type Logger interface {
    Info(msg string, args ...any)
    Error(msg string, err error, args ...any)
    With(args ...any) Logger
}

StatusRecorder

StatusRecorder is exported for use in custom middleware that needs to inspect the written status code:

rec := &httpmw.StatusRecorder{ResponseWriter: w, Status: http.StatusOK}
next.ServeHTTP(rec, r)
fmt.Println(rec.Status) // e.g. 404

Dependencies

  • code.nochebuena.dev/go/logz
Description
HTTP middleware toolkit: request ID, recovery, CORS, and structured request logging.
Readme MIT 48 KiB
2026-03-18 18:05:57 -06:00
Languages
Go 100%