Router

Middleware

Process requests and responses with powerful middleware system

Middleware in Forge allows you to process HTTP requests and responses in a pipeline, enabling cross-cutting concerns like authentication, logging, CORS, error handling, and more. Forge provides a powerful middleware system that works seamlessly with its handler pattern.

Middleware Pattern

Forge middleware uses a functional pattern with forge.Handler and forge.Context:

type Middleware func(next forge.Handler) forge.Handler
type Handler func(ctx forge.Context) error

This pattern provides type-safe, composable middleware with proper error handling.

Basic Middleware

Create custom middleware by wrapping handlers:

package main

import (
    "time"
    
    "github.com/xraph/forge"
    "github.com/xraph/forge/middleware"
)

func main() {
    app := forge.New()
    
    // Apply middleware globally
    app.Router().Use(
        middleware.RequestID(),
        middleware.Logging(app.Logger()),
        middleware.Recovery(app.Logger()),
        middleware.CORS(middleware.DefaultCORSConfig()),
    )
    
    app.Router().GET("/users", getUsersHandler)
    
    if err := app.Run(); err != nil {
        panic(err)
    }
}

// Custom logging middleware
func customLoggingMiddleware(logger forge.Logger) forge.Middleware {
    return func(next forge.Handler) forge.Handler {
        return func(ctx forge.Context) error {
        start := time.Now()
        
            logger.Info("request started",
                "method", ctx.Request().Method,
                "path", ctx.Request().URL.Path,
            )
            
            // Call next handler
            err := next(ctx)
            
            duration := time.Since(start)
            logger.Info("request completed",
                "method", ctx.Request().Method,
                "path", ctx.Request().URL.Path,
                "duration", duration,
            )
            
            return err
        }
    }
}

Built-In Middleware

Forge provides production-ready middleware out of the box:

CORS Middleware

Handle Cross-Origin Resource Sharing (CORS) with full configuration support:

import "github.com/xraph/forge/middleware"

// Default CORS configuration (permissive for development)
app.Router().Use(middleware.CORS(middleware.DefaultCORSConfig()))

// Custom CORS configuration
app.Router().Use(middleware.CORS(middleware.CORSConfig{
    AllowOrigins:     []string{"https://example.com", "https://app.example.com"},
    AllowMethods:     []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
    AllowHeaders:     []string{"Content-Type", "Authorization", "X-API-Key"},
    ExposeHeaders:    []string{"X-Request-ID"},
    AllowCredentials: true,
    MaxAge:           3600, // Cache preflight for 1 hour
}))

// Wildcard subdomain support
app.Router().Use(middleware.CORS(middleware.CORSConfig{
    AllowOrigins: []string{"*.example.com"}, // Matches any subdomain
    AllowMethods: []string{"GET", "POST"},
}))

Features:

  • Automatic OPTIONS preflight handling
  • Wildcard origin support (*)
  • Subdomain wildcard support (*.example.com)
  • Credentials handling with security validation
  • Proper Vary header management
  • Method and header validation

Security Note: AllowOrigins: ["*"] and AllowCredentials: true cannot be used together. The middleware will panic if misconfigured.

Logging Middleware

Structured logging with request/response tracking:

import "github.com/xraph/forge/middleware"

// Basic logging with default configuration
app.Router().Use(middleware.Logging(app.Logger()))

// Custom logging configuration
app.Router().Use(middleware.LoggingWithConfig(
    app.Logger(),
    middleware.LoggingConfig{
        IncludeHeaders:   true,
        ExcludePaths:     []string{"/health", "/metrics"},
        SensitiveHeaders: []string{"Authorization", "Cookie"},
    },
))

Features:

  • Request start/completion logging
  • Duration tracking
  • Path exclusion for health checks
  • Sensitive header redaction
  • Structured logging support

Default Excluded Paths:

  • /health
  • /metrics

