main
py 121 lines 4.12 KB
Raw
1 from fastapi import HTTPException
2 from fastapi import Request
3 from fastapi.exceptions import RequestValidationError
4 from fastapi.responses import JSONResponse
5 from sqlalchemy.ext.asyncio import AsyncSession
6
7 from app.auth.utils import AuthHandler
8 from app.db.db_session import async_engine # Make sure to import the async engine
9 from app.utils import ErrorType
10 from app.utils import Logger
11 from app.utils import ValidationErrorItem
12 from app.utils import ValidationErrorResponse
13
14
15 # Utility function to get user_id from request
16 async def get_user_id_from_request(request: Request, logger_instance):
17 """
18 Retrieves the user ID from the given request using the provided logger instance.
19
20 Args:
21 request (Request): The request object.
22 logger_instance: The logger instance used to retrieve the user ID.
23
24 Returns:
25 The user ID extracted from the request.
26 """
27 return await logger_instance.get_user_id_from_request(request)
28
29
30 async def custom_http_exception_handler(request: Request, exc: HTTPException):
31 """
32 Custom exception handler for handling HTTP exceptions.
33
34 Args:
35 request (Request): The incoming request object.
36 exc (HTTPException): The raised HTTP exception.
37
38 Returns:
39 JSONResponse: The JSON response containing the error details.
40 """
41 async with AsyncSession(async_engine) as session: # Use AsyncSession
42 logger_instance = Logger(session, AuthHandler())
43 user_id = await get_user_id_from_request(request, logger_instance)
44 await logger_instance.log_error(user_id, request, exc.detail)
45 await session.commit() # Make sure to commit the session
46
47 return JSONResponse(
48 status_code=exc.status_code,
49 content={
50 "success": False,
51 "message": exc.detail,
52 },
53 )
54
55
56 async def validation_exception_handler(request: Request, exc: RequestValidationError):
57 """
58 Handles validation exceptions and logs the error.
59
60 Args:
61 request (Request): The incoming request.
62 exc (RequestValidationError): The validation exception.
63
64 Returns:
65 JSONResponse: The JSON response with the validation error details.
66 """
67 errors = exc.errors()
68 details = []
69
70 for error in errors:
71 field = error["loc"][-1]
72 try:
73 error_type = ErrorType(error["type"])
74 except ValueError:
75 # Pydantic 2 emits codes the v1-era ErrorType enum doesn't list
76 # (string_too_long, string_pattern_mismatch, etc.) — fall back to
77 # GENERAL so unknown codes still produce a 422 with a sensible
78 # message instead of crashing the handler.
79 error_type = ErrorType.GENERAL
80 details.append(ValidationErrorItem(field=field, error_type=error_type))
81
82 main_message = details[0].message if details else "Validation Error"
83
84 async with AsyncSession(async_engine) as session: # Use AsyncSession
85 logger_instance = Logger(session, AuthHandler())
86 user_id = await get_user_id_from_request(request, logger_instance)
87 await logger_instance.log_error(user_id, request, main_message)
88 await session.commit() # Make sure to commit the session
89
90 return JSONResponse(
91 status_code=422,
92 content=ValidationErrorResponse(message=main_message, details=details).model_dump(),
93 )
94
95
96 async def value_error_handler(request: Request, exc: ValueError):
97 """
98 Handles the ValueError exception and logs the error message.
99
100 Args:
101 request (Request): The incoming request object.
102 exc (ValueError): The ValueError exception object.
103
104 Returns:
105 JSONResponse: The response containing the error message.
106 """
107 error_message = str(exc)
108
109 async with AsyncSession(async_engine) as session:
110 logger_instance = Logger(session, AuthHandler())
111 user_id = await get_user_id_from_request(request, logger_instance)
112 await logger_instance.log_error(user_id, request, error_message)
113 await session.commit()
114
115 return JSONResponse(
116 status_code=400, # Bad Request
117 content={
118 "success": False,
119 "message": error_message,
120 },
121 )