Skip to main content
Middlewares play a crucial role in the Definable backend, providing cross-cutting functionality that applies to all requests and responses. This document explains the middleware architecture and how it fits into the overall application flow.

What are Middlewares?

Middlewares in Definable are components that process HTTP requests and responses at the global level. They wrap around the request handling process, allowing code to be executed:
  1. Before the request is processed by the route handlers
  2. After the route handler generates a response

Middleware Implementation

Definable middlewares are implemented using Starlette’s BaseHTTPMiddleware class, which FastAPI inherits from. Each middleware follows a consistent pattern:

Middleware Registration

Middlewares are automatically discovered and registered in the FastAPI application by the Manager class, which scans the middlewares directory for Python files:
This approach allows middlewares to be added or removed without modifying the application’s core code.

Middleware Stack

Middlewares are executed in the reverse order they are added to the FastAPI application. The current middleware stack in Definable is:
  1. CORS Middleware - Added directly in app.py for handling Cross-Origin Resource Sharing
  2. RateLimiting Middleware - Limits the number of requests per client IP
  3. Exceptions Middleware - Global exception handling and formatting
The middleware stack order is important as it determines both the pre-processing and post-processing execution sequence. CORS middleware is executed first for pre-processing but last for post-processing.

Core Middlewares

Exception Handling Middleware

The exceptions.py middleware provides centralized error handling for the application:
Key features:
  • Catches all unhandled exceptions from route handlers
  • Provides detailed error information in development mode
  • Logs exceptions with full stack trace
  • Returns simplified error messages in production

Rate Limiting Middleware

The ratelimit.py middleware implements a sliding window rate limiter to prevent API abuse:
Key features:
  • Implements a sliding window algorithm rather than a fixed time bucket
  • Tracks requests per client IP address
  • Configurable maximum requests and time window
  • Returns HTTP 429 (Too Many Requests) when rate limit is exceeded

CORS Middleware

The Cross-Origin Resource Sharing middleware is added directly in app.py:
Key features:
  • Controls which domains can access the API
  • Configures allowed HTTP methods and headers
  • Manages preflight requests automatically
  • Essential for browser-based clients accessing the API

Middleware vs. Dependencies

Definable uses both middlewares and FastAPI dependencies to handle cross-cutting concerns, but they serve different purposes:

Middlewares

  • Global scope: Applied to all requests
  • Pre/post processing: Can modify both requests and responses
  • Application-level concerns: Logging, error handling, rate limiting
  • No access to route-specific details: Limited context about the specific endpoint

Dependencies (like RBAC and JWTBearer)

  • Route-specific: Applied only to routes that declare them
  • Integrated with OpenAPI: Included in API documentation
  • Request-specific validation: Can validate and extract route-specific data
  • Type safety: Provide type hints for route handlers

Creating New Middlewares

To add a new middleware to the Definable backend:
  1. Create a new file in the src/middlewares/ directory
  2. Implement a class named Middleware that inherits from BaseHTTPMiddleware
  3. Implement the __init__ and dispatch methods
  4. The middleware will be automatically discovered and registered
Example of a new logging middleware:

Middleware Best Practices

When working with middlewares in Definable, follow these best practices:
  1. Keep middlewares focused: Each middleware should have a single responsibility
  2. Minimize middleware overhead: Optimize performance-critical code
  3. Handle exceptions: Catch and handle exceptions within the middleware
  4. Use dependency injection: Leverage the Acquire class for dependencies
  5. Consider order: Be aware of middleware execution order
  6. Prefer dependencies for route-specific concerns: Use FastAPI dependencies instead of parsing route data in middlewares

Performance Considerations

Middlewares run for every request, so they can impact API performance:
  • Memory usage: Avoid storing large amounts of data in middleware instances
  • Computation overhead: Minimize complex calculations in the request path
  • Database access: Avoid database queries in middlewares when possible
  • Caching: Consider caching results for expensive operations

Security Middlewares

While authentication in Definable is primarily handled by dependencies (JWTBearer and RBAC), security-related middlewares could be added for:
  • IP filtering: Blocking requests from suspicious IPs
  • Request validation: Scanning for malicious patterns
  • Response headers: Adding security headers like CSP, HSTS
  • Request throttling: More advanced rate limiting strategies

Summary

Middlewares in Definable provide a powerful mechanism for implementing cross-cutting concerns that apply to all API requests. They are automatically discovered and registered, making the architecture extensible and maintainable. The core middlewares handle essential functionality like exception management, rate limiting, and CORS, while working alongside FastAPI dependencies to create a comprehensive request processing pipeline.