middleware

package
v0.8.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 20, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package middleware provides standard net/http server middleware for skit services.

It covers the cross-cutting concerns most HTTP services need: panic recovery, trace-context injection, structured access logging, request timeouts, body-size limits, CORS, security headers, response compression, and request-id echo. Every middleware has the signature func(http.Handler) http.Handler (aliased as Middleware), so it composes with router.Use, router.With, and go-pkgz/routegroup. Because TraceRequest seeds a trace id and AccessLog logs through the skit logger, log lines carry trace_id automatically.

These are the transport layer of the two-layer model (see the router package): they wrap the encoded response and every route — including raw http.Handlers and the typed rest boundary — via router.Use / router.With. Concerns that need the typed ResponseEncoder a handler returns (auth, validation, error localization) belong instead in the application layer as rest.MidFunc (router.UseApp / WithApp / per-route).

Ordering

Register them outermost-first. Panics goes first so it wraps everything; TraceRequest next so downstream logs and spans share the request's trace context; then AccessLog, then the limit/timeout guards:

r := router.New(appMids...)
r.Use(
	middleware.Panics(log),            // recover -> 500, log stack
	middleware.TraceRequest(tracer),   // extract/seed W3C trace context
	middleware.AccessLog(log),         // one structured line per request
	middleware.SizeLimit(1<<20),       // cap request body at 1 MiB
	middleware.Timeout(5*time.Second), // cancel ctx after 5s
)

Middleware

  • Panics(log): recover from panics, log the stack, respond 500. A nil log skips logging.
  • TraceRequest(tracer): extract incoming W3C trace context and ensure a trace id is available for logging.
  • AccessLog(log): emit one structured line per request using OpenTelemetry HTTP semantic-convention field names. A nil log skips logging.
  • Timeout(d): cancel the request context after d; a non-positive d disables it (returns next unchanged).
  • SizeLimit(n): cap the request body at n bytes via http.MaxBytesReader; a non-positive n disables it.
  • CORS(cfg): apply a cross-origin policy — set Access-Control-* headers on allowed origins and answer preflight OPTIONS with 204.
  • SecureHeaders(): set conservative security response headers (nosniff, frame-deny, no-referrer) without overriding ones a handler set.
  • Compress(): gzip responses when the client sends Accept-Encoding: gzip.
  • RequestID(): echo the correlation id (incoming X-Request-ID, else the trace id) in the X-Request-ID response header.

The last four are not part of the generated scaffold's default chain — wire them per service (CORS in particular needs a per-deployment origin policy).

Index

Constants

View Source
const RequestIDHeader = "X-Request-ID"

RequestIDHeader is the header RequestID reads and echoes.

Variables

This section is empty.

Functions

This section is empty.

Types

type CORSConfig added in v0.6.0

type CORSConfig struct {
	// AllowedOrigins is the set of permitted Origin values, e.g.
	// {"https://app.example.com"}. The single entry "*" allows any origin.
	AllowedOrigins []string
	// AllowedMethods defaults to GET, POST, PUT, PATCH, DELETE, OPTIONS.
	AllowedMethods []string
	// AllowedHeaders defaults to Origin, Content-Type, Accept, Authorization.
	AllowedHeaders []string
	// ExposedHeaders lists response headers the browser is allowed to read.
	ExposedHeaders []string
	// AllowCredentials sets Access-Control-Allow-Credentials. With credentials
	// the wildcard is never sent: the specific request Origin is echoed instead
	// (browsers reject "*" with credentials).
	AllowCredentials bool
	// MaxAge is the preflight cache lifetime in seconds (Access-Control-Max-Age).
	MaxAge int
}

CORSConfig configures the CORS middleware. The zero value allows no origins (every cross-origin request is passed through without CORS headers, so the browser blocks it) — set AllowedOrigins to opt in.

type Middleware

type Middleware = func(http.Handler) http.Handler

Middleware is standard net/http middleware.

func AccessLog

func AccessLog(log *logger.Logger) Middleware

AccessLog logs one structured line per request. Because it logs through the skit logger, each line carries the request's trace_id automatically.

func CORS added in v0.6.0

func CORS(cfg CORSConfig) Middleware

CORS returns middleware applying the policy in cfg. It sets the Access-Control-* headers on allowed cross-origin responses and answers the preflight OPTIONS request with 204. Requests without an Origin are passed through untouched; a request from a disallowed origin gets no CORS headers (so the browser blocks it), and a disallowed preflight is short-circuited with 204 and no Allow-* headers.

func Compress added in v0.6.0

func Compress() Middleware

Compress returns middleware that gzip-encodes responses when the client sends "Accept-Encoding: gzip". It sets Content-Encoding: gzip and Vary: Accept-Encoding, and drops the (now-wrong) Content-Length. Bodyless responses (1xx, 204, 304) are never encoded, and a handler that already set Content-Encoding is left alone. Flusher is preserved.

func Panics

func Panics(log *logger.Logger) Middleware

Panics recovers panics, logs the stack, and responds with 500.

func RequestID added in v0.6.0

func RequestID() Middleware

RequestID echoes a request correlation id in the X-Request-ID response header. It reuses the client's incoming X-Request-ID when present; otherwise it falls back to the active trace id (so put this after TraceRequest in the chain). It never overwrites an id a handler set itself. When no id is available it does nothing — it does not synthesize one (tracing owns id generation).

func SecureHeaders added in v0.6.0

func SecureHeaders() Middleware

SecureHeaders sets a conservative set of security response headers on every response — safe defaults for a JSON API:

X-Content-Type-Options: nosniff   // do not MIME-sniff the body
X-Frame-Options: DENY             // never framed (clickjacking)
Referrer-Policy: no-referrer      // do not leak the URL in Referer

It only sets a header when the handler has not already set it, so a handler that needs a different value (e.g. an endpoint meant to be embedded) wins.

func SizeLimit

func SizeLimit(n int64) Middleware

SizeLimit caps the request body at n bytes. A non-positive n disables it.

func Timeout

func Timeout(d time.Duration) Middleware

Timeout cancels the request context after d and (if nothing was written) lets downstream handlers observe ctx.Err. A non-positive d disables the middleware.

func TraceRequest

func TraceRequest(tracer trace.Tracer) Middleware

TraceRequest seeds the request context with trace context extracted from incoming headers and ensures a trace id is available for logging.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL