Middleware Interface
Fromhttpserver/middleware.go:9, middleware implements a simple interface:
Wrap method can be used as middleware.
MiddlewareFunc
For simple middleware, use theMiddlewareFunc convenience type from httpserver/middleware.go:15:
Creating Middleware
Basic Pattern
Middleware follows this structure:Example: Request Logging
Fromdemo-app/cmd/api/main.go:45, inline middleware for logging:
Example: TraceID Middleware
Real implementation fromlog/traceid.go:11:
demo-app/cmd/api/main.go:34:
This middleware generates a unique trace ID for each request, adds it to the response headers, and makes it available in the request context for logging.
Applying Middleware
Use() - Apply Middleware
Fromhttpserver/handlergroup.go:19, apply middleware to a server or group:
UseFunc() - Apply Function Middleware
Fromhttpserver/handlergroup.go:24, for inline middleware:
Wrap() - Apply to Single Handler
Fromauth/domain.go:27, wrap individual handlers:
Middleware Execution Order
Middleware is applied in reverse order fromhttpserver/middleware.go:26:
- Request enters
traceIDMiddleware - Passes to
loggingMiddleware - Passes to
authMiddleware - Reaches
handler - Response flows back through auth → logging → traceID
Common Middleware Patterns
Authentication
Check for valid credentials and inject user into context:Request Timing
Measure request duration:Error Recovery
Recover from panics:CORS Headers
Add cross-origin resource sharing headers:Request ID Injection
Similar to TraceID, but from header if present:Middleware with Configuration
Create configurable middleware using constructors:Context-Based Middleware
Pass values through request context:Conditional Middleware
Apply middleware based on conditions:Combining Middleware
Chain multiple middleware together:Testing Middleware
Test middleware in isolation:Best Practices
Order Matters
Order Matters
Place middleware that sets context values (like trace ID, user) before middleware that uses those values (like logging).
Always Call Next
Always Call Next
Unless you’re intentionally short-circuiting the request (auth failure, rate limit), always call
h.ServeHTTP(w, r).Don't Modify Request Body
Don't Modify Request Body
Reading
r.Body consumes it. If you need to inspect the body, create a copy first using io.TeeReader.Keep Middleware Focused
Keep Middleware Focused
Each middleware should do one thing well. Compose multiple middleware instead of creating monolithic ones.
Use Types for Configuration
Use Types for Configuration
Create a struct type for middleware with configuration rather than passing many parameters.
Next Steps
HTTP Routing
Learn how to apply middleware to routes and groups
Domains
See how middleware fits into domain architecture
Logging
Use context-aware logging in middleware