Documentation
¶
Overview ¶
Package middleware provides a collection of HTTP middleware for Go web applications.
Middleware are functions that wrap HTTP handlers to add functionality such as request logging, error handling, timeout management, and CORS support. This package offers ready-to-use middleware for common tasks and utilities for middleware chaining and context management.
Key features:
- Request Context: Add request IDs and timing information to request contexts
- Logging: Log request details including method, path, status code, and duration
- Error Handling: Map errors to appropriate HTTP responses with status codes
- Panic Recovery: Catch and handle panics to prevent application crashes
- Timeout Management: Add request timeouts with proper cancellation handling
- CORS Support: Add Cross-Origin Resource Sharing headers to responses
- Context Cancellation: Detect and handle client disconnections
- Middleware Chaining: Apply multiple middleware in a specific order
- Thread Safety: Thread-safe response writing for concurrent operations
The package provides both individual middleware functions and utilities for combining them. The ApplyMiddleware function applies a standard set of middleware in the recommended order, while the Chain function allows for custom combinations.
Example usage:
// Create a logger logger, _ := zap.NewProduction() // Create a simple handler handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello, World!")) }) // Apply middleware wrappedHandler := middleware.ApplyMiddleware(handler, logger) // Start the server http.ListenAndServe(":8080", wrappedHandler)
For more advanced usage, middleware can be applied individually or chained in a custom order:
// Create a logger logger, _ := zap.NewProduction() contextLogger := logging.NewContextLogger(logger) // Apply middleware in a custom order handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello, World!")) }) // Chain middleware in a specific order wrappedHandler := middleware.Chain(handler, middleware.WithRequestID(context.Background()), middleware.Logging(contextLogger), middleware.Recovery(contextLogger), ) // Start the server http.ListenAndServe(":8080", wrappedHandler)
The order of middleware application is important, as it determines the order of execution. Middleware is executed in reverse order of application, so the first middleware applied is the outermost wrapper (first to process the request, last to process the response).
Index ¶
- func ApplyMiddleware(handler http.Handler, logger *zap.Logger) http.Handler
- func Chain(handler http.Handler, middlewares ...Middleware) http.Handler
- func RequestDuration(ctx context.Context) time.Duration
- func RequestID(ctx context.Context) string
- func StartTime(ctx context.Context) time.Time
- func WithCORS(next http.Handler) http.Handler
- func WithContextCancellation(logger *logging.ContextLogger) func(next http.Handler) http.Handler
- func WithErrorHandling(next http.Handler) http.Handler
- func WithLogging(logger *logging.ContextLogger, next http.Handler) http.Handler
- func WithRecovery(logger *logging.ContextLogger, next http.Handler) http.Handler
- func WithRequestContext(next http.Handler) http.Handler
- func WithTimeout(timeout time.Duration) func(http.Handler) http.Handler
- type ContextKey
- type Middleware
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ApplyMiddleware ¶
ApplyMiddleware applies all middleware to a handler in the recommended order. This function provides a consistent way to apply middleware across different applications. It applies the following middleware in order (outermost first):
- WithRequestContext - Adds request ID and timing information
- WithCORS - Adds CORS headers for cross-origin requests
- WithRecovery - Catches panics and converts them to 500 responses
- WithContextCancellation - Handles client disconnections
- WithLogging - Logs request details
- WithErrorHandling - Maps errors to appropriate HTTP responses
The order is important for proper middleware chaining. For example, the request context middleware is applied first so that all other middleware can access the request ID. The recovery middleware is applied early to catch panics in other middleware.
Parameters:
- handler: The HTTP handler to wrap with middleware.
- logger: Logger for recording middleware events.
Returns:
- A wrapped HTTP handler with all middleware applied in the recommended order.
func Chain ¶ added in v1.4.0
func Chain(handler http.Handler, middlewares ...Middleware) http.Handler
Chain applies multiple middleware to a http.Handler in the order they are provided. The first middleware in the list becomes the outermost wrapper, meaning it is the first to process the incoming request and the last to process the outgoing response.
The middleware are applied in reverse order (from last to first) to achieve this, because each middleware wraps the handler that comes after it in the chain.
Parameters:
- handler: The base HTTP handler to wrap with middleware.
- middlewares: A variadic list of middleware functions to apply.
Returns:
- An http.Handler with all the middleware applied in the specified order.
Example:
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello, World!")) }) // Apply middleware in order: logging, then recovery, then request ID wrappedHandler := middleware.Chain(handler, middleware.WithRequestID(context.Background()), middleware.Recovery(logger), middleware.Logging(logger), )
func RequestDuration ¶
RequestDuration returns the duration since the request started. This function calculates how long a request has been processing by comparing the start time from the context with the current time. If the start time is not found or is a zero time, a duration of 0 is returned.
Parameters:
- ctx: The context containing the request start time.
Returns:
- A time.Duration representing how long the request has been processing.
func RequestID ¶
RequestID returns the request ID from the context. This function safely extracts the request ID from the context, handling nil contexts and type assertions. If the context is nil or doesn't contain a request ID, an empty string is returned.
Parameters:
- ctx: The context from which to extract the request ID.
Returns:
- A string containing the request ID, or an empty string if not found.
func StartTime ¶
StartTime returns the request start time from the context. This function safely extracts the start time from the context, handling nil contexts and type assertions. If the context is nil or doesn't contain a start time, a zero time is returned.
Parameters:
- ctx: The context from which to extract the start time.
Returns:
- A time.Time representing when the request started, or a zero time if not found.
func WithContextCancellation ¶
WithContextCancellation is a middleware that checks for context cancellation It detects when a client disconnects and logs the event
func WithErrorHandling ¶
WithErrorHandling adds centralized error handling
func WithLogging ¶
WithLogging adds request logging. This middleware logs information about each request, including the HTTP method, path, status code, and duration. It uses a response writer wrapper to capture the status code of the response.
The logging occurs after the request has been processed, so it includes the final status code and the total time taken to process the request. This is useful for monitoring and debugging.
Parameters:
- logger: A context logger for logging request details.
- next: The next handler in the middleware chain.
Returns:
- An http.Handler that wraps the next handler with logging functionality.
func WithRecovery ¶
WithRecovery adds panic recovery to the request. This middleware catches any panics that occur during request processing and converts them into 500 Internal Server Error responses. It also logs the panic details, including the stack trace, to help with debugging.
Without this middleware, a panic in a handler would crash the entire server. With it, the panic is contained to just the current request, allowing the server to continue handling other requests.
Parameters:
- logger: A context logger for logging panic details.
- next: The next handler in the middleware chain.
Returns:
- An http.Handler that wraps the next handler with panic recovery functionality.
func WithRequestContext ¶
WithRequestContext adds request context information to the request. This middleware adds a unique request ID and start time to the request context. If the request already has an X-Request-ID header, that value is used as the request ID; otherwise, a new unique ID is generated. The request ID is also added to the response headers for correlation.
This middleware is typically one of the first in the chain, as it provides context information that other middleware and handlers can use.
Parameters:
- next: The next handler in the middleware chain.
Returns:
- An http.Handler that wraps the next handler with request context functionality.
func WithTimeout ¶
WithTimeout adds a timeout to the request context. This middleware sets a maximum duration for the request to complete. If the request takes longer than the specified timeout, it is canceled and a 504 Gateway Timeout response is returned to the client.
The middleware uses a goroutine to process the request and a select statement to wait for either the request to complete or the timeout to expire. It uses a synchronized response writer to avoid race conditions when writing the response.
Parameters:
- timeout: The maximum duration allowed for the request to complete.
Returns:
- A middleware function that adds timeout functionality to an HTTP handler.
Types ¶
type ContextKey ¶
type ContextKey string
ContextKey is a type for context keys to avoid collisions. Using a custom type for context keys helps prevent key collisions when multiple packages store values in the context.
const ( // RequestIDKey is the key for the request ID in the context. // This key is used to store and retrieve the unique identifier for each request. RequestIDKey ContextKey = "request_id" // StartTimeKey is the key for the request start time in the context. // This key is used to store and retrieve the time when the request started processing. StartTimeKey ContextKey = "start_time" // UserIDKey is the key for the user ID in the context (for future auth). // This key is used to store and retrieve the ID of the authenticated user. UserIDKey ContextKey = "user_id" )
type Middleware ¶ added in v1.4.0
Middleware represents a middleware function that wraps an http.Handler. A middleware takes an http.Handler and returns a new http.Handler that adds some functionality before and/or after calling the original handler.
This type allows middleware to be composed and chained together in a flexible way.
func Logging ¶ added in v1.4.0
func Logging(logger *logging.ContextLogger) Middleware
Logging is a middleware that logs request information. This is a convenience wrapper around WithLogging that returns a Middleware function, making it easier to use with the Chain function.
Parameters:
- logger: A context logger for logging request details.
Returns:
- A Middleware function that adds logging functionality.
func Recovery ¶ added in v1.4.0
func Recovery(logger *logging.ContextLogger) Middleware
Recovery is a middleware that recovers from panics. This is a convenience wrapper around WithRecovery that returns a Middleware function, making it easier to use with the Chain function.
Parameters:
- logger: A context logger for logging panic details.
Returns:
- A Middleware function that adds panic recovery functionality.
func WithRequestID ¶ added in v1.4.0
func WithRequestID(ctx context.Context) Middleware
WithRequestID is a middleware that adds a request ID to the context. This is a convenience wrapper around WithRequestContext that returns a Middleware function, making it easier to use with the Chain function.
Parameters:
- ctx: The parent context to use (typically context.Background()).
Returns:
- A Middleware function that adds request ID functionality.