middleware

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Feb 23, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package middleware provides production-ready HTTP middleware that works with any net/http compatible router.

All middleware follows the standard func(http.Handler) http.Handler signature.

Usage:

stack := middleware.Chain(
    middleware.RequestID(),
    middleware.Logger(logger),
    middleware.Recover(),
    middleware.CORS(middleware.DefaultCORSConfig()),
    middleware.Timeout(30 * time.Second),
)

http.ListenAndServe(":8080", stack(mux))

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GetAuthUser

func GetAuthUser(ctx context.Context) any

GetAuthUser retrieves the authenticated user from the request context. Returns nil if no user is set.

func GetAuthUserAs

func GetAuthUserAs[T any](ctx context.Context) (T, bool)

GetAuthUserAs retrieves the authenticated user with type assertion.

user, ok := middleware.GetAuthUserAs[*User](r.Context())

func GetRequestID

func GetRequestID(ctx context.Context) string

GetRequestID retrieves the request ID from the context.

func Then

func Then(handler http.Handler, middlewares ...Middleware) http.Handler

Then is an alias for applying middleware to a handler. Equivalent to Chain(middlewares...)(handler).

Types

type AuthConfig

type AuthConfig struct {
	// Authenticate is the function that validates credentials and returns user info.
	// The token/key string is extracted from the request based on the scheme.
	// Return any user object to store in context, or error to reject.
	Authenticate func(ctx context.Context, token string) (any, error)

	// Scheme determines where to extract credentials from.
	// Default: "bearer"
	// Options: "bearer", "api-key"
	Scheme string

	// APIKeyHeader is the header name for API key auth.
	// Default: "X-API-Key"
	APIKeyHeader string

	// SkipPaths are paths that bypass authentication.
	SkipPaths map[string]bool

	// ErrorMessage is the message for unauthorized responses.
	// Default: "Authentication required"
	ErrorMessage string
}

AuthConfig configures authentication middleware.

type CORSConfig

type CORSConfig struct {
	// AllowOrigins is a list of allowed origins.
	// Use "*" to allow all origins (not recommended for production with credentials).
	// Default: []
	AllowOrigins []string

	// AllowMethods is a list of allowed HTTP methods.
	// Default: GET, POST, PUT, PATCH, DELETE, OPTIONS
	AllowMethods []string

	// AllowHeaders is a list of allowed request headers.
	// Default: Content-Type, Authorization, X-Request-ID
	AllowHeaders []string

	// ExposeHeaders is a list of headers the browser is allowed to access.
	// Default: X-Request-ID
	ExposeHeaders []string

	// AllowCredentials indicates whether credentials (cookies, auth headers) are allowed.
	// Default: false
	AllowCredentials bool

	// MaxAge is how long preflight results can be cached.
	// Default: 12 hours
	MaxAge time.Duration
}

CORSConfig configures the CORS middleware.

func DefaultCORSConfig

func DefaultCORSConfig() CORSConfig

DefaultCORSConfig returns a permissive CORS configuration for development. For production, you should specify AllowOrigins explicitly.

type LoggerConfig

type LoggerConfig struct {
	// Logger is the slog.Logger to use. Default: slog.Default()
	Logger *slog.Logger

	// Level is the default log level for successful requests. Default: slog.LevelInfo
	Level slog.Level

	// SkipPaths is a set of paths to skip logging for (e.g., health checks).
	SkipPaths map[string]bool

	// LogRequestBody logs the request body (use with caution — PII concerns).
	// Default: false
	LogRequestBody bool

	// LogResponseBody logs the response body.
	// Default: false
	LogResponseBody bool
}

LoggerConfig configures the Logger middleware.

func DefaultLoggerConfig

func DefaultLoggerConfig() LoggerConfig

DefaultLoggerConfig returns the default logger configuration.

type Middleware

type Middleware func(http.Handler) http.Handler

