Middleware

Middleware in Rue allows you to execute code before and after request handlers. Rue comes with several built-in middleware and makes it easy to create custom ones.

Using Middleware

Apply middleware globally or to specific route groups:

go
r := rue.New()

// Global middleware
r.Use(rue.Logger())
r.Use(rue.Recovery())

// Group-specific middleware
api := r.Group("/api")
api.Use(rue.CORS())
{
    api.GET("/users", listUsers)
}

// Route-specific middleware
r.GET("/admin", adminOnly(), adminHandler)

Logger

Logs HTTP requests with timing information:

go
// Default logger
r.Use(rue.Logger())

// With configuration
r.Use(rue.LoggerWithConfig(rue.LoggerConfig{
    SkipPaths: []string{"/health", "/metrics"},
}))

Output example:

[RUE] 2024/01/15 - 10:30:45 | 200 |     1.234ms | 192.168.1.1 | GET /api/users

Recovery

Recovers from panics and returns a 500 error:

go
r.Use(rue.Recovery())

CORS

Handle Cross-Origin Resource Sharing:

go
// Default CORS (allows all origins)
r.Use(rue.CORS())

// Custom configuration
r.Use(rue.CORSWithConfig(rue.CORSConfig{
    AllowOrigins:     []string{"https://example.com", "https://app.example.com"},
    AllowMethods:     []string{"GET", "POST", "PUT", "DELETE"},
    AllowHeaders:     []string{"Origin", "Content-Type", "Authorization"},
    ExposeHeaders:    []string{"Content-Length"},
    AllowCredentials: true,
    MaxAge:           86400,
}))

Rate Limiter

Limit request rates per client:

go
// Simple rate limiter: 10 requests/second, burst of 20
r.Use(rue.RateLimiter(10, 20))

// Custom configuration
r.Use(rue.RateLimiterWithConfig(rue.RateLimiterConfig{
    Rate:  100,   // 100 requests per second
    Burst: 200,   // Allow burst of 200
    KeyFunc: func(c *rue.Context) string {
        // Rate limit by API key instead of IP
        return c.GetHeader("X-API-Key")
    },
}))

JWT Authentication

Validate JSON Web Tokens:

go
secret := []byte("your-secret-key")

// Generate a token
claims := &rue.JWTClaims{
    Subject:   "user123",
    ExpiresAt: time.Now().Add(24 * time.Hour).Unix(),
    Custom: map[string]any{
        "role": "admin",
        "permissions": []string{"read", "write"},
    },
}
token, err := rue.GenerateToken(claims, secret)

// Protect routes with JWT middleware
api := r.Group("/api")
api.Use(rue.JWT(secret))
{
    api.GET("/profile", func(c *rue.Context) {
        // Access claims from context
        claims, _ := c.Get("jwt_claims")
        jwtClaims := claims.(*rue.JWTClaims)
        
        c.JSON(http.StatusOK, rue.H{
            "user_id": jwtClaims.Subject,
            "role":    jwtClaims.Custom["role"],
        })
    })
}

API Key Authentication

Validate API keys from headers or query parameters:

go
// Simple API key validation
r.Use(rue.APIKey(func(key string) bool {
    validKeys := map[string]bool{
        "key1": true,
        "key2": true,
    }
    return validKeys[key]
}))

// Custom configuration
r.Use(rue.APIKeyWithConfig(rue.APIKeyConfig{
    KeyLookup: "header:X-API-Key",  // or "query:api_key"
    Validator: func(key string) bool {
        // Validate against database
        return db.ValidateAPIKey(key)
    },
}))

Compression

Compress responses with Gzip or Brotli:

go
// Auto-select best compression (prefers Brotli)
r.Use(rue.Compress())

// Gzip only
r.Use(rue.Gzip())

// Brotli only
r.Use(rue.Brotli())

Custom Middleware

Create your own middleware:

go
func RequestID() rue.HandlerFunc {
    return func(c *rue.Context) {
        // Before request
        requestID := uuid.New().String()
        c.Set("request_id", requestID)
        c.SetHeader("X-Request-ID", requestID)
        
        c.Next()  // Process request
        
        // After request
        // Access response status, timing, etc.
    }
}

func Timing() rue.HandlerFunc {
    return func(c *rue.Context) {
        start := time.Now()
        
        c.Next()
        
        duration := time.Since(start)
        c.SetHeader("X-Response-Time", duration.String())
        log.Printf("Request took %v", duration)
    }
}

// Use custom middleware
r.Use(RequestID())
r.Use(Timing())

Middleware Order

Middleware executes in the order they are added:

go
r.Use(A())  // Executes first (before)
r.Use(B())  // Executes second (before)
r.Use(C())  // Executes third (before)

// Request flow:
// A (before) -> B (before) -> C (before) -> Handler -> C (after) -> B (after) -> A (after)
💡 Best Practice

Place error handling middleware (Recovery) first, then logging, then authentication, then business logic middleware.

Aborting Requests

Stop request processing in middleware:

go
func AuthRequired() rue.HandlerFunc {
    return func(c *rue.Context) {
        token := c.GetHeader("Authorization")
        if token == "" {
            c.AbortWithStatus(http.StatusUnauthorized)
            return  // Important: return after abort
        }
        
        user, err := validateToken(token)
        if err != nil {
            c.AbortWithError(http.StatusUnauthorized, err)
            return
        }
        
        c.Set("user", user)
        c.Next()
    }
}