middleware.go
Overview
The [middleware.go](/projects/291/69274) file provides HTTP middleware components for the API server built using the Gorilla Mux router. Middleware functions are wrappers around HTTP handlers that execute code before and/or after the main handler logic. This file primarily implements:
Logging middleware: Tracks HTTP request details, response status, timing, and emits metrics using Prometheus.
Scheme middleware: Determines and sets the URL scheme (
http,https,ws,wss) for incoming requests based on headers and TLS state.
These middleware layers enhance observability, metrics collection, and correct request context handling needed throughout the API service.
Detailed Explanation of Components
Struct: statusWriter
type statusWriter struct {
http.ResponseWriter
status int
}
Purpose: Wraps an
http.ResponseWriterto capture the HTTP response status code for logging and metrics.Fields:
ResponseWriter: Embedded original response writer.status: HTTP status code written to the client (default is 200 OK).
Functions related to statusWriter
newStatusWriter(w http.ResponseWriter) *statusWriterCreates a new
statusWriterwrapping the providedResponseWriter. Initializes status to HTTP 200 OK.Parameters:
w: Originalhttp.ResponseWriterfrom the request.
**Returns**:
Pointer to a new
statusWriter.
(w *statusWriter) WriteHeader(status int)Overrides
WriteHeaderto record the status code before forwarding the call to the originalResponseWriter.Parameters:
status: HTTP status code to write.
**Usage**: Used internally by Gorilla Mux handlers or middleware to capture status for logging.
Middleware Function: Logger
func Logger(prometheus *metrics.Prometheus) mux.MiddlewareFunc
Purpose: Provides request logging and Prometheus metrics instrumentation as middleware.
Parameters:
prometheus: Pointer to a Prometheus metrics collector instance which exposes counters and histograms.
Returns:
mux.MiddlewareFunc: Middleware compatible with Gorilla Mux.
Behavior:
Wraps the
ResponseWriterwithstatusWriterto capture response status.Handles WebSocket upgrade requests specially (does not write status header to avoid conflict).
Measures the duration of the HTTP request.
Logs request method, URI, remote address, response status, and duration.
For API requests under
/api/v1/(excluding 404 responses), increments Prometheus metrics:HTTP request count (
HTTPRequestCounter) labeled by method, route, and status code.HTTP request duration (
HTTPRequestDurationSeconds).
Logs errors for HTTP status codes indicating client or server errors (status < 200 or >= 400).
Logs info messages for successful requests.
Usage Example
router := mux.NewRouter()
prometheus := metrics.NewPrometheus()
router.Use(api.Logger(prometheus))
Middleware Function: Scheme
func Scheme(next http.Handler) http.Handler
Purpose: Sets the
Schemefield of the incoming HTTP request URL based on request headers and TLS state. This helps downstream handlers correctly construct absolute URLs and understand the protocol used.Parameters:
next: The next HTTP handler to execute.
Returns:
An
http.Handlerwrappingnextwith scheme-detection logic.
Behavior:
Checks for the presence of common headers indicating the original request scheme (e.g., behind reverse proxies):
X-Forwarded-ProtoX-Forwarded-SchemeForwarded(RFC7239 header, parsesprototoken using regex)Upgradeheader (specifically for WebSocket requests)
Uses
r.TLSpresence to infer HTTPS if no headers are present.Sets
r.URL.Schemeaccordingly:httporhttpsfor normal HTTP/HTTPS requests.wsorwssfor WebSocket connections.
Calls the next handler in the chain with the updated request.
Example Usage
router := mux.NewRouter()
router.Use(api.Scheme)
Important Implementation Details
statusWriterWrapper: Captures HTTP status code becausehttp.ResponseWriterdoes not expose a method to query the status after writing headers. This technique is a common pattern for logging middleware.WebSocket Handling in Logger: The logger skips writing status headers on WebSocket upgrade requests because the WebSocket upgrader itself controls header writing, and writing twice causes errors.
Scheme Detection: The
Schememiddleware follows common proxy header conventions and RFC7239 for detecting the original request scheme, which is crucial when the API server is behind reverse proxies or load balancers that terminate TLS.Metrics Labels: Uses the exact request URI as the route label, which may cause high cardinality in Prometheus if dynamic segments are not normalized elsewhere.
Interaction with Other System Components
Uses the Gorilla Mux router for HTTP routing.
Integrates with a Prometheus metrics system via the
metrics.Prometheusstruct to expose counters and histograms.Relies on a custom logging package (
log) to output structured logs with fields.Middleware functions are intended to be composed in the API server's routing setup, wrapping API handlers to provide consistent telemetry and request context.
Visual Diagram
flowchart TD
subgraph MiddlewareChain
direction TB
Request --> SchemeMiddleware[Scheme Middleware]
SchemeMiddleware --> LoggerMiddleware[Logger Middleware]
LoggerMiddleware --> Handler[Final HTTP Handler]
end
subgraph LoggerMiddlewareDetails
LoggerMiddleware --> WrapResponseWriter[Wrap with statusWriter]
WrapResponseWriter --> CallNextHandler
CallNextHandler --> MeasureDuration
MeasureDuration --> LogRequestAndMetrics
end
subgraph SchemeMiddlewareDetails
SchemeMiddleware --> ExtractHeaders[Extract Scheme Headers]
ExtractHeaders --> DetermineScheme[Determine URL Scheme]
DetermineScheme --> SetRequestScheme[Set r.URL.Scheme]
end
style MiddlewareChain fill:#f9f,stroke:#333,stroke-width:1px
style LoggerMiddlewareDetails fill:#bbf,stroke:#333,stroke-width:1px
style SchemeMiddlewareDetails fill:#bbf,stroke:#333,stroke-width:1px
Summary
The [middleware.go](/projects/291/69274) file offers essential HTTP middleware for the API server to:
Log incoming requests with status codes and response times.
Collect detailed Prometheus metrics for observability.
Correctly identify the scheme used for requests to support URL generation and protocol awareness, especially behind proxies and with WebSocket support.
By integrating these middleware functions into the HTTP router, the application enhances reliability, debugging, and monitoring capabilities critical for production-grade APIs.