TypeFunction
Middleware
Function signature for middleware that wraps handlers to provide cross-cutting functionality.
Type Definition
type Middleware func(HandlerFunc) HandlerFuncCreating Custom Middleware
Basic Middleware Pattern
The fundamental structure of middleware in Squirrel Framework.
// Basic middleware template
func myMiddleware(next HandlerFunc) HandlerFunc {
return func(req *Request, res *Response) {
// Code to run BEFORE the handler
fmt.Println("Before handler execution")
// Call the next handler in the chain
next(req, res)
// Code to run AFTER the handler
fmt.Println("After handler execution")
}
}
func main() {
server := SpawnServer()
// Apply middleware globally
server.Use(myMiddleware)
server.Get("/", func(req *Request, res *Response) {
res.Write("Hello, World!")
res.Send()
})
server.Listen(":8080")
}Logging Middleware
Middleware that logs request details and response times.
import (
"fmt"
"time"
)
func LoggingMiddleware(next HandlerFunc) HandlerFunc {
return func(req *Request, res *Response) {
start := time.Now()
// Log request start
fmt.Printf("[%s] %s %s - Started\n",
start.Format("2006-01-02 15:04:05"),
req.Method,
req.Path,
)
// Call next handler
next(req, res)
// Log request completion
duration := time.Since(start)
fmt.Printf("[%s] %s %s - Completed in %v\n",
time.Now().Format("2006-01-02 15:04:05"),
req.Method,
req.Path,
duration,
)
}
}
// Usage
server.Use(LoggingMiddleware)Authentication Middleware
Middleware that validates authentication tokens.
func AuthMiddleware(next HandlerFunc) HandlerFunc {
return func(req *Request, res *Response) {
// Check for Authorization header
authHeader := req.Headers["Authorization"]
if authHeader == "" {
res.SetStatus(401)
res.JSON(map[string]string{
"error": "Authorization header required",
})
res.Send()
return // Stop the chain here
}
// Validate token (simplified)
if !strings.HasPrefix(authHeader, "Bearer ") {
res.SetStatus(401)
res.JSON(map[string]string{
"error": "Invalid authorization format",
})
res.Send()
return
}
token := strings.TrimPrefix(authHeader, "Bearer ")
if token != "valid-token-123" {
res.SetStatus(401)
res.JSON(map[string]string{
"error": "Invalid token",
})
res.Send()
return
}
// Token is valid, continue to next handler
next(req, res)
}
}
// Apply to specific routes
server.Get("/protected", protectedHandler, AuthMiddleware)
// Or apply globally
server.Use(AuthMiddleware)CORS Middleware
Middleware that handles Cross-Origin Resource Sharing.
func CORSMiddleware(next HandlerFunc) HandlerFunc {
return func(req *Request, res *Response) {
// Set CORS headers
res.SetHeader("Access-Control-Allow-Origin", "*")
res.SetHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
res.SetHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With")
res.SetHeader("Access-Control-Max-Age", "86400") // 24 hours
// Handle preflight OPTIONS request
if req.Method == "OPTIONS" {
res.SetStatus(200)
res.Send()
return
}
// Continue to next handler
next(req, res)
}
}
// Usage
server.Use(CORSMiddleware)Rate Limiting Middleware
Middleware that implements basic rate limiting.
import (
"sync"
"time"
)
type RateLimiter struct {
requests map[string][]time.Time
mutex sync.RWMutex
limit int
window time.Duration
}
func NewRateLimiter(limit int, window time.Duration) *RateLimiter {
return &RateLimiter{
requests: make(map[string][]time.Time),
limit: limit,
window: window,
}
}
func (rl *RateLimiter) Middleware(next HandlerFunc) HandlerFunc {
return func(req *Request, res *Response) {
// Use IP address as identifier (simplified)
clientIP := req.Headers["X-Forwarded-For"]
if clientIP == "" {
clientIP = "unknown"
}
rl.mutex.Lock()
defer rl.mutex.Unlock()
now := time.Now()
// Clean old requests
if requests, exists := rl.requests[clientIP]; exists {
var validRequests []time.Time
for _, reqTime := range requests {
if now.Sub(reqTime) < rl.window {
validRequests = append(validRequests, reqTime)
}
}
rl.requests[clientIP] = validRequests
}
// Check rate limit
if len(rl.requests[clientIP]) >= rl.limit {
res.SetStatus(429) // Too Many Requests
res.SetHeader("Retry-After", "60")
res.JSON(map[string]string{
"error": "Rate limit exceeded",
})
res.Send()
return
}
// Add current request
rl.requests[clientIP] = append(rl.requests[clientIP], now)
// Continue to next handler
next(req, res)
}
}
// Usage
rateLimiter := NewRateLimiter(100, time.Minute) // 100 requests per minute
server.Use(rateLimiter.Middleware)Request Validation Middleware
Middleware that validates request content and format.
func ValidateJSONMiddleware(next HandlerFunc) HandlerFunc {
return func(req *Request, res *Response) {
// Only validate POST and PUT requests
if req.Method != "POST" && req.Method != "PUT" {
next(req, res)
return
}
// Check Content-Type
contentType := req.Headers["Content-Type"]
if contentType != "application/json" {
res.SetStatus(415) // Unsupported Media Type
res.JSON(map[string]string{
"error": "Content-Type must be application/json",
})
res.Send()
return
}
// Check Content-Length
if req.ContentLength == 0 {
res.SetStatus(400)
res.JSON(map[string]string{
"error": "Request body cannot be empty",
})
res.Send()
return
}
// Validate JSON format
body, err := req.ReadBodyAsString()
if err != nil {
res.SetStatus(400)
res.JSON(map[string]string{
"error": "Failed to read request body",
})
res.Send()
return
}
var jsonData interface{}
if err := json.Unmarshal([]byte(body), &jsonData); err != nil {
res.SetStatus(400)
res.JSON(map[string]string{
"error": "Invalid JSON format",
"details": err.Error(),
})
res.Send()
return
}
// JSON is valid, continue
next(req, res)
}
}
// Usage for specific routes
server.Post("/api/data", dataHandler, ValidateJSONMiddleware)Middleware Chaining
How to combine multiple middleware functions.
func main() {
server := SpawnServer()
// Global middleware (applied to all routes)
server.Use(LoggingMiddleware)
server.Use(CORSMiddleware)
// Public routes
server.Get("/", func(req *Request, res *Response) {
res.JSON(map[string]string{"message": "Public endpoint"})
res.Send()
})
// Protected routes with multiple middleware
server.Get("/api/protected",
protectedHandler,
AuthMiddleware, // Route-specific auth
rateLimiter.Middleware, // Route-specific rate limiting
)
// API routes with validation
server.Post("/api/users",
createUserHandler,
AuthMiddleware,
ValidateJSONMiddleware,
)
server.Listen(":8080")
}
// Middleware execution order:
// 1. LoggingMiddleware (global)
// 2. CORSMiddleware (global)
// 3. AuthMiddleware (route-specific)
// 4. ValidateJSONMiddleware (route-specific)
// 5. createUserHandler (actual handler)Middleware functions are executed in the order they are registered. Global middleware (added with
Use()) runs before route-specific middleware. Always call next(req, res) to continue the chain, or omit it to terminate early.