klg-asutk-app/backend/app/api/exceptions.py
Yuriy 0150aba4f5 Consolidation: KLG ASUTK + PAPA integration
- Unify API: lib/api.ts uses /api/v1, inbox uses /api/inbox (rewrites)
- Remove localhost refs: openapi, inbox page
- Add rewrites: /api/inbox|tmc -> inbox-server, /api/v1 -> FastAPI
- Add stub routes: knowledge/insights, recommendations, search, log-error
- Transfer from PAPA: prompts (inspection, tmc), scripts, supabase, data/tmc-requests
- Fix inbox-server: ORDER BY created_at, package.json
- Remove redundant app/api/inbox/files route (rewrites handle it)
- knowledge/ in gitignore (large PDFs)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-08 17:18:31 +03:00

74 lines
2.9 KiB
Python

"""
Централизованная обработка исключений для API.
"""
import logging
from fastapi import Request, status
from fastapi.responses import JSONResponse
from fastapi.exceptions import RequestValidationError
from sqlalchemy.exc import SQLAlchemyError, IntegrityError
from pydantic import ValidationError
logger = logging.getLogger(__name__)
async def pydantic_validation_error_handler(request: Request, exc: ValidationError):
"""Ошибки валидации Pydantic при сериализации ответа (например, datetime из SQLite)."""
errs = exc.errors()
logger.warning("Pydantic ValidationError on %s: %s", request.url.path, errs)
return JSONResponse(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
content={
"detail": "Ошибка формата данных. Подробности в логе бэкенда.",
"errors": errs,
},
)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
"""Обработчик ошибок валидации Pydantic."""
errors = exc.errors()
logger.warning(f"Validation error on {request.url.path}: {errors}")
return JSONResponse(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
content={
"detail": "Ошибка валидации данных",
"errors": errors,
},
)
async def integrity_error_handler(request: Request, exc: IntegrityError):
"""Обработчик ошибок целостности БД (дубликаты, внешние ключи и т.д.)."""
logger.error(f"Database integrity error on {request.url.path}: {str(exc)}")
return JSONResponse(
status_code=status.HTTP_409_CONFLICT,
content={
"detail": "Нарушение целостности данных. Возможно, запись уже существует.",
},
)
async def sqlalchemy_error_handler(request: Request, exc: SQLAlchemyError):
"""Обработчик общих ошибок SQLAlchemy."""
logger.error(f"Database error on {request.url.path}: {str(exc)}", exc_info=True)
return JSONResponse(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
content={
"detail": "Ошибка базы данных. Обратитесь к администратору.",
},
)
async def general_exception_handler(request: Request, exc: Exception):
"""Обработчик всех остальных исключений."""
logger.error(
f"Unhandled exception on {request.url.path}: {str(exc)}",
exc_info=True,
)
return JSONResponse(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
content={
"detail": "Внутренняя ошибка сервера. Обратитесь к администратору.",
},
)