Default Sensitive Headers:

  • Authorization
  • Cookie
  • Set-Cookie

Recovery Middleware

Recover from panics gracefully:

import "github.com/xraph/forge/middleware"

app.Router().Use(middleware.Recovery(app.Logger()))

Features:

  • Catches panics in handlers
  • Logs panic details with stack trace
  • Returns 500 Internal Server Error
  • Prevents server crashes
  • Production-ready error handling
// Example handler that panics
app.Router().GET("/panic", func(ctx forge.Context) error {
    panic("something went wrong!")
    // Recovery middleware catches this and returns 500
})

Rate Limiting Middleware

Token bucket algorithm for precise rate limiting:

import "github.com/xraph/forge/middleware"

// Create rate limiter: 100 requests per second, burst of 200
limiter := middleware.NewRateLimiter(100, 200)

// Apply to all routes
app.Router().Use(middleware.RateLimit(limiter, app.Logger()))

// Per-route rate limiting
app.Router().GET("/expensive", handler,
    forge.WithMiddleware(middleware.RateLimit(
        middleware.NewRateLimiter(10, 20), // Stricter limits
        app.Logger(),
    )),
)

Features:

  • Token bucket algorithm (industry standard)
  • Per-client rate limiting (by remote address)
  • Automatic token refill over time
  • Configurable burst capacity
  • Background cleanup of old buckets
  • Thread-safe implementation

Parameters:

  • rate: Maximum requests per second
  • burst: Maximum burst size (bucket capacity)

Response:

  • Returns 429 Too Many Requests when limit exceeded
  • Sets X-Ratelimit-Limit: exceeded header

Request ID Middleware

Track requests with unique identifiers:

import "github.com/xraph/forge/middleware"

app.Router().Use(middleware.RequestID())

// Access request ID in handlers
app.Router().GET("/users", func(ctx forge.Context) error {
    requestID := middleware.GetRequestIDFromForgeContext(ctx)
    
    ctx.Logger().Info("processing request", "request_id", requestID)
    
    return ctx.JSON(200, map[string]string{
        "request_id": requestID,
    })
})

Features:

  • Generates UUID for each request
  • Reuses X-Request-ID header if present
  • Sets response header automatically
  • Stores in context for easy access
  • Perfect for distributed tracing

Compression Middleware

Gzip compression for responses:

import "github.com/xraph/forge/middleware"

// Default compression level
app.Router().Use(middleware.CompressDefault())

// Custom compression level (1-9)
app.Router().Use(middleware.Compress(6))

Features:

  • Automatic gzip compression
  • Client capability detection
  • Configurable compression level
  • Response writer wrapping
  • Proper header management

Compression Levels:

  • 1: Best speed, least compression
  • 6: Default balanced
  • 9: Best compression, slower

Timeout Middleware

Enforce request timeouts:

import (
    "net/http"
    "time"
    "github.com/xraph/forge/middleware"
)

// Note: Timeout uses http.Handler pattern
timeoutMiddleware := middleware.Timeout(30*time.Second, app.Logger())

// Apply using PureMiddleware conversion
app.Router().Use(func(next forge.Handler) forge.Handler {
    return func(ctx forge.Context) error {
        // Create a wrapper that calls the timeout middleware
        handler := timeoutMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            _ = next(ctx)
        }))
        
        handler.ServeHTTP(ctx.Response(), ctx.Request())
        return nil
    }
})

Features:

  • Context-based timeout enforcement
  • Safe response buffering
  • Race condition prevention
  • Returns 504 Gateway Timeout
  • Goroutine-safe implementation

The Timeout middleware uses http.Handler pattern due to goroutine requirements for proper timeout handling.

Custom Middleware

Authentication Example

Create custom middleware for your application needs:

