Sfoglia il codice sorgente

api 返回统一格式。

tanlie 1 mese fa
parent
commit
65a825a5d0

+ 66 - 1
FastApi/app/__init__.py

@@ -3,12 +3,77 @@ __init__.py -
 auther: tanlie
 date: 2026/8/30
 """
-from fastapi import FastAPI
+import logging
+import traceback
+from fastapi import FastAPI, Request, HTTPException
+from fastapi.exceptions import RequestValidationError
+from fastapi.responses import JSONResponse
 
 from app.mobile import register_mobile_routes
+from app.core.response import error_response
+
+# Basic logging configuration for the app; applications may override this
+logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s: %(message)s")
+logger = logging.getLogger("app")
 
 
 def create_app():
     app = FastAPI()
     register_mobile_routes(app)
+
+    @app.exception_handler(RequestValidationError)
+    async def validation_exception_handler(request: Request, exc: RequestValidationError):
+        # Build a friendly, JSON-serializable summary of validation errors
+        errors = []
+        for e in exc.errors():
+            loc = e.get("loc", [])
+            # remove leading location indicators like 'body', 'query', 'path', 'header'
+            if loc and len(loc) > 0 and str(loc[0]) in ("body", "query", "path", "header"):
+                loc_parts = loc[1:]
+            else:
+                loc_parts = loc
+            # join remaining location parts into a dotted path for readability
+            loc_str = ".".join([str(p) for p in loc_parts if p is not None]) if loc_parts else ""
+            errors.append({"field": loc_str, "message": e.get("msg", "")})
+
+        # Log validation details for debugging
+        logger.info("Validation error for %s: %s", request.url.path, errors)
+
+        return JSONResponse(
+            status_code=422,
+            content=error_response(msg="参数校验失败", code=422, data=errors),
+        )
+
+    @app.exception_handler(HTTPException)
+    async def http_exception_handler(request: Request, exc: HTTPException):
+        # Use HTTPException's status_code and detail
+        detail = exc.detail if exc.detail is not None else ""
+        logger.warning("HTTPException for %s: %s", request.url.path, detail)
+        return JSONResponse(
+            status_code=getattr(exc, "status_code", 500),
+            content=error_response(msg=str(detail), code=getattr(exc, "status_code", 500)),
+        )
+
+    @app.exception_handler(Exception)
+    async def generic_exception_handler(request: Request, exc: Exception):
+        # Map common ValueError to a friendlier 400 parameter error
+        if isinstance(exc, ValueError):
+            # Log with stack for debugging
+            tb = "".join(traceback.format_exception(type(exc), exc, exc.__traceback__))
+            logger.warning("ValueError on %s: %s\n%s", request.url.path, str(exc), tb)
+            return JSONResponse(
+                status_code=400,
+                content=error_response(msg=str(exc) or "参数错误", code=400),
+            )
+
+        # Generic fallback to avoid leaking internal stack traces
+        # Log full stack trace for internal debugging
+        tb = "".join(traceback.format_exception(type(exc), exc, exc.__traceback__))
+        logger.error("Unhandled exception on %s: %s\n%s", request.url.path, str(exc), tb)
+
+        return JSONResponse(
+            status_code=500,
+            content=error_response(msg="服务器内部错误", code=500),
+        )
+
     return app

+ 3 - 0
FastApi/app/core/__init__.py

@@ -0,0 +1,3 @@
+from .response import success_response, error_response
+
+__all__ = ["success_response", "error_response"]

+ 15 - 0
FastApi/app/core/response.py

@@ -0,0 +1,15 @@
+"""Common response helpers for the project.
+
+Provides success_response and error_response helpers to standardize API responses.
+"""
+from typing import Any, Dict
+
+
+def success_response(data: Any = None, msg: str = "success", code: int = 200) -> Dict[str, Any]:
+    """Return a standardized success response."""
+    return {"code": code, "msg": msg, "data": data}
+
+
+def error_response(msg: str = "error", code: int = 500, data: Any = None) -> Dict[str, Any]:
+    """Return a standardized error response."""
+    return {"code": code, "msg": msg, "data": data}

+ 10 - 5
FastApi/app/mobile/views/user_views.py

@@ -3,32 +3,37 @@ user - mobile user views
 auther: tanlie
 date: 2026/8/30
 """
-from fastapi import APIRouter, Query, Body
+from typing import Any
+
+from fastapi import APIRouter, Body, Query
 
 from app.mobile.req.user import UserLoginReq
 
 user = APIRouter(prefix="/dgapi/mobile/user", tags=["mobile user"])
 
 
+from app.core.response import success_response, error_response
+
+
 @user.get("/login/captcha", summary="获取验证码")
 def get_captcha(type: int = Query(default=1, description="验证码类型,1:登录验证码,2:注册验证码")):
     print(f"获取验证码,type={type}")
-    return {"message": "get captcha"}
+    return success_response(data={"type": type}, msg="获取验证码成功")
 
 
 @user.post("/login", summary="登录")
 def login(req: UserLoginReq):
     print(f"用户登录,请求参数:{req}")
-    return {"message": "login"}
+    return success_response(data={"user": req.model_dump()}, msg="登录成功")
 
 
 @user.post("/logout", summary="登出")
 def logout(userId: int = Body(description="用户ID")):
     print(f"用户登出,userId={userId}")
-    return {"message": "logout"}
+    return success_response(data={"userId": userId}, msg="退出成功")
 
 
 @user.get("/wish-summary", summary="心愿单摘要")
 def wish_summary():
     print("获取心愿单摘要")
-    return "心愿单"
+    return success_response(data={"wish_summary": "心愿单"}, msg="查询成功")