Backend
Middleware

Middleware

The application uses Fiber middleware for request processing, authentication, logging, and more.

Core Middleware

1. Logger Middleware

Logs all HTTP requests and responses.

Features:

  • Request method and path
  • Response status code
  • Response time
  • Request ID for tracing

Registration:

middleware.Register(app, cfg)

2. Recovery Middleware

Recovers from panics and returns 500 error.

Features:

  • Panic recovery
  • Error logging
  • Graceful error responses

3. CORS Middleware

Handles Cross-Origin Resource Sharing.

Configuration:

  • Allows specific origins
  • Configurable headers
  • Configurable methods

4. Request ID Middleware

Adds unique request ID to each request.

Usage:

  • Request ID in response headers
  • Request ID in logs
  • Request tracing

Authentication Middleware

Telegram Auth Middleware

Validates Telegram authentication.

Function: TelegramAuthMiddlewareFunc(cfg)

Behavior:

  • Validates X-Telegram-Auth header
  • Extracts user information
  • Attaches user context to request
  • Returns 401 if invalid

Usage:

app.Get("/protected", 
    middleware.TelegramAuthMiddlewareFunc(cfg), 
    handler.Protected)

Optional Telegram Auth Middleware

Optional Telegram authentication.

Function: OptionalTelegramAuthMiddlewareFunc(cfg)

Behavior:

  • Validates auth if header present
  • Proceeds without auth if header missing
  • Attaches user context if authenticated

Usage:

app.Get("/public", 
    middleware.OptionalTelegramAuthMiddlewareFunc(cfg), 
    handler.Public)

Admin API Key Middleware

Validates admin API key.

Function: AdminAPIKeyAuth(cfg)

Behavior:

  • Validates X-API-Key header
  • Compares with ADMIN_API_KEY from config
  • Returns 401 if invalid

Usage:

admin := app.Group("/admin", middleware.AdminAPIKeyAuth(cfg))

Admin JWT Middleware

Validates admin JWT tokens.

Function: AdminAuthMiddleware(cfg, jwtService)

Behavior:

  • Validates JWT token
  • Checks admin permissions
  • Returns 401 if invalid

Usage:

admin := app.Group("/admin", 
    middleware.AdminAuthMiddleware(cfg, jwtService))

Rate Limiting Middleware

Rate Limit Middleware

Limits request rate per user/IP.

Function: RateLimitMiddleware(config, deps)

Configuration:

config := middleware.RateLimitConfig{
    Max:        100,  // Max requests
    Expiration: time.Minute,  // Time window
    KeyGenerator: func(c *fiber.Ctx) string {
        // Generate key from request
    },
}

Usage:

app.Post("/api/v1/connections", 
    middleware.RateLimitMiddleware(config, deps),
    handler.CreateConnection)

Features:

  • Redis-based rate limiting
  • Per-user/IP limits
  • Configurable limits
  • Custom key generation

Custom Middleware

Request Validation Middleware

Validates request bodies.

Example:

func ValidateRequest(validator *validator.Validate) fiber.Handler {
    return func(c *fiber.Ctx) error {
        var req MyRequest
        if err := c.BodyParser(&req); err != nil {
            return c.Status(400).JSON(fiber.Map{
                "error": "Invalid request body",
            })
        }
        if err := validator.Struct(&req); err != nil {
            return c.Status(400).JSON(fiber.Map{
                "error": "Validation failed",
                "details": err.Error(),
            })
        }
        c.Locals("validated_request", &req)
        return c.Next()
    }
}

Error Handling Middleware

Centralized error handling.

Example:

func ErrorHandler(c *fiber.Ctx, err error) error {
    code := fiber.StatusInternalServerError
    message := "Internal Server Error"
    
    if e, ok := err.(*fiber.Error); ok {
        code = e.Code
        message = e.Message
    }
    
    return c.Status(code).JSON(fiber.Map{
        "error": message,
        "code": fmt.Sprintf("ERR_%d", code),
    })
}

Middleware Order

Middleware is executed in registration order:

  1. Recovery - Catch panics first
  2. Logger - Log all requests
  3. Request ID - Add request ID
  4. CORS - Handle CORS
  5. Authentication - Validate auth
  6. Rate Limiting - Check rate limits
  7. Handler - Process request

Middleware Registration

All middleware is registered in internal/middleware/middleware.go:

func Register(app *fiber.App, cfg *config.Config) {
    // Recovery
    app.Use(recover.New())
    
    // Logger
    app.Use(logger.New())
    
    // Request ID
    app.Use(requestid.New())
    
    // CORS
    app.Use(cors.New(cors.Config{
        AllowOrigins: "*",
        AllowMethods: "GET,POST,PUT,DELETE,OPTIONS",
        AllowHeaders: "Content-Type,Authorization,X-API-Key,X-Telegram-Auth",
    }))
}

Accessing Context

Getting User from Context

func handler(c *fiber.Ctx) error {
    userID := c.Locals("user_id")
    telegramID := c.Locals("telegram_id")
    // Use user information
}

Getting Request ID

func handler(c *fiber.Ctx) error {
    requestID := c.Locals("requestid")
    // Use request ID for logging
}

Best Practices

  1. Order matters - Register middleware in correct order
  2. Fail fast - Authentication before business logic
  3. Error handling - Handle errors gracefully
  4. Logging - Log important events
  5. Performance - Keep middleware lightweight
  6. Security - Validate all inputs
  7. Rate limiting - Protect sensitive endpoints

Testing Middleware

Test Authentication Middleware

func TestTelegramAuth(t *testing.T) {
    app := fiber.New()
    app.Get("/test", 
        middleware.TelegramAuthMiddlewareFunc(cfg),
        func(c *fiber.Ctx) error {
            return c.SendString("OK")
        })
    
    // Test with valid auth
    req := httptest.NewRequest("GET", "/test", nil)
    req.Header.Set("X-Telegram-Auth", validAuth)
    resp, _ := app.Test(req)
    assert.Equal(t, 200, resp.StatusCode)
    
    // Test with invalid auth
    req = httptest.NewRequest("GET", "/test", nil)
    resp, _ = app.Test(req)
    assert.Equal(t, 401, resp.StatusCode)
}