// JWT Authentication middleware
func jwtAuthMiddleware(secretKey string) forge.Middleware {
    return func(next forge.Handler) forge.Handler {
        return func(ctx forge.Context) error {
            authHeader := ctx.Request().Header.Get("Authorization")
            if authHeader == "" {
                return forge.Unauthorized("authorization header required")
            }
            
            tokenString := strings.TrimPrefix(authHeader, "Bearer ")
            if tokenString == authHeader {
                return forge.Unauthorized("bearer token required")
            }
            
            // Validate JWT token (pseudo-code)
            claims, err := validateJWT(tokenString, secretKey)
            if err != nil {
                return forge.Unauthorized("invalid token")
            }
            
            // Store claims in context
            ctx.Set("user_id", claims.UserID)
            ctx.Set("username", claims.Username)
            
            return next(ctx)
        }
    }
}

// API Key middleware
func apiKeyMiddleware(validKeys map[string]bool) forge.Middleware {
    return func(next forge.Handler) forge.Handler {
        return func(ctx forge.Context) error {
            apiKey := ctx.Request().Header.Get("X-API-Key")
            if apiKey == "" {
                return forge.Unauthorized("API key required")
            }
            
            if !validKeys[apiKey] {
                return forge.Unauthorized("invalid API key")
            }
            
            return next(ctx)
        }
    }
}

Validation Example

import "github.com/go-playground/validator/v10"

// Request validation middleware
func validationMiddleware() forge.Middleware {
    validate := validator.New()
    
    return func(next forge.Handler) forge.Handler {
        return func(ctx forge.Context) error {
            // Content-Type validation for POST/PUT
            if ctx.Request().Method == "POST" || ctx.Request().Method == "PUT" {
                contentType := ctx.Request().Header.Get("Content-Type")
            if !strings.Contains(contentType, "application/json") {
                    return forge.BadRequest("content-Type must be application/json")
            }
        }
        
        // Request size validation
            if ctx.Request().ContentLength > 10*1024*1024 { // 10MB
                return forge.NewHTTPError(413, "request body too large")
            }
            
            return next(ctx)
        }
    }
}

// Struct validation middleware
func structValidationMiddleware() forge.Middleware {
    validate := validator.New()
    
    return func(next forge.Handler) forge.Handler {
        return func(ctx forge.Context) error {
            // This would be applied after BindJSON
            // Handler should validate the struct manually
            return next(ctx)
        }
    }
}

Middleware Chaining

Chain multiple middleware in a specific order:

import "github.com/xraph/forge/middleware"

func setupMiddlewareChain(app *forge.App) {
    // Global middleware (applied to all routes)
    // Order matters: request ID → recovery → logging → CORS
    app.Router().Use(
        middleware.RequestID(),
        middleware.Recovery(app.Logger()),
        middleware.Logging(app.Logger()),
        middleware.CORS(middleware.DefaultCORSConfig()),
    )
    
    // API routes with rate limiting and auth
    limiter := middleware.NewRateLimiter(100, 200)
    api := app.Router().Group("/api",
        forge.WithGroupMiddleware(middleware.RateLimit(limiter, app.Logger())),
        forge.WithGroupMiddleware(jwtAuthMiddleware("secret")),
    )
    
    // Admin routes with stricter limits
    adminLimiter := middleware.NewRateLimiter(10, 20)
    admin := api.Group("/admin",
        forge.WithGroupMiddleware(middleware.RateLimit(adminLimiter, app.Logger())),
        forge.WithGroupMiddleware(requireAdminRole()),
        forge.WithGroupMiddleware(auditLogMiddleware()),
    )
    
    admin.GET("/users", adminGetUsersHandler)
}

// Admin role validation
func requireAdminRole() forge.Middleware {
    return func(next forge.Handler) forge.Handler {
        return func(ctx forge.Context) error {
            userRole := ctx.Get("user_role")
            if userRole != "admin" {
                return forge.Forbidden("admin access required")
            }
            return next(ctx)
        }
    }
}

