Middleware and Patterns
Understanding Middleware
Middleware provides a powerful way to intercept and process HTTP requests before they reach the final handler.
Basic Middleware Structure
func middlewareFunc(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Pre-processing logic
next.ServeHTTP(w, r)
// Post-processing logic
}
}
Middleware Types
graph TD
A[Middleware Types] --> B[Authentication]
A --> C[Logging]
A --> D[Rate Limiting]
A --> E[Compression]
A --> F[CORS Handling]
Common Middleware Patterns
1. Logging Middleware
func loggingMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
log.Printf("%s %s %v", r.Method, r.URL.Path, time.Since(start))
}
}
2. Authentication Middleware
func authMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
if !validateToken(token) {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
next.ServeHTTP(w, r)
}
}
Middleware Composition
func chainMiddleware(handlers ...func(http.HandlerFunc) http.HandlerFunc) func(http.HandlerFunc) http.HandlerFunc {
return func(next http.HandlerFunc) http.HandlerFunc {
for i := len(handlers) - 1; i >= 0; i-- {
next = handlers[i](next)
}
return next
}
}
Middleware Application Patterns
Pattern |
Description |
Use Case |
Chained Middleware |
Multiple middlewares applied sequentially |
Complex request processing |
Conditional Middleware |
Middleware applied based on conditions |
Selective request handling |
Global Middleware |
Applied to all routes |
Logging, security |
Advanced Middleware Example
func main() {
finalHandler := http.HandlerFunc(homeHandler)
enhancedHandler := chainMiddleware(
loggingMiddleware,
authMiddleware,
rateLimitMiddleware,
)(finalHandler)
http.Handle("/", enhancedHandler)
http.ListenAndServe(":8080", nil)
}
graph LR
A[Request] --> B{Middleware 1}
B --> |Process| C{Middleware 2}
C --> |Process| D{Middleware 3}
D --> E[Final Handler]
Best Practices
- Keep middleware lightweight
- Minimize performance overhead
- Handle errors gracefully
- Use middleware selectively
LabEx Recommended Middleware Libraries
gorilla/handlers
rs/cors
justinas/alice
Error Handling in Middleware
func recoveryMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err != nil {
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
log.Printf("Panic: %v", err)
}
}()
next.ServeHTTP(w, r)
}
}
Conclusion
Middleware provides a flexible and powerful mechanism for processing HTTP requests, enabling developers to add cross-cutting concerns efficiently and maintain clean, modular code.