TypeFunction

Middleware

Function signature for middleware that wraps handlers to provide cross-cutting functionality.

Type Definition

type Middleware func(HandlerFunc) HandlerFunc

Creating 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)