1
1
import orjson
2
2
from fastapi import FastAPI , Request
3
+ from fastapi .exceptions import ResponseValidationError
3
4
from fastapi .responses import JSONResponse
4
5
from rotoger import AppStructLogger
5
6
from sqlalchemy .exc import SQLAlchemyError
6
7
7
8
logger = AppStructLogger ().get_logger ()
8
9
9
- #TODO: add reasoning for this in readme plus higligh using re-raise in db session
10
+
11
+ # TODO: add reasoning for this in readme plus higligh using re-raise in db session
10
12
async def sqlalchemy_exception_handler (
11
13
request : Request , exc : SQLAlchemyError
12
14
) -> JSONResponse :
@@ -30,6 +32,51 @@ async def sqlalchemy_exception_handler(
30
32
)
31
33
32
34
35
+ async def response_validation_exception_handler (
36
+ request : Request , exc : ResponseValidationError
37
+ ) -> JSONResponse :
38
+ request_path = request .url .path
39
+ try :
40
+ raw_body = await request .body ()
41
+ request_body = orjson .loads (raw_body ) if raw_body else None
42
+ except orjson .JSONDecodeError :
43
+ request_body = None
44
+
45
+ errors = exc .errors ()
46
+
47
+ # Check if this is a None/null response case
48
+ is_none_response = False
49
+ for error in errors :
50
+ # Check for null input pattern
51
+ if error .get ("input" ) is None and "valid dictionary" in error .get ("msg" , "" ):
52
+ is_none_response = True
53
+ break
54
+
55
+ await logger .aerror (
56
+ "Response validation error occurred" ,
57
+ validation_errors = errors ,
58
+ request_url = request_path ,
59
+ request_body = request_body ,
60
+ is_none_response = is_none_response ,
61
+ )
62
+
63
+ if is_none_response :
64
+ # Return 404 when response is None (resource not found)
65
+ return JSONResponse (
66
+ status_code = 404 ,
67
+ content = {"no_response" : "The requested resource was not found" },
68
+ )
69
+ else :
70
+ # Return 422 when response exists but doesn't match expected format
71
+ return JSONResponse (
72
+ status_code = 422 ,
73
+ content = {"response_format_error" : errors },
74
+ )
75
+
76
+
33
77
def register_exception_handlers (app : FastAPI ) -> None :
34
78
"""Register all exception handlers with the FastAPI app."""
35
79
app .add_exception_handler (SQLAlchemyError , sqlalchemy_exception_handler )
80
+ app .add_exception_handler (
81
+ ResponseValidationError , response_validation_exception_handler
82
+ )
0 commit comments