46 lines
1.2 KiB
Python
46 lines
1.2 KiB
Python
"""通用响应 Schema。"""
|
|
from datetime import datetime
|
|
from typing import Any
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
class ErrorResponse(BaseModel):
|
|
"""统一错误响应格式。"""
|
|
|
|
detail: str
|
|
code: str # 如 "NOT_FOUND", "VALIDATION_ERROR", "INTERNAL_ERROR", "FORBIDDEN"
|
|
timestamp: datetime = Field(default_factory=datetime.utcnow)
|
|
extra: dict[str, Any] | None = None
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
# 常用错误码常量
|
|
class ErrorCode:
|
|
NOT_FOUND = "NOT_FOUND"
|
|
VALIDATION_ERROR = "VALIDATION_ERROR"
|
|
INTERNAL_ERROR = "INTERNAL_ERROR"
|
|
FORBIDDEN = "FORBIDDEN"
|
|
UNAUTHORIZED = "UNAUTHORIZED"
|
|
CONFLICT = "CONFLICT"
|
|
BAD_REQUEST = "BAD_REQUEST"
|
|
RATE_LIMITED = "RATE_LIMITED"
|
|
|
|
# HTTP 状态码 → 错误码 映射
|
|
STATUS_CODE_MAP: dict[int, str] = {
|
|
400: "BAD_REQUEST",
|
|
401: "UNAUTHORIZED",
|
|
403: "FORBIDDEN",
|
|
404: "NOT_FOUND",
|
|
409: "CONFLICT",
|
|
422: "VALIDATION_ERROR",
|
|
429: "RATE_LIMITED",
|
|
500: "INTERNAL_ERROR",
|
|
503: "SERVICE_UNAVAILABLE",
|
|
}
|
|
|
|
@classmethod
|
|
def from_status(cls, status_code: int) -> str:
|
|
return cls.STATUS_CODE_MAP.get(status_code, "INTERNAL_ERROR")
|