// Audit logging middleware
func auditLogMiddleware() forge.Middleware {
    return func(next forge.Handler) forge.Handler {
        return func(ctx forge.Context) error {
            userID := ctx.Get("user_id")
            ctx.Logger().Info("admin action",
                "user_id", userID,
                "path", ctx.Request().URL.Path,
                "method", ctx.Request().Method,
            )
            return next(ctx)
        }
    }
}

Middleware Order Matters

The order of middleware execution is important:

  1. Request ID - Generate tracking ID first
  2. Recovery - Catch panics early
  3. Logging - Log with request ID
  4. CORS - Handle CORS before auth
  5. Authentication - Verify identity
  6. Authorization - Check permissions
  7. Rate Limiting - After auth for accurate limiting

Route-Specific Middleware

Apply middleware to individual routes:

import "github.com/xraph/forge/middleware"

func setupRouteMiddleware(app *forge.App) {
    // Public route (no middleware)
    app.Router().GET("/public/data", getPublicDataHandler)
    
    // Route with authentication
    app.Router().GET("/private/data", getPrivateDataHandler,
        forge.WithMiddleware(jwtAuthMiddleware("secret")),
    )
    
    // Route with multiple middleware
    app.Router().POST("/upload", uploadHandler,
        forge.WithMiddleware(jwtAuthMiddleware("secret")),
        forge.WithMiddleware(fileSizeValidation(50*1024*1024)), // 50MB
        forge.WithMiddleware(fileTypeValidation([]string{".jpg", ".png"})),
    )
    
    // Admin route with strict rate limit
    adminLimiter := middleware.NewRateLimiter(10, 20)
    app.Router().GET("/admin/stats", getStatsHandler,
        forge.WithMiddleware(jwtAuthMiddleware("secret")),
        forge.WithMiddleware(requireAdminRole()),
        forge.WithMiddleware(middleware.RateLimit(adminLimiter, app.Logger())),
    )
}

// File size validation middleware
func fileSizeValidation(maxSize int64) forge.Middleware {
    return func(next forge.Handler) forge.Handler {
        return func(ctx forge.Context) error {
            if ctx.Request().ContentLength > maxSize {
                return forge.NewHTTPError(413, "file too large")
            }
            return next(ctx)
        }
    }
}

// File type validation middleware
func fileTypeValidation(allowedTypes []string) forge.Middleware {
    return func(next forge.Handler) forge.Handler {
        return func(ctx forge.Context) error {
            contentType := ctx.Request().Header.Get("Content-Type")
            
            allowed := false
            for _, t := range allowedTypes {
                if strings.Contains(contentType, t) {
                    allowed = true
                    break
                }
            }
            
            if !allowed {
                return forge.BadRequest("invalid file type")
            }
            
            return next(ctx)
        }
    }
}

Advanced Middleware Patterns

Conditional Middleware

Execute middleware based on conditions:

// Conditional middleware factory
func conditionalMiddleware(condition bool, middleware forge.Middleware) forge.Middleware {
    if condition {
        return middleware
    }
    // No-op middleware
    return func(next forge.Handler) forge.Handler {
        return next
    }
}

func setupConditionalMiddleware(app *forge.App, config *AppConfig) {
    app.Router().Use(
        conditionalMiddleware(config.Debug, debugMiddleware()),
        conditionalMiddleware(config.EnableMetrics, metricsMiddleware()),
        conditionalMiddleware(config.EnableTracing, tracingMiddleware()),
    )
}

// Environment-based middleware
func envMiddleware(env string) forge.Middleware {
    if env == "development" {
        return func(next forge.Handler) forge.Handler {
            return func(ctx forge.Context) error {
                // Add debug headers
                ctx.SetHeader("X-Environment", "development")
                ctx.SetHeader("X-Debug", "true")
                return next(ctx)
            }
        }
    }
    return func(next forge.Handler) forge.Handler {
        return next
    }
}

Middleware with Dependencies

Inject dependencies into middleware:

