$npx -y skills add proyecto26/system-design-skills --skill api-designThis skill should be used when the user needs to "design the API", do "endpoint design", pin down a "request/response shape", choose a "pagination" strategy (cursor vs offset), add an "idempotency key" to a write, plan "API versioning", an "error contract", or pick between "REST
| 1 | # API Design |
| 2 | |
| 3 | Define the contract between clients and a service: the exact request and response |
| 4 | shapes, how callers page through data, how retried writes stay safe, how errors |
| 5 | are reported, and how the contract evolves. Get this vague and the rest of the |
| 6 | diagram is guesswork (GUIDE #8) — a "NoSQL box" or "user service" solves nothing |
| 7 | until you can write the request, the response, and the key it hits. |
| 8 | |
| 9 | ## When to reach for this |
| 10 | The design has named services and a datastore, and you now need the *interface*: |
| 11 | what a client sends, what it gets back, how it fetches the next page, how it |
| 12 | retries a payment without double-charging, and how a v1 client survives a v2 |
| 13 | deploy. Reach here the moment someone says "fetch the feed" or "store the post" |
| 14 | without a shape. |
| 15 | |
| 16 | ## When NOT to |
| 17 | Before requirements and scale are pinned — the protocol choice depends on |
| 18 | read/write ratio and latency target, not taste (→ `requirements-scoping`, |
| 19 | `back-of-the-envelope`). Don't reach for gRPC, GraphQL, or streaming because they |
| 20 | sound modern; a plain REST/JSON endpoint is the cheapest contract that meets most |
| 21 | constraints, and naming a fancier protocol you don't need is a YAGNI red flag. |
| 22 | Internal data-access keys and partition design live in `data-storage`; this skill |
| 23 | designs the *external* contract that mirrors them. |
| 24 | |
| 25 | ## Clarify first |
| 26 | - **Call shape** — request/response (CRUD), bidirectional/real-time, or one |
| 27 | request → many results (streaming)? This picks the protocol. |
| 28 | - **Read/write ratio and result-set size** — drives pagination and whether reads |
| 29 | need their own optimized path (→ `back-of-the-envelope`). |
| 30 | - **Retry safety** — can a write be safely repeated? Which operations are |
| 31 | naturally idempotent (PUT/DELETE) vs not (POST that creates/charges)? |
| 32 | - **Client diversity & churn** — public third parties (slow to upgrade, need |
| 33 | strict versioning) vs your own apps (ship together)? |
| 34 | - **Latency & payload budget** — mobile/high-latency links favor compact binary |
| 35 | and fewer round trips; browsers favor cacheable HTTP. |
| 36 | |
| 37 | ## The options |
| 38 | |
| 39 | **Protocol / style** (pick per call shape) |
| 40 | - **REST over HTTP/JSON** — resource CRUD over standard verbs. Use as the default |
| 41 | for public, cacheable, browser-friendly APIs. |
| 42 | - **RPC / gRPC (HTTP/2, protobuf)** — typed method calls, compact binary, |
| 43 | streaming. Use for internal service-to-service traffic where latency and schema |
| 44 | contracts matter. |
| 45 | - **GraphQL** — client specifies exactly the fields it wants in one query. Use |
| 46 | when many clients need different shapes of the same graph and over/under-fetching |
| 47 | on REST hurts. |
| 48 | - **WebSocket / SSE (streaming)** — persistent server→client push. Use when the |
| 49 | server must push updates (chat, presence, live feeds) — see the polling tier below. |
| 50 | - **Webhooks** — server calls *the client's* URL on an event. Use for async, |
| 51 | third-party event delivery. |
| 52 | |
| 53 | **Server-push tier** (when clients need fresh data) |
| 54 | - **Polling** → **long-polling** → **SSE** → **WebSocket**, in increasing |
| 55 | efficiency for push and increasing connection cost. Start at polling; escalate |
| 56 | only when a number (update frequency, fanout) forces it. |
| 57 | |
| 58 | **Pagination** |
| 59 | - **Cursor (keyset)** — opaque token over a stable sort key. Default for large or |
| 60 | changing datasets. |
| 61 | - **Offset/limit** — `?offset=40&limit=20`. Use only for small, mostly-static, |
| 62 | jump-to-page lists. |
| 63 | |
| 64 | **Idempotency** — client sends an `Idempotency-Key` on unsafe writes; the server |
| 65 | dedupes retries. This skill owns the key contract (see Interface sketch). |
| 66 | |
| 67 | **Versioning** — URI (`/v2/...`), header (`Accept: application/vnd.x.v2+json`), or |
| 68 | additive/never-break. Prefer additive; reserve a new version for breaking changes. |
| 69 | |
| 70 | ## Trade-offs |
| 71 | |
| 72 | | Option | What it solves | What it worsens | Change it when | |
| 73 | |---|---|---|---| |
| 74 | | REST/JSON | Universal, cacheable, simple, tooling everywhere | Over/under-fetch; chatty for graphs; weak typing | Field-shaping pain → GraphQL; internal latency → gRPC | |
| 75 | | gRPC/RPC | Compact, typed, fast, native streaming | Not browser-native; needs proxy; opaque to HTTP caches | Public/browser clients need it → REST gateway | |
| 76 | | GraphQL | One round trip, client picks fields | Caching/rate-limiting hard; expensive queries (N+1); server complexity | Few fixed shapes (REST simpler) or query cost unbounded | |
| 77 | | WebSocket/SSE | True server push, low-latency updates | Stateful connections, harder to scale/LB, reconnection logic | Updates are infrequent → long-poll; one-way only → S |