Middleware is a function that wraps an http.Handler.

func Auth

func Auth(cfg AuthConfig) Middleware

Auth creates an authentication middleware.

Example with bearer token:

auth := middleware.Auth(middleware.AuthConfig{
    Authenticate: func(ctx context.Context, token string) (any, error) {
        user, err := verifyJWT(token)
        if err != nil { return nil, errors.Unauthorized("Invalid token") }
        return user, nil
    },
    SkipPaths: map[string]bool{"/health": true, "/login": true},
})

func BodyLimit

func BodyLimit(maxBytes int64) Middleware

BodyLimit limits the maximum request body size. Requests exceeding the limit receive a 413 Payload Too Large response.

mux.Handle("/upload", middleware.BodyLimit(10<<20)(handler)) // 10 MB

func CORS

func CORS(cfg CORSConfig) Middleware

CORS adds Cross-Origin Resource Sharing headers.

func Chain

func Chain(middlewares ...Middleware) Middleware

Chain composes multiple middleware into a single middleware. Middleware is applied in the order provided (first middleware is outermost).

stack := middleware.Chain(first, second, third)
// Request flow: first → second → third → handler
// Response flow: third → second → first → client

func Logger

func Logger(logger *slog.Logger) Middleware

Logger logs each HTTP request with structured fields. Logs: method, path, status, duration, request_id, client_ip, user_agent.

func LoggerWithConfig

func LoggerWithConfig(cfg LoggerConfig) Middleware

LoggerWithConfig creates a logging middleware with custom configuration.

func RateLimit

func RateLimit(cfg RateLimitConfig) Middleware

RateLimit applies rate limiting per client.

func Recover

func Recover() Middleware

Recover recovers from panics and returns a 500 JSON response. Internal error details are logged but NOT exposed to clients.

func RecoverWithConfig

func RecoverWithConfig(cfg RecoverConfig) Middleware

RecoverWithConfig recovers from panics with custom configuration.

func RequestID

func RequestID() Middleware

RequestID adds a unique request ID to each request. The ID is stored in the request context and set as a response header.

func RequestIDWithConfig

func RequestIDWithConfig(cfg RequestIDConfig) Middleware

RequestIDWithConfig adds request IDs with custom configuration.

func RequireRole

func RequireRole(role string, roleExtractor func(ctx context.Context) []string) Middleware

RequireRole creates middleware that checks if the authenticated user has a required role. The roleExtractor function should return the user's roles from the context.

func SecureHeaders

func SecureHeaders() Middleware

SecureHeaders adds security headers to responses.

func SecureHeadersWithConfig

func SecureHeadersWithConfig(cfg SecurityHeadersConfig) Middleware

SecureHeadersWithConfig adds security headers with custom configuration.

func Timeout

func Timeout(duration time.Duration) Middleware

Timeout wraps each request with a context deadline. If the handler doesn't complete within the timeout, a 504 response is sent.

mux.Handle("/slow", middleware.Timeout(5*time.Second)(handler))

type RateLimitConfig

type RateLimitConfig struct {
	// Limiter is the rate limiting backend.
	// If nil, a default in-memory token bucket is used.
	Limiter RateLimiter

	// KeyFunc extracts the rate limit key from the request.
	// Default: uses client IP from RemoteAddr (safe).
	// Set TrustProxy to true if behind a reverse proxy.
	KeyFunc func(r *http.Request) string

	// TrustProxy enables reading client IP from X-Forwarded-For and X-Real-IP headers.
	// Only enable this if your server is behind a trusted reverse proxy.
	// Default: false (uses RemoteAddr only)
	TrustProxy bool

	// Rate is the number of requests allowed per window (for default limiter).
	// Default: 100
	Rate int

	// Window is the time window for the rate limit (for default limiter).
	// Default: 1 minute
	Window time.Duration

	// Message is the error message sent when rate limited.
	// Default: "Rate limit exceeded"
	Message string
}