import "github.com/xraph/forge/middleware"

// Middleware factory with dependencies
type MiddlewareFactory struct {
    logger   forge.Logger
    config   *AppConfig
    cache    CacheService
    metrics  MetricsService
}

func NewMiddlewareFactory(
    logger forge.Logger,
    config *AppConfig,
    cache CacheService,
    metrics MetricsService,
) *MiddlewareFactory {
    return &MiddlewareFactory{
        logger:  logger,
        config:  config,
        cache:   cache,
        metrics: metrics,
    }
}

// Create middleware with injected dependencies
func (mf *MiddlewareFactory) CachingMiddleware(ttl time.Duration) forge.Middleware {
    return func(next forge.Handler) forge.Handler {
        return func(ctx forge.Context) error {
            // Check cache
            cacheKey := ctx.Request().URL.Path
            if cached, found := mf.cache.Get(cacheKey); found {
                mf.metrics.IncrementCacheHits()
                return ctx.JSON(200, cached)
            }
            
            // Process request
            err := next(ctx)
            
            // Cache response (simplified)
            mf.metrics.IncrementCacheMisses()
            
            return err
        }
    }
}

// Metrics middleware
func (mf *MiddlewareFactory) MetricsMiddleware() forge.Middleware {
    return func(next forge.Handler) forge.Handler {
        return func(ctx forge.Context) error {
            start := time.Now()
            
            err := next(ctx)
            
            duration := time.Since(start)
            mf.metrics.RecordRequest(
                ctx.Request().Method,
                ctx.Request().URL.Path,
                duration,
            )
            
            return err
        }
    }
}

Configurable Middleware

Create reusable configurable middleware:

// Cache configuration
type CacheConfig struct {
    TTL         time.Duration
    KeyPrefix   string
    OnlyMethods []string
}

// Caching middleware with config
func cachingMiddleware(cache CacheService, config CacheConfig) forge.Middleware {
    // Pre-compile method check map
    allowedMethods := make(map[string]bool)
    for _, method := range config.OnlyMethods {
        allowedMethods[method] = true
    }
    
    return func(next forge.Handler) forge.Handler {
        return func(ctx forge.Context) error {
            method := ctx.Request().Method
            
            // Skip if method not allowed
            if len(allowedMethods) > 0 && !allowedMethods[method] {
                return next(ctx)
            }
            
            cacheKey := config.KeyPrefix + ctx.Request().URL.Path
            
            // Check cache
            if cached, found := cache.Get(cacheKey); found {
                return ctx.JSON(200, cached)
            }
            
            // Execute handler and cache result
            err := next(ctx)
            // Cache logic here
            
            return err
        }
    }
}

Error Handling in Middleware

Forge's error handling system integrates seamlessly with middleware:

import "github.com/xraph/forge/errors"

// Error wrapping middleware
func errorContextMiddleware() forge.Middleware {
    return func(next forge.Handler) forge.Handler {
        return func(ctx forge.Context) error {
            err := next(ctx)
            if err != nil {
                // Add context to errors
                requestID := middleware.GetRequestIDFromForgeContext(ctx)
                
                ctx.Logger().Error("request failed",
                    "error", err,
                    "request_id", requestID,
                    "path", ctx.Request().URL.Path,
                    "method", ctx.Request().Method,
                )
                
                // Return the error for the error handler
                return err
            }
            return nil
        }
    }
}

// Validation error middleware
func validationMiddleware(validator *validator.Validate) forge.Middleware {
    return func(next forge.Handler) forge.Handler {
        return func(ctx forge.Context) error {
            // Handler will validate and return errors
            err := next(ctx)
            
            // Transform validation errors
            if verr, ok := err.(validator.ValidationErrors); ok {
                details := make(map[string]string)
                for _, fe := range verr {
                    details[fe.Field()] = fe.Tag()
                }
                
                return forge.NewHTTPError(422, "validation failed", details)
            }
            
            return err
        }
    }
}

