Middleware Flow
Deep dive into the request/response middleware processing pipeline
Middleware Flow
This document details the middleware pipeline in the crelio-app service, explaining how requests are processed, authenticated, and enriched before reaching the view layer.
Overview
The middleware stack is configured in config/settings/base.py. Request processing flows down through the list, while response processing flows up.
Standard vs Custom Middlewares
| Middleware | Type | Responsibility |
|---|---|---|
SecurityMiddleware | Standard | HTTP security headers (HSTS, XSS protection) |
SessionMiddleware | Standard | Hydrates request.session from cookies |
CorsMiddleware | 3rd Party | Handles Cross-Origin Resource Sharing headers |
UserAgentMiddleware | 3rd Party | Parses user agent string |
ErrorReportingMiddleware | Custom | Global exception handling and reporting |
AuthenticationMiddleware | Custom | Multi-tenant authentication and user context |
StoreIdentifierMiddleware | Custom | E-commerce store context resolution |
ThreadingLocaleMiddleware | Custom | Thread-local persistence of request/session |
Detailed Request Flow
The following sequence diagram illustrates the deep logic within the custom middlewares.
Deep Dive: Custom Middlewares
1. ErrorReportingMiddleware
Location: core/middlewares/error_reporting.py
Functions as the safety net for the application. It sits high in the stack to catch exceptions from all subsequent layers.
- Process:
- Catches ALL unhandled exceptions.
- Ignores specific benign errors (
ValidationError,ShippingError). - Reports to Sentry with tags (
app,is_mobile). - Returns a standardized JSON response instead of Django's HTML debug page.
def process_exception(self, request, err):
status_code, response = self.report_exception(request, err)
return JsonResponse(response, status=status_code or 500)2. AuthenticationMiddleware
Location: core/middlewares/authentication.py
The core security gatekeeper. It supports multiple authentication strategies based on the incoming request type.
-
Request Classification:
is_mobile: Requests from mobile apps (uses JWT).is_pacs_request: Internal PACS service communication.is_lambda_request: AWS Lambda callbacks.is_internal_request: Internal microservice calls.is_web: Browser-based session requests.
-
User Type Resolution (Web):
- Determines if the user is a
labuser(staff),patient, orsupportuserbased on URL patterns and session data. - Dispatches to specialized authenticators:
authenticate_labuserauthenticate_patientauthenticate_supportuser
- Determines if the user is a
-
Response Enrichment:
- Sets global cookies:
DEPLOYMENT_ZONE,DEPLOYMENT_MODE. - Injects translation updates if needed.
- Sets global cookies:
3. StoreIdentifierMiddleware
Location: crm/store/middleware.py
Handles context for the e-commerce and patient portal features.
- Logic:
- Inspects
request.get_host()(Domain). - Resolves
store_uuidusingdomain_identifierutility. - If a white-label domain is detected, sets
white_labeled_lab_id. - Injects
store_uuiddirectly intoview_kwargsso views don't need to look it up. - Manages
storeIdcookies to persist store selection across sessions.
- Inspects
4. ThreadingLocaleMiddleware
Location: core/middlewares/local.py
Solves the problem of accessing request.session in deep utility layers where request object isn't available.
- Mechanism:
- Uses python's
threading.local()to create thread-safe storage. - Saves
request.sessionat start of request. - Clears it at end of request to prevent memory leaks or data pollution.
- Usage: Used by
ActivityLogand other audit utilities to get the current user ID without passingrequestthrough every function signature.
- Uses python's
Critical Logic Paths
Authentication Bypass
- URL patterns defined in
guest_methodsdecorator or views marked withauthentication_classes = []in DRF are NOT skipped by this middleware. - Instead, the middleware checks
resolve(request.path).view_name in guest_methods. - Warning: If a view is public, it must be explicitly marked.
Exception Handling
ValidationErroris treated as a logic error, not a system crash. It returns 400 (or custom status) and is NOT reported to Sentry.Ratelimitedexceptions return 429 Too Many Requests.