from datetime import datetime, timezone from typing import Any from uuid import uuid4 from pydantic import BaseModel, Field class ApiMeta(BaseModel): request_id: str = Field(alias="requestId") timestamp: str trace_id: str | None = Field(default=None, alias="traceId") model_config = {"populate_by_name": True} class StandardResponse(BaseModel): code: int = 0 message: str = "ok" data: Any | None = None meta: ApiMeta model_config = {"populate_by_name": True} def build_meta(request_id: str | None = None) -> ApiMeta: return ApiMeta( requestId=request_id or uuid4().hex, timestamp=datetime.now(timezone.utc).isoformat(), traceId=uuid4().hex[:16], ) def ok(data: Any = None, message: str = "ok", request_id: str | None = None) -> dict[str, Any]: return StandardResponse(code=0, message=message, data=data, meta=build_meta(request_id)).model_dump( by_alias=True ) def error(code: int, message: str, request_id: str | None = None, **details: Any) -> dict[str, Any]: payload = {"errorCode": message, **details} if details else {"errorCode": message} return StandardResponse(code=code, message=message, data=payload, meta=build_meta(request_id)).model_dump( by_alias=True )