feat(api): add POST/GET /v1/files with auth, error envelope, and request-id middleware
Why: - Wires the ADR-0008 error envelope, per-request correlation id, and the /v1/files routes into the app. Changes: - Extend AppResources/lifespan with the ingestion CapacityLimiter and ObjectStorage adapter. Impact: - /v1 now exposes routes for the first time.
This commit is contained in:
38
src/api/middleware.py
Normal file
38
src/api/middleware.py
Normal file
@@ -0,0 +1,38 @@
|
||||
"""Per-request correlation id (ADR-0008, ADR-0011).
|
||||
|
||||
Every request gets a `request_id`: reused from an incoming `X-Request-Id` if
|
||||
the caller supplied one, otherwise generated. It is bound into structlog's
|
||||
contextvars so every log line emitted while handling the request carries it,
|
||||
stored on `request.state` for exception handlers, and echoed back in the
|
||||
response header.
|
||||
"""
|
||||
|
||||
import uuid
|
||||
from collections.abc import Awaitable, Callable
|
||||
from typing import override
|
||||
|
||||
import structlog
|
||||
from starlette.middleware.base import BaseHTTPMiddleware
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import Response
|
||||
|
||||
_HEADER = "X-Request-Id"
|
||||
|
||||
|
||||
class RequestIdMiddleware(BaseHTTPMiddleware):
|
||||
@override
|
||||
async def dispatch(
|
||||
self, request: Request, call_next: Callable[[Request], Awaitable[Response]]
|
||||
) -> Response:
|
||||
request_id = request.headers.get(_HEADER) or str(uuid.uuid4())
|
||||
request.state.request_id = request_id
|
||||
|
||||
structlog.contextvars.clear_contextvars()
|
||||
structlog.contextvars.bind_contextvars(request_id=request_id)
|
||||
try:
|
||||
response = await call_next(request)
|
||||
finally:
|
||||
structlog.contextvars.clear_contextvars()
|
||||
|
||||
response.headers[_HEADER] = request_id
|
||||
return response
|
||||
Reference in New Issue
Block a user