"""Middleware to propagate or generate request_id for every request.""" import uuid from starlette.middleware.base import BaseHTTPMiddleware from starlette.requests import Request from starlette.responses import Response from app.core.logging_config import request_id_ctx REQUEST_ID_HEADER = "X-Request-ID" class RequestIDMiddleware(BaseHTTPMiddleware): """Extract X-Request-ID from incoming request headers or generate one. The request_id is stored in a ContextVar so that all log records emitted during the request are automatically annotated with it, without needing to pass it explicitly through every call. The same request_id is also echoed back in the response header so that callers can correlate logs. """ async def dispatch(self, request: Request, call_next) -> Response: request_id = request.headers.get(REQUEST_ID_HEADER) or str(uuid.uuid4()) token = request_id_ctx.set(request_id) try: response = await call_next(request) finally: request_id_ctx.reset(token) response.headers[REQUEST_ID_HEADER] = request_id return response