refactor: update module docstrings for clarity and consistency

This commit is contained in:
Abhimanyu Saharan
2026-02-09 15:49:50 +05:30
parent 78bb08d4a3
commit 7ca1899d9f
99 changed files with 2345 additions and 855 deletions

View File

@@ -1,8 +1,10 @@
"""Global exception handlers and request-id middleware for FastAPI."""
from __future__ import annotations
import logging
from collections.abc import Awaitable, Callable
from typing import Any, Final, cast
from typing import TYPE_CHECKING, Any, Final, cast
from uuid import uuid4
from fastapi import FastAPI, Request
@@ -10,7 +12,9 @@ from fastapi.exceptions import RequestValidationError, ResponseValidationError
from fastapi.responses import JSONResponse
from starlette.exceptions import HTTPException as StarletteHTTPException
from starlette.responses import Response
from starlette.types import ASGIApp, Message, Receive, Scope, Send
if TYPE_CHECKING:
from starlette.types import ASGIApp, Message, Receive, Scope, Send
logger = logging.getLogger(__name__)
@@ -20,12 +24,16 @@ ExceptionHandler = Callable[[Request, Exception], Response | Awaitable[Response]
class RequestIdMiddleware:
"""ASGI middleware that ensures every request has a request-id."""
def __init__(self, app: ASGIApp, *, header_name: str = REQUEST_ID_HEADER) -> None:
"""Initialize middleware with app instance and header name."""
self._app = app
self._header_name = header_name
self._header_name_bytes = header_name.lower().encode("latin-1")
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
"""Inject request-id into request state and response headers."""
if scope["type"] != "http":
await self._app(scope, receive, send)
return
@@ -36,8 +44,11 @@ class RequestIdMiddleware:
if message["type"] == "http.response.start":
# Starlette uses `list[tuple[bytes, bytes]]` here.
headers: list[tuple[bytes, bytes]] = message.setdefault("headers", [])
if not any(key.lower() == self._header_name_bytes for key, _ in headers):
headers.append((self._header_name_bytes, request_id.encode("latin-1")))
if not any(
key.lower() == self._header_name_bytes for key, _ in headers
):
request_id_bytes = request_id.encode("latin-1")
headers.append((self._header_name_bytes, request_id_bytes))
await send(message)
await self._app(scope, receive, send_with_request_id)
@@ -62,8 +73,10 @@ class RequestIdMiddleware:
def install_error_handling(app: FastAPI) -> None:
"""Install middleware and exception handlers on the FastAPI app."""
# Important: add request-id middleware last so it's the outermost middleware.
# This ensures it still runs even if another middleware (e.g. CORS preflight) returns early.
# This ensures it still runs even if another middleware
# (e.g. CORS preflight) returns early.
app.add_middleware(RequestIdMiddleware)
app.add_exception_handler(
@@ -88,7 +101,7 @@ def _get_request_id(request: Request) -> str | None:
return None
def _error_payload(*, detail: Any, request_id: str | None) -> dict[str, Any]:
def _error_payload(*, detail: object, request_id: str | None) -> dict[str, object]:
payload: dict[str, Any] = {"detail": detail}
if request_id:
payload["request_id"] = request_id
@@ -96,7 +109,8 @@ def _error_payload(*, detail: Any, request_id: str | None) -> dict[str, Any]:
async def _request_validation_handler(
request: Request, exc: RequestValidationError
request: Request,
exc: RequestValidationError,
) -> JSONResponse:
# `RequestValidationError` is expected user input; don't log at ERROR.
request_id = _get_request_id(request)
@@ -107,7 +121,8 @@ async def _request_validation_handler(
async def _response_validation_handler(
request: Request, exc: ResponseValidationError
request: Request,
exc: ResponseValidationError,
) -> JSONResponse:
request_id = _get_request_id(request)
logger.exception(
@@ -125,7 +140,10 @@ async def _response_validation_handler(
)
async def _http_exception_handler(request: Request, exc: StarletteHTTPException) -> JSONResponse:
async def _http_exception_handler(
request: Request,
exc: StarletteHTTPException,
) -> JSONResponse:
request_id = _get_request_id(request)
return JSONResponse(
status_code=exc.status_code,
@@ -134,11 +152,18 @@ async def _http_exception_handler(request: Request, exc: StarletteHTTPException)
)
async def _unhandled_exception_handler(request: Request, exc: Exception) -> JSONResponse:
async def _unhandled_exception_handler(
request: Request,
_exc: Exception,
) -> JSONResponse:
request_id = _get_request_id(request)
logger.exception(
"unhandled_exception",
extra={"request_id": request_id, "method": request.method, "path": request.url.path},
extra={
"request_id": request_id,
"method": request.method,
"path": request.url.path,
},
)
return JSONResponse(
status_code=500,