upload
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any
|
||||
import uuid
|
||||
import logging
|
||||
|
||||
from fastapi import Request, status
|
||||
from fastapi.exceptions import RequestValidationError
|
||||
from fastapi.responses import JSONResponse
|
||||
from starlette.exceptions import HTTPException
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def now_iso() -> str:
|
||||
return datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
|
||||
|
||||
|
||||
async def validation_exception_handler(request: Request, exc: RequestValidationError) -> JSONResponse:
|
||||
trace_id = getattr(request.state, "traceId", str(uuid.uuid4()))
|
||||
is_json_error = any(e.get("type") in ("json_invalid", "json_decode", "value_error.jsondecode") for e in exc.errors())
|
||||
|
||||
if is_json_error:
|
||||
return JSONResponse(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
content={
|
||||
"code": "BAD_REQUEST",
|
||||
"message": "Невалидный JSON",
|
||||
"traceId": trace_id,
|
||||
"timestamp": now_iso(),
|
||||
"path": request.url.path,
|
||||
"details": {"hint": "Проверьте запятые/кавычки"},
|
||||
},
|
||||
)
|
||||
|
||||
field_errors: list[dict[str, Any]] = []
|
||||
for err in exc.errors():
|
||||
loc = [str(x) for x in err.get("loc", []) if x != "body"]
|
||||
field_name = ".".join(loc) if loc else "unknown"
|
||||
|
||||
msg = err.get("msg", "invalid")
|
||||
if msg.startswith("Value error, "):
|
||||
msg = msg.replace("Value error, ", "")
|
||||
|
||||
field_errors.append({
|
||||
"field": field_name,
|
||||
"issue": msg,
|
||||
"rejectedValue": err.get("input", None),
|
||||
})
|
||||
|
||||
return JSONResponse(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
content={
|
||||
"code": "VALIDATION_FAILED",
|
||||
"message": "Некоторые поля не прошли валидацию",
|
||||
"traceId": trace_id,
|
||||
"timestamp": now_iso(),
|
||||
"path": request.url.path,
|
||||
"fieldErrors": field_errors,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
async def http_exception_handler(request: Request, exc: HTTPException) -> JSONResponse:
|
||||
trace_id = getattr(request.state, "traceId", str(uuid.uuid4()))
|
||||
|
||||
message = str(exc.detail)
|
||||
details = None
|
||||
|
||||
if isinstance(exc.detail, dict):
|
||||
message = exc.detail.get("message", str(exc.detail))
|
||||
details_data = {k: v for k, v in exc.detail.items() if k != "message"}
|
||||
if details_data:
|
||||
details = details_data
|
||||
|
||||
code = "HTTP_ERROR"
|
||||
if exc.status_code == status.HTTP_409_CONFLICT:
|
||||
code = "EMAIL_ALREADY_EXISTS" if "email" in message.lower() else "CONFLICT"
|
||||
elif exc.status_code == status.HTTP_400_BAD_REQUEST:
|
||||
code = "BAD_REQUEST"
|
||||
elif exc.status_code == status.HTTP_401_UNAUTHORIZED:
|
||||
code = "UNAUTHORIZED"
|
||||
elif exc.status_code == status.HTTP_423_LOCKED:
|
||||
code = "USER_INACTIVE"
|
||||
elif exc.status_code == status.HTTP_403_FORBIDDEN:
|
||||
code = "FORBIDDEN"
|
||||
elif exc.status_code == status.HTTP_404_NOT_FOUND:
|
||||
code = "NOT_FOUND"
|
||||
if message == "Not Found":
|
||||
message = "Ресурс не найден"
|
||||
elif exc.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY:
|
||||
code = "VALIDATION_FAILED"
|
||||
|
||||
content = {
|
||||
"code": code,
|
||||
"message": message,
|
||||
"traceId": trace_id,
|
||||
"timestamp": now_iso(),
|
||||
"path": request.url.path,
|
||||
}
|
||||
|
||||
if details:
|
||||
content["details"] = details
|
||||
|
||||
return JSONResponse(
|
||||
status_code=exc.status_code,
|
||||
content=content,
|
||||
)
|
||||
|
||||
|
||||
async def unhandled_exception_handler(request: Request, exc: Exception) -> JSONResponse:
|
||||
trace_id = getattr(request.state, "traceId", str(uuid.uuid4()))
|
||||
logger.exception("Unhandled exception on %s", request.url.path, exc_info=exc)
|
||||
|
||||
return JSONResponse(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
content={
|
||||
"code": "INTERNAL_ERROR",
|
||||
"message": "Внутренняя ошибка сервера",
|
||||
"traceId": trace_id,
|
||||
"timestamp": now_iso(),
|
||||
"path": request.url.path,
|
||||
},
|
||||
)
|
||||
Reference in New Issue
Block a user