// Database error transformation
func dbErrorMiddleware() forge.Middleware {
    return func(next forge.Handler) forge.Handler {
        return func(ctx forge.Context) error {
            err := next(ctx)
            if err != nil {
                // Transform database errors
                if isDuplicateKeyError(err) {
                    return forge.NewHTTPError(409, "resource already exists")
                }
                if isNotFoundError(err) {
                    return forge.NotFound("resource not found")
                }
            }
            return err
        }
    }
}

Error Flow in Forge

  1. Handler returns error
  2. Middleware can wrap or transform errors
  3. Error handler converts to HTTP response
  4. Recovery middleware catches panics

Use forge.HTTPError for structured error responses.

Performance Optimization

Optimize middleware for production workloads:

Pre-compilation

Pre-compile expensive operations during initialization:

    // Pre-compile regex patterns
func pathMatchingMiddleware() forge.Middleware {
    // Compile once at initialization
    apiPattern := regexp.MustCompile(`^/api/v\d+/`)
    
    return func(next forge.Handler) forge.Handler {
        return func(ctx forge.Context) error {
            path := ctx.Request().URL.Path
            
            // Fast path check
            if !apiPattern.MatchString(path) {
                return next(ctx)
            }
            
            // Expensive operations only for matching paths
            // ... middleware logic
            
            return next(ctx)
        }
    }
}

Object Pooling

Use sync.Pool for frequently allocated objects:

import "sync"

// Buffer pool for reading bodies
var bufferPool = sync.Pool{
    New: func() interface{} {
        return make([]byte, 4096)
    },
}

func bufferedMiddleware() forge.Middleware {
    return func(next forge.Handler) forge.Handler {
        return func(ctx forge.Context) error {
            // Get buffer from pool
        buffer := bufferPool.Get().([]byte)
        defer bufferPool.Put(buffer)
        
        // Use buffer for operations
            // ... middleware logic
            
            return next(ctx)
        }
    }
}

Early Returns

Exit middleware early when possible:

func conditionalMiddleware() forge.Middleware {
    return func(next forge.Handler) forge.Handler {
        return func(ctx forge.Context) error {
            // Fast path: skip middleware for certain routes
            if strings.HasPrefix(ctx.Request().URL.Path, "/health") {
                return next(ctx)
            }
            
            // Only do expensive work when needed
            if ctx.Request().Method == "POST" {
                // Expensive validation
            }
            
            return next(ctx)
        }
    }
}

Avoid Allocations

Minimize memory allocations in hot paths:

func lowAllocMiddleware() forge.Middleware {
    // Pre-allocate reusable structures
    type contextData struct {
        StartTime time.Time
        RequestID string
    }
    
    return func(next forge.Handler) forge.Handler {
        return func(ctx forge.Context) error {
            // Reuse context values instead of creating new ones
            start := time.Now()
            
            err := next(ctx)
            
            // Minimize string concatenation
            _ = time.Since(start)
            
            return err
        }
    }
}

Best Practices

Middleware Best Practices

  1. Order Matters: Request ID → Recovery → Logging → CORS → Auth → Business Logic
  2. Error Handling: Return forge.HTTPError for proper error responses
  3. Performance: Pre-compile patterns, use object pools, exit early
  4. Context Usage: Use ctx.Set() and ctx.Get() for request-scoped data
  5. Testing: Write table-driven tests for all middleware
  6. Reusability: Create configurable factories for common patterns
  7. Security: Validate all inputs, never log sensitive data
  8. Observability: Always include request ID in logs

Testing Middleware

Write comprehensive tests for your middleware:

package middleware_test

import (
    "net/http"
    "net/http/httptest"
    "testing"
    
    "github.com/xraph/forge"
    "github.com/xraph/forge/testing"
)

