Skip to content

Commit f2315cf

Browse files
feat: Unified response model and exception handling
1 parent 122f47c commit f2315cf

File tree

2 files changed

+84
-1
lines changed

2 files changed

+84
-1
lines changed
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import json
2+
import logging
3+
from starlette.middleware.base import BaseHTTPMiddleware
4+
from starlette.responses import JSONResponse
5+
from starlette.exceptions import HTTPException
6+
from starlette.requests import Request
7+
8+
class ResponseMiddleware(BaseHTTPMiddleware):
9+
def __init__(self, app):
10+
super().__init__(app)
11+
12+
async def dispatch(self, request, call_next):
13+
response = await call_next(request)
14+
15+
if isinstance(response, JSONResponse):
16+
return response
17+
18+
if response.headers.get("content-type") == "application/json":
19+
try:
20+
body = b""
21+
async for chunk in response.body_iterator:
22+
body += chunk
23+
24+
raw_data = json.loads(body.decode())
25+
26+
if isinstance(raw_data, dict) and all(k in raw_data for k in ["code", "data", "msg"]):
27+
return JSONResponse(
28+
content=raw_data,
29+
status_code=response.status_code,
30+
headers={
31+
k: v for k, v in response.headers.items()
32+
if k.lower() not in ("content-length", "content-type")
33+
}
34+
)
35+
36+
wrapped_data = {
37+
"code": 0,
38+
"data": raw_data,
39+
"msg": None
40+
}
41+
42+
return JSONResponse(
43+
content=wrapped_data,
44+
status_code=response.status_code,
45+
headers={
46+
k: v for k, v in response.headers.items()
47+
if k.lower() not in ("content-length", "content-type")
48+
}
49+
)
50+
except Exception as e:
51+
logging.error(f"Response processing error: {str(e)}", exc_info=True)
52+
return response
53+
54+
return response
55+
56+
57+
class exception_handler():
58+
@staticmethod
59+
async def http_exception_handler(request: Request, exc: HTTPException):
60+
return JSONResponse(
61+
status_code=exc.status_code,
62+
content={
63+
"code": exc.status_code,
64+
"msg": exc.detail,
65+
"data": None
66+
}
67+
)
68+
69+
70+
@staticmethod
71+
async def global_exception_handler(request: Request, exc: Exception):
72+
logging.error(f"Error info: {str(exc)}", exc_info=True)
73+
74+
return JSONResponse(
75+
status_code=500,
76+
content={
77+
"code": 500,
78+
"msg": str(exc),
79+
"data": None
80+
}
81+
)
82+

backend/main.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from apps.api import api_router
1010
from apps.system.middleware.auth import TokenMiddleware
1111
from common.core.config import settings
12+
from common.core.response_middleware import ResponseMiddleware
1213

1314
def custom_generate_unique_id(route: APIRoute) -> str:
1415
tag = route.tags[0] if route.tags and len(route.tags) > 0 else ""
@@ -35,10 +36,10 @@ def custom_generate_unique_id(route: APIRoute) -> str:
3536
)
3637

3738
app.add_middleware(TokenMiddleware)
39+
app.add_middleware(ResponseMiddleware)
3840
app.include_router(api_router, prefix=settings.API_V1_STR)
3941

4042

41-
4243
frontend_dist = os.path.abspath("../frontend/dist")
4344
if not os.path.exists(frontend_dist):
4445
logging.warning(f"The front-end build directory does not exist: {frontend_dist}")

0 commit comments

Comments
 (0)