File size: 2,242 Bytes
7c6ffa6 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | """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}
|