response.py 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. """统一响应格式"""
  2. from typing import Any, Generic, Optional, TypeVar, List
  3. from pydantic import BaseModel, Field
  4. T = TypeVar("T")
  5. class ResponseModel(BaseModel, Generic[T]):
  6. """通用响应格式"""
  7. code: int = 200
  8. message: str = "success"
  9. data: Optional[T] = None
  10. timestamp: int = 0
  11. class Config:
  12. from_attributes = True
  13. class PageResult(BaseModel, Generic[T]):
  14. """分页响应格式"""
  15. items: List[T] = Field(default_factory=list, serialization_alias="list")
  16. total: int = 0
  17. page: int = 1
  18. pageSize: int = 10
  19. totalPages: int = 0
  20. def success_response(data: Any = None, message: str = "success") -> dict:
  21. """成功响应"""
  22. from datetime import datetime
  23. return {
  24. "code": 200,
  25. "message": message,
  26. "data": data,
  27. "timestamp": int(datetime.now().timestamp() * 1000)
  28. }
  29. def format_api_error_message(exc: Exception, *, fallback: str = "操作失败") -> str:
  30. """将 HTTP/SQLAlchemy 等异常转为可展示的错误文案(避免 str([]) 空列表)。"""
  31. if isinstance(exc, PermissionError):
  32. return str(exc) or fallback
  33. status_code = getattr(exc, "status_code", None)
  34. if status_code is not None:
  35. detail = getattr(exc, "detail", None)
  36. if isinstance(detail, str) and detail.strip():
  37. return detail
  38. if detail not in (None, "", []):
  39. return str(detail)
  40. msg = str(exc).strip()
  41. if msg and msg != "[]":
  42. return msg
  43. return fallback
  44. def error_response(code: int = 400, message: str = "error", data: Any = None) -> dict:
  45. """错误响应"""
  46. from datetime import datetime
  47. return {
  48. "code": code,
  49. "message": message,
  50. "data": data,
  51. "timestamp": int(datetime.now().timestamp() * 1000)
  52. }