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}