# API Design

> Choose the API protocol (REST / GraphQL / gRPC) by traffic shape and design resources, versioning, and async patterns. Use when adding a new API surface, designing a service boundary, or when clients complain about over/under-fetching. Not for the schema/error envelope details (use api-contract) or per-resource access control (use authorization).

- Skill: `jaykim88/api-design` (Agent Skill)
- Install (CLI): `npx skillmds@latest add jaykim88/api-design`
- Raw SKILL.md: https://api.skillmd.com/api/skills/jaykim88/api-design/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- License: MIT
- Author: JayKim88 (https://skillmd.com/u/jaykim88)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/jaykim88/api-design

---


# API Design

## Purpose
Pick the right protocol for each API surface by traffic characteristics — not by fashion — and model resources, versioning, and async operations so the contract can evolve without breaking clients.

**Universal** — protocol selection criteria (latency, client shaping needs, internal vs external), resource modeling, and versioning strategy apply to any language; only the framework's routing/serialization differs.

## Procedure

1. **Choose protocol by traffic shape**
   - **REST** — default for CRUD, public APIs, broad client compatibility, cacheable via HTTP
   - **gRPC** — internal service-to-service, sub-10ms latency mesh, streaming, strict contracts
   - **GraphQL** — clients need field-level shaping / aggregate many resources; accept the schema-design + N+1 discipline cost (requires a per-request batching/caching layer)
   - Decide by *concrete thresholds* (latency budget, payload variability), not "it depends"

2. **Model resources (REST)**
   - Nouns not verbs (`/orders/{id}` not `/getOrder`)
   - Nest only one level deep (`/orders/{id}/items`, not 4 levels)
   - Use sub-resources for relationships, query params for filtering

3. **Design versioning before v1 ships**
   - URL versioning (`/v1/`) — simplest, most visible
   - Header versioning — cleaner URLs, less discoverable
   - Commit to one; document the deprecation policy (sunset header + timeline)

4. **Async / long-running operations**
   - Return `202 Accepted` + a status resource (`/operations/{id}`) for jobs > a few seconds
   - Don't hold the request open; pair with `background-jobs` skill

5. **Validate the design**
   - Walk the top 3 client use cases through the API — count round-trips
   - If a common screen needs 5+ calls → consider GraphQL or a BFF aggregate endpoint

## Anti-patterns

| ❌ Anti-pattern | ✅ Correct |
|---|---|
| Verbs in paths (`/createUser`) | Nouns + HTTP methods (`POST /users`) |
| GraphQL "because it's modern" for a simple CRUD API | REST default; GraphQL only when field-shaping is a real need |
| Breaking change shipped without a version bump | New version OR additive-only change (see `api-contract`) |
| Deep nesting (`/a/{}/b/{}/c/{}`) | Max one level; use query params / sub-resource links |

## Completion Criteria
- [ ] Protocol choice justified by a concrete traffic characteristic (documented)
- [ ] Versioning strategy decided and documented before v1
- [ ] Top 3 client use cases verified for round-trip count
- [ ] Long-running ops return 202 + status resource

## Output
- **API design doc / ADR**: `docs/adr/ADR-NNN-api-<surface>.md` — protocol choice + rationale + versioning policy
- **Route definitions**: with resource modeling applied
- **Commit format**: `feat(api): design <surface> endpoints [protocol: REST|gRPC|GraphQL]`

## Implementation

### TypeScript + NestJS (default)
- REST: NestJS controllers + `@nestjs/swagger` for OpenAPI generation
- GraphQL: `@nestjs/graphql` (code-first) + DataLoader for N+1
- gRPC: `@nestjs/microservices` gRPC transport + `.proto` contracts
- Versioning: NestJS `enableVersioning({ type: VersioningType.URI })`

### Other stacks
- **Python / FastAPI**: native OpenAPI; Strawberry/Ariadne for GraphQL; grpcio for gRPC
- **Go**: chi/echo for REST; gqlgen for GraphQL; google.golang.org/grpc
- **Universal**: resource modeling, versioning, and 202-async patterns are protocol-level, not framework-level

## Related skills
- `api-contract` — once protocol is chosen, define the schema-first contract there
- `schema-design` — resource modeling aligns with DB schema
- `authorization` — per-resource access control

## Reference
- **Key insight encoded**: Pick protocol by traffic shape — REST default for CRUD, gRPC for sub-10ms internal mesh, GraphQL only when clients need field-level shaping (and you accept the schema-design discipline).