RateLimitConfig configures the rate limiting middleware.

func DefaultRateLimitConfig

func DefaultRateLimitConfig() RateLimitConfig

DefaultRateLimitConfig returns sensible rate limit defaults.

type RateLimiter

type RateLimiter interface {
	// Allow checks if a request from the given key is allowed.
	// Returns true if allowed, false if rate limited.
	Allow(key string) bool
}

RateLimiter defines the interface for rate limiting backends. Implement this interface to use Redis, memcached, etc.

type RecoverConfig

type RecoverConfig struct {
	// Logger is used to log panic details.
	// If nil, uses slog.Default().
	Logger *slog.Logger

	// EnableStackTrace includes the stack trace in logs.
	// Default: true
	EnableStackTrace bool

	// OnPanic is called when a panic is recovered.
	// If nil, a default handler is used.
	OnPanic func(w http.ResponseWriter, r *http.Request, recovered any)
}

RecoverConfig configures the Recover middleware.

func DefaultRecoverConfig

func DefaultRecoverConfig() RecoverConfig

DefaultRecoverConfig returns the default configuration.

type RequestIDConfig

type RequestIDConfig struct {
	// Header is the header to read/write the request ID.
	// Default: "X-Request-ID"
	Header string

	// Generator is a function that generates a new request ID.
	// Default: generates a random 16-byte hex string.
	Generator func() string

	// TrustProxy trusts the incoming X-Request-ID header if present.
	// If false, always generates a new ID.
	// Default: true
	TrustProxy bool
}

RequestIDConfig configures the RequestID middleware.

func DefaultRequestIDConfig

func DefaultRequestIDConfig() RequestIDConfig

DefaultRequestIDConfig returns the default configuration.

type SecurityHeadersConfig

type SecurityHeadersConfig struct {
	// ContentTypeNosniff sets X-Content-Type-Options: nosniff
	// Default: true
	ContentTypeNosniff bool

	// XFrameOptions sets X-Frame-Options. Common values: DENY, SAMEORIGIN
	// Default: "DENY"
	XFrameOptions string

	// XSSProtection sets X-XSS-Protection.
	// Default: "1; mode=block"
	XSSProtection string

	// HSTSMaxAge sets Strict-Transport-Security max-age in seconds.
	// Set to 0 to disable. Default: 31536000 (1 year)
	HSTSMaxAge int

	// HSTSIncludeSubdomains adds includeSubDomains to HSTS.
	// Default: true
	HSTSIncludeSubdomains bool

	// ReferrerPolicy sets Referrer-Policy header.
	// Default: "strict-origin-when-cross-origin"
	ReferrerPolicy string

	// ContentSecurityPolicy sets Content-Security-Policy header.
	// Default: "" (not set)
	ContentSecurityPolicy string

	// PermissionsPolicy sets Permissions-Policy header.
	// Default: "" (not set)
	PermissionsPolicy string
}

SecurityHeadersConfig configures security headers.

func DefaultSecurityHeadersConfig

func DefaultSecurityHeadersConfig() SecurityHeadersConfig

DefaultSecurityHeadersConfig returns recommended security headers.

type TokenBucket

type TokenBucket struct {
	// contains filtered or unexported fields
}

TokenBucket implements a simple in-memory token bucket rate limiter.

func NewTokenBucket

func NewTokenBucket(rate int, window time.Duration) *TokenBucket

NewTokenBucket creates a new in-memory token bucket rate limiter. Call Stop() when the limiter is no longer needed to release the cleanup goroutine.

func (*TokenBucket) Allow

func (tb *TokenBucket) Allow(key string) bool

Allow checks if a request is allowed for the given key.

func (*TokenBucket) Stop

func (tb *TokenBucket) Stop()

Stop terminates the background cleanup goroutine. The TokenBucket should not be used after calling Stop.

Jump to

Keyboard shortcuts

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