DocDoeAI / app /core /response.py
asnannp's picture
Deploy backend cd4237ff: support routes + rate limit + exam_date nullable + upload 413 fix
7c6ffa6
Raw
History Blame Contribute Delete
2.24 kB
"""Standard API response envelope.
All new endpoints should return via these helpers to produce a consistent
``{success, data, meta}`` shape that the frontend can depend on.
Existing endpoints are NOT required to migrate — this is additive only.
Usage::
from app.core.response import ok, created, paginated
@router.get("/sync/progress")
def get_progress(...):
return ok({"events": []})
@router.post("/sync/progress")
def post_progress(...):
return created({"synced": True}, message="Progress recorded.")
"""
from __future__ import annotations
from datetime import datetime, timezone
from typing import Any
def _now_iso() -> str:
return datetime.now(timezone.utc).isoformat()
def ok(
data: Any,
*,
meta: dict[str, Any] | None = None,
message: str | None = None,
) -> dict[str, Any]:
"""Return a 200 OK envelope.
Shape::
{"success": true, "data": <data>, "meta": {"timestamp": "...", ...}}
"""
m: dict[str, Any] = {"timestamp": _now_iso()}
if meta:
m.update(meta)
if message:
m["message"] = message
return {"success": True, "data": data, "meta": m}
def created(
data: Any,
*,
meta: dict[str, Any] | None = None,
message: str | None = None,
) -> dict[str, Any]:
"""Return a 201 Created envelope (same shape as ``ok``)."""
return ok(data, meta=meta, message=message)
def paginated(
data: list[Any],
*,
total: int,
page: int = 1,
per_page: int = 20,
extra_meta: dict[str, Any] | None = None,
) -> dict[str, Any]:
"""Return a paginated 200 OK envelope.
Shape::
{
"success": true,
"data": [...],
"meta": {
"timestamp": "...",
"total": 42,
"page": 1,
"per_page": 20,
"pages": 3
}
}
"""
pages = max(1, (total + per_page - 1) // per_page)
meta: dict[str, Any] = {
"timestamp": _now_iso(),
"total": total,
"page": page,
"per_page": per_page,
"pages": pages,
}
if extra_meta:
meta.update(extra_meta)
return {"success": True, "data": data, "meta": meta}