|
4 | 4 | from http import HTTPStatus |
5 | 5 | from uuid import uuid4 |
6 | 6 |
|
7 | | -from fastapi import FastAPI, HTTPException, Request |
| 7 | +from fastapi import FastAPI, HTTPException, Request, WebSocket |
8 | 8 | from fastapi.exceptions import RequestValidationError |
9 | 9 | from fastapi.responses import JSONResponse |
10 | 10 | from sqlalchemy.exc import OperationalError |
|
14 | 14 | logger = logging.getLogger("api.errors") |
15 | 15 |
|
16 | 16 |
|
17 | | -def _resolve_request_id(request: Request) -> str: |
| 17 | +def _resolve_request_id(request: Request | WebSocket) -> str: |
18 | 18 | request_id = getattr(request.state, "request_id", None) |
19 | 19 | if isinstance(request_id, str) and request_id: |
20 | 20 | return request_id |
@@ -128,17 +128,23 @@ async def validation_exception_handler( |
128 | 128 | return JSONResponse(status_code=422, content=body) |
129 | 129 |
|
130 | 130 | @app.exception_handler(ValueError) |
131 | | - async def value_error_handler(request: Request, exc: ValueError) -> JSONResponse: |
| 131 | + async def value_error_handler(request: Request | WebSocket, exc: ValueError) -> JSONResponse | None: |
132 | 132 | request_id = _resolve_request_id(request) |
| 133 | + path = request.url.path if request.url is not None else "<unknown>" |
| 134 | + method = request.method if isinstance(request, Request) else "WEBSOCKET" |
133 | 135 | logger.warning( |
134 | 136 | "value_error", |
135 | 137 | extra={ |
136 | 138 | "request_id": request_id, |
137 | | - "method": request.method, |
138 | | - "path": request.url.path, |
| 139 | + "method": method, |
| 140 | + "path": path, |
139 | 141 | "error_detail": str(exc), |
140 | 142 | }, |
141 | 143 | ) |
| 144 | + if isinstance(request, WebSocket): |
| 145 | + reason = str(exc) or "Invalid value" |
| 146 | + await request.close(code=1008, reason=reason[:120]) |
| 147 | + return None |
142 | 148 | body = _build_error_body( |
143 | 149 | status_code=422, |
144 | 150 | request_id=request_id, |
|
0 commit comments