README
¶
Middleware Basics Example
This interactive example demonstrates HyperServe's middleware system by building up a middleware stack step by step. You'll see how each middleware affects the server's behavior and performance.
What This Example Shows
- How middleware wraps HTTP handlers
- The order of middleware execution
- Global vs route-specific middleware
- Common middleware patterns
- Performance impact of different middleware
Running the Example
go run main.go
The example runs interactively, guiding you through 5 steps:
- No Middleware - Baseline server
- Request Logging - Add logging
- Request Metrics - Add metrics collection
- Rate Limiting - Add rate limiting
- Full Stack - Complete middleware setup with route-specific rules
Interactive Demo
When you run the example, it will:
- Explain what each step demonstrates
- Wait for you to press Enter to start
- Run the server with that configuration
- Let you test it with curl
- Wait for Enter to continue to the next step
Testing Each Step
Step 1: No Middleware
curl http://localhost:8080/api/data
# Fast response, no logging
Step 2: With Logging
curl http://localhost:8080/api/data
# See request details in console
Step 3: With Metrics
curl http://localhost:8080/api/data
curl http://localhost:8080/metrics
# See request count and timing
Step 4: With Rate Limiting
# Make rapid requests
for i in {1..20}; do curl http://localhost:8080/api/data; done
# See 429 errors after limit exceeded
Step 5: Full Stack
# Public route (no rate limit)
curl http://localhost:8080/
# API route (rate limited)
curl http://localhost:8080/api/data
# Crash test (recovery middleware)
curl http://localhost:8080/api/crash
# Metrics
curl http://localhost:8080/metrics
Key Concepts
1. Middleware Order Matters
server.AddMiddleware("*", logging) // Runs first
server.AddMiddleware("*", metrics) // Runs second
server.AddMiddleware("*", rateLimit) // Runs third
Middleware executes in the order it's added. The first middleware sees the request first and the response last.
2. Global vs Route-Specific
// Global - applies to all routes
server.AddMiddleware("*", middleware)
// Route-specific - only for paths starting with /api
server.AddMiddleware("/api", middleware)
3. Middleware Signature
HyperServe uses this middleware function type:
type MiddlewareFunc func(http.Handler) http.HandlerFunc
Standard middleware pattern:
func MyMiddleware(next http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Before handler
next.ServeHTTP(w, r)
// After handler
}
}
4. Performance Impact
Each middleware adds overhead:
- Logging: ~250% overhead (I/O bound)
- Metrics: ~50% overhead (memory/CPU)
- Rate Limiting: ~50% overhead (map lookups)
- Recovery: ~-9% (actually improves performance!)
Common Middleware Patterns
Timing Requests
start := time.Now()
next.ServeHTTP(w, r)
duration := time.Since(start)
Modifying Requests
// Add header before processing
r.Header.Set("X-Request-ID", generateID())
next.ServeHTTP(w, r)
Short-Circuit Responses
if !authorized {
http.Error(w, "Unauthorized", 401)
return // Don't call next
}
next.ServeHTTP(w, r)
Wrapping Response Writer
wrapped := &responseWriter{ResponseWriter: w}
next.ServeHTTP(wrapped, r)
log.Printf("Status: %d", wrapped.statusCode)
Try These Modifications
- Add Custom Middleware: Create a middleware that adds a custom header
- Conditional Middleware: Only apply middleware based on request headers
- Chain Middleware: Create a middleware that combines multiple middlewares
- Error Handling: Add middleware that catches and formats errors
Writing Your Own Middleware
Here's a template for custom middleware compatible with HyperServe:
func MyMiddleware(srv *server.Server) server.MiddlewareFunc {
return func(next http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Pre-processing
log.Println("Before request")
// Call the next handler
next.ServeHTTP(w, r)
// Post-processing
log.Println("After request")
}
}
}
Best Practices
- Order Carefully: Place authentication before rate limiting
- Minimize Overhead: Avoid expensive operations in middleware
- Use Context: Pass data between middleware using
r.Context() - Handle Errors: Don't let middleware panic
- Document Effects: Clearly state what your middleware does
What's Next?
Now that you understand middleware, move on to configuration to learn about HyperServe's configuration system.
Documentation
¶
There is no documentation for this package.
Click to show internal directories.
Click to hide internal directories.