func TestAuthMiddleware(t *testing.T) {
    tests := []struct {
        name           string
        authHeader     string
        expectedStatus int
        expectedError  bool
    }{
        {
            name:           "valid token",
            authHeader:     "Bearer valid-token",
            expectedStatus: 200,
            expectedError:  false,
        },
        {
            name:           "missing token",
            authHeader:     "",
            expectedStatus: 401,
            expectedError:  true,
        },
        {
            name:           "invalid token",
            authHeader:     "Bearer invalid",
            expectedStatus: 401,
            expectedError:  true,
        },
    }
    
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            // Create test handler
            handler := func(ctx forge.Context) error {
                return ctx.JSON(200, map[string]string{"status": "ok"})
            }
            
            // Wrap with middleware
            middleware := jwtAuthMiddleware("test-secret")
            wrappedHandler := middleware(handler)
            
            // Create test request
            req := httptest.NewRequest("GET", "/test", nil)
            if tt.authHeader != "" {
                req.Header.Set("Authorization", tt.authHeader)
            }
            
            // Create test context
            rec := httptest.NewRecorder()
            ctx := forgetesting.NewTestContext(rec, req)
            
            // Execute handler
            err := wrappedHandler(ctx)
            
            // Assertions
            if tt.expectedError && err == nil {
                t.Error("expected error, got nil")
            }
            if !tt.expectedError && err != nil {
                t.Errorf("unexpected error: %v", err)
            }
        })
    }
}

func TestLoggingMiddleware(t *testing.T) {
    // Mock logger
    var loggedMessages []string
    mockLogger := &MockLogger{
        InfoFunc: func(msg string, args ...interface{}) {
            loggedMessages = append(loggedMessages, msg)
        },
    }
    
    // Create middleware
    middleware := customLoggingMiddleware(mockLogger)
    handler := func(ctx forge.Context) error {
        return ctx.JSON(200, map[string]string{"status": "ok"})
    }
    
    // Test
    req := httptest.NewRequest("GET", "/test", nil)
    rec := httptest.NewRecorder()
    ctx := forgetesting.NewTestContext(rec, req)
    
    wrappedHandler := middleware(handler)
    _ = wrappedHandler(ctx)
    
    // Verify logging
    if len(loggedMessages) < 2 {
        t.Error("expected at least 2 log messages")
    }
}

Middleware Reference

Built-In Middleware Summary

MiddlewarePurposeImport
CORSCross-origin resource sharingmiddleware.CORS()
LoggingRequest/response loggingmiddleware.Logging()
RecoveryPanic recoverymiddleware.Recovery()
RateLimitToken bucket rate limitingmiddleware.RateLimit()
RequestIDUnique request trackingmiddleware.RequestID()
CompressGzip compressionmiddleware.Compress()
TimeoutRequest timeout enforcementmiddleware.Timeout()

Common Middleware Patterns

import "github.com/xraph/forge/middleware"

// Production middleware stack
app.Router().Use(
    middleware.RequestID(),                    // 1. Generate request ID
    middleware.Recovery(app.Logger()),         // 2. Catch panics
    middleware.Logging(app.Logger()),          // 3. Log requests
    middleware.CORS(middleware.DefaultCORSConfig()), // 4. Handle CORS
    middleware.CompressDefault(),              // 5. Compress responses
)

// API group with auth and rate limiting
limiter := middleware.NewRateLimiter(100, 200)
api := app.Router().Group("/api",
    forge.WithGroupMiddleware(middleware.RateLimit(limiter, app.Logger())),
    forge.WithGroupMiddleware(jwtAuthMiddleware("secret")),
)

// Admin group with strict limits
adminLimiter := middleware.NewRateLimiter(10, 20)
admin := api.Group("/admin",
    forge.WithGroupMiddleware(middleware.RateLimit(adminLimiter, app.Logger())),
    forge.WithGroupMiddleware(requireAdminRole()),
)

Next Steps

How is this guide?

Last updated on