api-design-expert · diff
git:20260913.4cedcda to v3.0.0
317 added, 317 removed. Audit A to A.
- ---
- name: api-design-expert
- description: "Expert guide for designing robust APIs: REST best practices, GraphQL, gRPC, tRPC, OpenAPI/Swagger, API versioning, rate limiting, and contract-first design / Panduan ahli untuk merancang API yang kuat: praktik terbaik REST, GraphQL, gRPC, tRPC, OpenAPI/Swagger, versioning API, rate limiting, dan desain contract-first."
- author: "Roedy Rustam"
- ---
-
- # API Design Expert
-
- [English](#english) | [Bahasa Indonesia](#bahasa-indonesia)
-
- ---
-
- <a name="english"></a>
- ## English
-
- ### Description
- Expert guide for designing, documenting, and evolving production-grade APIs. Covers **REST** resource modeling and HTTP semantics, **GraphQL** schema design, **gRPC** with protobuf, and **tRPC** for end-to-end type-safe APIs in TypeScript monorepos. Includes OpenAPI 3.1 documentation, API versioning strategies, rate limiting, idempotency, and contract-first development workflows.
-
- ### Trigger Conditions
- - Designing a new API from scratch (REST, GraphQL, gRPC, or tRPC).
- - Evolving an existing API without breaking clients.
- - Documenting APIs with OpenAPI/Swagger.
- - Implementing rate limiting, throttling, or idempotency.
- - Choosing between REST, GraphQL, gRPC, and tRPC.
- - Designing webhook systems.
- - Implementing API authentication (API keys, JWT, OAuth2).
-
- ---
-
- ### API Protocol Selection Guide
-
- | Criteria | REST | GraphQL | gRPC | tRPC |
- |---|---|---|---|---|
- | **Type Safety** | Manual (OpenAPI) | Schema-enforced | Protobuf | End-to-end TS |
- | **Performance** | Good | Good | Excellent (HTTP/2) | Good |
- | **Browser Support** | Native | Native | Needs proxy | TS/JS only |
- | **Streaming** | SSE / WebSocket | Subscriptions | Native bi-directional | SSE |
- | **Best For** | Public APIs, mobile | Complex data graphs | Microservice-to-service | Next.js full-stack |
- | **Tooling** | Universal | Rich ecosystem | Strong (Go, Java) | Next.js / Expo |
-
- ---
-
- ### REST API Design Principles
-
- #### Resource Naming Conventions
- ```
- Collection: GET /api/v1/posts
- Item: GET /api/v1/posts/{id}
- Sub-resource:GET /api/v1/posts/{id}/comments
- Action: POST /api/v1/posts/{id}/publish (use sparingly)
-
- AVOID: /api/v1/getPosts, /api/v1/createPost, /api/v1/deletePost/{id}
- ```
-
- #### HTTP Method Semantics
- | Method | Idempotent | Safe | Use Case |
- |---|---|---|---|
- | `GET` | Yes | Yes | Retrieve resources |
- | `POST` | No | No | Create resources, trigger actions |
- | `PUT` | Yes | No | Replace entire resource |
- | `PATCH` | No | No | Partial update |
- | `DELETE` | Yes | No | Remove resource |
-
- #### Consistent Response Structure
- ```typescript
- // Success response
- {
- "data": { "id": "usr_01", "email": "user@example.com" },
- "meta": { "requestId": "req_xyz", "timestamp": "2026-01-01T00:00:00Z" }
- }
-
- // Paginated list response
- {
- "data": [...],
- "meta": {
- "total": 1234,
- "page": 2,
- "pageSize": 20,
- "hasNextPage": true,
- "nextCursor": "eyJpZCI6"
- }
- }
-
- // Error response (RFC 9457 Problem Details)
- {
- "type": "https://api.example.com/errors/validation-failed",
- "title": "Validation Failed",
- "status": 422,
- "detail": "The 'email' field must be a valid email address.",
- "instance": "/api/v1/users",
- "errors": [
- { "field": "email", "message": "Invalid email format" }
- ]
- }
- ```
-
- #### HTTP Status Codes — Correct Usage
- ```
- 200 OK — Successful GET, PUT, PATCH
- 201 Created — Successful POST (include Location header)
- 204 No Content — Successful DELETE
- 400 Bad Request — Invalid request body or params
- 401 Unauthorized— Missing or invalid authentication
- 403 Forbidden — Authenticated but not authorized
- 404 Not Found — Resource not found
- 409 Conflict — Duplicate key, version conflict
- 422 Unprocessable Entity — Validation failure
- 429 Too Many Requests — Rate limit exceeded (include Retry-After)
- 500 Internal Server Error— Unexpected server error
- ```
-
- ---
-
- ### API Versioning Strategies
-
- ```
- Strategy 1 — URL Path (Recommended for public APIs):
- GET /api/v1/users
- GET /api/v2/users
-
- Strategy 2 — Header:
- GET /api/users
- Accept: application/vnd.example.v2+json
-
- Strategy 3 — Query Parameter (Avoid in production):
- GET /api/users?version=2
- ```
-
- **Rules for non-breaking changes** (no version bump needed):
- - Adding new optional fields to responses.
- - Adding new optional request parameters.
- - Adding new endpoints.
-
- **Breaking changes** (require new version):
- - Removing or renaming fields.
- - Changing field types.
- - Changing error response structure.
-
- ---
-
- ### tRPC — End-to-End Type Safety
-
- ```typescript
- // server/router.ts
- import { initTRPC, TRPCError } from '@trpc/server';
- import { z } from 'zod';
-
- const t = initTRPC.context<Context>().create();
- export const router = t.router;
- export const publicProcedure = t.procedure;
- export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
- if (!ctx.session?.user) throw new TRPCError({ code: 'UNAUTHORIZED' });
- return next({ ctx: { ...ctx, user: ctx.session.user } });
- });
-
- export const appRouter = router({
- users: router({
- list: publicProcedure
- .input(z.object({ page: z.number().int().min(1).default(1) }))
- .query(async ({ input, ctx }) => {
- return ctx.db.user.findMany({ skip: (input.page - 1) * 20, take: 20 });
- }),
- create: protectedProcedure
- .input(z.object({ email: z.string().email(), name: z.string().min(2) }))
- .mutation(async ({ input, ctx }) => {
- return ctx.db.user.create({ data: input });
- }),
- }),
- });
-
- export type AppRouter = typeof appRouter;
- // Client automatically infers all types — no code generation needed
- ```
-
- ---
-
- ### Rate Limiting Implementation
-
- ```typescript
- // Sliding window rate limit with Redis (using Upstash)
- import { Ratelimit } from '@upstash/ratelimit';
- import { Redis } from '@upstash/redis';
-
- const ratelimit = new Ratelimit({
- redis: Redis.fromEnv(),
- limiter: Ratelimit.slidingWindow(100, '1 m'), // 100 requests/minute
- analytics: true,
- prefix: 'api:ratelimit',
- });
-
- // Next.js middleware usage
- export async function rateLimitMiddleware(req: Request) {
- const ip = req.headers.get('x-forwarded-for') ?? '127.0.0.1';
- const { success, limit, remaining, reset } = await ratelimit.limit(ip);
-
- if (!success) {
- return new Response(JSON.stringify({ error: 'Too Many Requests' }), {
- status: 429,
- headers: {
- 'X-RateLimit-Limit': limit.toString(),
- 'X-RateLimit-Remaining': remaining.toString(),
- 'X-RateLimit-Reset': new Date(reset).toISOString(),
- 'Retry-After': Math.ceil((reset - Date.now()) / 1000).toString(),
- },
- });
- }
- }
- ```
-
- ---
-
- ### Idempotency for Mutations
-
- ```typescript
- // Client sends Idempotency-Key header for safe retries
- // POST /api/payments
- // Idempotency-Key: a0e4b2c1-unique-uuid-here
-
- async function handlePayment(req: Request) {
- const idempotencyKey = req.headers.get('idempotency-key');
- if (!idempotencyKey) return errorResponse(400, 'Idempotency-Key header required');
-
- // Check cache first
- const cached = await redis.get(`idempotency:${idempotencyKey}`);
- if (cached) return Response.json(JSON.parse(cached), { status: 200 });
-
- // Process payment
- const result = await processPayment(await req.json());
-
- // Cache result for 24 hours
- await redis.setex(`idempotency:${idempotencyKey}`, 86400, JSON.stringify(result));
- return Response.json(result, { status: 201 });
- }
- ```
-
- ---
-
- ### OpenAPI 3.1 Documentation
-
- ```yaml
- # openapi.yaml
- openapi: "3.1.0"
- info:
- title: Example API
- version: "1.0.0"
- description: "RESTful API for Example SaaS"
-
- paths:
- /api/v1/users:
- get:
- operationId: listUsers
- summary: List all users
- tags: [Users]
- security: [{ bearerAuth: [] }]
- parameters:
- - name: page
- in: query
- schema: { type: integer, minimum: 1, default: 1 }
- - name: pageSize
- in: query
- schema: { type: integer, minimum: 1, maximum: 100, default: 20 }
- responses:
- "200":
- description: Users list
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/UserListResponse"
- "401":
- $ref: "#/components/responses/Unauthorized"
-
- components:
- securitySchemes:
- bearerAuth:
- type: http
- scheme: bearer
- bearerFormat: JWT
- ```
-
- ---
-
- <a name="bahasa-indonesia"></a>
- ## Bahasa Indonesia
-
- ### Integrasi Orkestrasi
- Terhubung dan mengorkestrasi skill domain yang relevan seperti `brainstorming`, `zero-to-prod-orchestrator`, dan `session-memory-manager` untuk memastikan eksekusi yang kohesif.
-
- ### Deskripsi
- Panduan ahli untuk merancang, mendokumentasikan, dan mengembangkan API berkualitas produksi. Mencakup pemodelan resource **REST** dan semantik HTTP, desain skema **GraphQL**, **gRPC** dengan protobuf, dan **tRPC** untuk API end-to-end type-safe di TypeScript. Termasuk dokumentasi OpenAPI 3.1, strategi versioning API, rate limiting, idempotency, dan alur kerja contract-first.
-
- ### Kondisi Pemicu
- - Merancang API baru dari nol (REST, GraphQL, gRPC, atau tRPC).
- - Mengembangkan API yang ada tanpa merusak klien.
- - Mendokumentasikan API dengan OpenAPI/Swagger.
- - Mengimplementasikan rate limiting, throttling, atau idempotency.
- - Memilih antara REST, GraphQL, gRPC, dan tRPC.
- - Merancang sistem webhook.
-
- ### Panduan Pemilihan Protokol API
-
- - **REST**: API publik, klien mobile, konsumsi universal.
- - **GraphQL**: Data graph kompleks, kebutuhan query fleksibel dari klien.
- - **gRPC**: Komunikasi layanan-ke-layanan dengan performa tinggi.
- - **tRPC**: Proyek full-stack TypeScript monorepo (Next.js + backend).
-
- ### Prinsip REST
-
- 1. **Penamaan resource**: Gunakan kata benda jamak (`/posts`, bukan `/getPost`).
- 2. **Status HTTP**: Gunakan kode yang tepat (201 untuk create, 204 untuk delete).
- 3. **Konsistensi respons**: Selalu kembalikan struktur `data` + `meta` yang konsisten.
- 4. **Versioning**: Gunakan URL path (`/api/v1/`) untuk API publik.
- 5. **Idempotency**: Implementasikan `Idempotency-Key` header untuk operasi mutasi yang kritis.
- 6. **Rate Limiting**: Selalu sertakan header `X-RateLimit-*` dan kode `429` yang benar.
-
-
- ## Orchestration & Integration
+ ---
+ name: api-design-expert
+ description: "Expert guide for designing robust APIs: REST best practices, GraphQL, gRPC, tRPC, OpenAPI/Swagger, API versioning, rate limiting, and contract-first design / Panduan ahli untuk merancang API yang kuat: praktik terbaik REST, GraphQL, gRPC, tRPC, OpenAPI/Swagger, versioning API, rate limiting, dan desain contract-first."
+ author: "Roedy Rustam"
+ version: "3.0.0"
+ ---
+
+ # API Design Expert
+
+ [English](#english) | [Bahasa Indonesia](#bahasa-indonesia)
+
+ ---
+
+ <a name="english"></a>
+ ## English
+
+ ### Description
+ Expert guide for designing, documenting, and evolving production-grade APIs. Covers **REST** resource modeling and HTTP semantics, **GraphQL** schema design, **gRPC** with protobuf, and **tRPC** for end-to-end type-safe APIs in TypeScript monorepos. Includes OpenAPI 3.1 documentation, API versioning strategies, rate limiting, idempotency, and contract-first development workflows.
+
+ ### Trigger Conditions
+ - Designing a new API from scratch (REST, GraphQL, gRPC, or tRPC).
+ - Evolving an existing API without breaking clients.
+ - Documenting APIs with OpenAPI/Swagger.
+ - Implementing rate limiting, throttling, or idempotency.
+ - Choosing between REST, GraphQL, gRPC, and tRPC.
+ - Designing webhook systems.
+ - Implementing API authentication (API keys, JWT, OAuth2).
+
+ ---
+
+ ### API Protocol Selection Guide
+
+ | Criteria | REST | GraphQL | gRPC | tRPC |
+ |---|---|---|---|---|
+ | **Type Safety** | Manual (OpenAPI) | Schema-enforced | Protobuf | End-to-end TS |
+ | **Performance** | Good | Good | Excellent (HTTP/2) | Good |
+ | **Browser Support** | Native | Native | Needs proxy | TS/JS only |
+ | **Streaming** | SSE / WebSocket | Subscriptions | Native bi-directional | SSE |
+ | **Best For** | Public APIs, mobile | Complex data graphs | Microservice-to-service | Next.js full-stack |
+ | **Tooling** | Universal | Rich ecosystem | Strong (Go, Java) | Next.js / Expo |
+
+ ---
+
+ ### REST API Design Principles
+
+ #### Resource Naming Conventions
+ ```
+ Collection: GET /api/v1/posts
+ Item: GET /api/v1/posts/{id}
+ Sub-resource:GET /api/v1/posts/{id}/comments
+ Action: POST /api/v1/posts/{id}/publish (use sparingly)
+
+ AVOID: /api/v1/getPosts, /api/v1/createPost, /api/v1/deletePost/{id}
+ ```
+
+ #### HTTP Method Semantics
+ | Method | Idempotent | Safe | Use Case |
+ |---|---|---|---|
+ | `GET` | Yes | Yes | Retrieve resources |
+ | `POST` | No | No | Create resources, trigger actions |
+ | `PUT` | Yes | No | Replace entire resource |
+ | `PATCH` | No | No | Partial update |
+ | `DELETE` | Yes | No | Remove resource |
+
+ #### Consistent Response Structure
+ ```typescript
+ // Success response
+ {
+ "data": { "id": "usr_01", "email": "user@example.com" },
+ "meta": { "requestId": "req_xyz", "timestamp": "2026-01-01T00:00:00Z" }
+ }
+
+ // Paginated list response
+ {
+ "data": [...],
+ "meta": {
+ "total": 1234,
+ "page": 2,
+ "pageSize": 20,
+ "hasNextPage": true,
+ "nextCursor": "eyJpZCI6"
+ }
+ }
+
+ // Error response (RFC 9457 Problem Details)
+ {
+ "type": "https://api.example.com/errors/validation-failed",
+ "title": "Validation Failed",
+ "status": 422,
+ "detail": "The 'email' field must be a valid email address.",
+ "instance": "/api/v1/users",
+ "errors": [
+ { "field": "email", "message": "Invalid email format" }
+ ]
+ }
+ ```
+
+ #### HTTP Status Codes — Correct Usage
+ ```
+ 200 OK — Successful GET, PUT, PATCH
+ 201 Created — Successful POST (include Location header)
+ 204 No Content — Successful DELETE
+ 400 Bad Request — Invalid request body or params
+ 401 Unauthorized— Missing or invalid authentication
+ 403 Forbidden — Authenticated but not authorized
+ 404 Not Found — Resource not found
+ 409 Conflict — Duplicate key, version conflict
+ 422 Unprocessable Entity — Validation failure
+ 429 Too Many Requests — Rate limit exceeded (include Retry-After)
+ 500 Internal Server Error— Unexpected server error
+ ```
+
+ ---
+
+ ### API Versioning Strategies
+
+ ```
+ Strategy 1 — URL Path (Recommended for public APIs):
+ GET /api/v1/users
+ GET /api/v2/users
+
+ Strategy 2 — Header:
+ GET /api/users
+ Accept: application/vnd.example.v2+json
+
+ Strategy 3 — Query Parameter (Avoid in production):
+ GET /api/users?version=2
+ ```
+
+ **Rules for non-breaking changes** (no version bump needed):
+ - Adding new optional fields to responses.
+ - Adding new optional request parameters.
+ - Adding new endpoints.
+
+ **Breaking changes** (require new version):
+ - Removing or renaming fields.
+ - Changing field types.
+ - Changing error response structure.
+
+ ---
+
+ ### tRPC — End-to-End Type Safety
+
+ ```typescript
+ // server/router.ts
+ import { initTRPC, TRPCError } from '@trpc/server';
+ import { z } from 'zod';
+
+ const t = initTRPC.context<Context>().create();
+ export const router = t.router;
+ export const publicProcedure = t.procedure;
+ export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
+ if (!ctx.session?.user) throw new TRPCError({ code: 'UNAUTHORIZED' });
+ return next({ ctx: { ...ctx, user: ctx.session.user } });
+ });
+
+ export const appRouter = router({
+ users: router({
+ list: publicProcedure
+ .input(z.object({ page: z.number().int().min(1).default(1) }))
+ .query(async ({ input, ctx }) => {
+ return ctx.db.user.findMany({ skip: (input.page - 1) * 20, take: 20 });
+ }),
+ create: protectedProcedure
+ .input(z.object({ email: z.string().email(), name: z.string().min(2) }))
+ .mutation(async ({ input, ctx }) => {
+ return ctx.db.user.create({ data: input });
+ }),
+ }),
+ });
+
+ export type AppRouter = typeof appRouter;
+ // Client automatically infers all types — no code generation needed
+ ```
+
+ ---
+
+ ### Rate Limiting Implementation
+
+ ```typescript
+ // Sliding window rate limit with Redis (using Upstash)
+ import { Ratelimit } from '@upstash/ratelimit';
+ import { Redis } from '@upstash/redis';
+
+ const ratelimit = new Ratelimit({
+ redis: Redis.fromEnv(),
+ limiter: Ratelimit.slidingWindow(100, '1 m'), // 100 requests/minute
+ analytics: true,
+ prefix: 'api:ratelimit',
+ });
+
+ // Next.js middleware usage
+ export async function rateLimitMiddleware(req: Request) {
+ const ip = req.headers.get('x-forwarded-for') ?? '127.0.0.1';
+ const { success, limit, remaining, reset } = await ratelimit.limit(ip);
+
+ if (!success) {
+ return new Response(JSON.stringify({ error: 'Too Many Requests' }), {
+ status: 429,
+ headers: {
+ 'X-RateLimit-Limit': limit.toString(),
+ 'X-RateLimit-Remaining': remaining.toString(),
+ 'X-RateLimit-Reset': new Date(reset).toISOString(),
+ 'Retry-After': Math.ceil((reset - Date.now()) / 1000).toString(),
+ },
+ });
+ }
+ }
+ ```
+
+ ---
+
+ ### Idempotency for Mutations
+
+ ```typescript
+ // Client sends Idempotency-Key header for safe retries
+ // POST /api/payments
+ // Idempotency-Key: a0e4b2c1-unique-uuid-here
+
+ async function handlePayment(req: Request) {
+ const idempotencyKey = req.headers.get('idempotency-key');
+ if (!idempotencyKey) return errorResponse(400, 'Idempotency-Key header required');
+
+ // Check cache first
+ const cached = await redis.get(`idempotency:${idempotencyKey}`);
+ if (cached) return Response.json(JSON.parse(cached), { status: 200 });
+
+ // Process payment
+ const result = await processPayment(await req.json());
+
+ // Cache result for 24 hours
+ await redis.setex(`idempotency:${idempotencyKey}`, 86400, JSON.stringify(result));
+ return Response.json(result, { status: 201 });
+ }
+ ```
+
+ ---
+
+ ### OpenAPI 3.1 Documentation
+
+ ```yaml
+ # openapi.yaml
+ openapi: "3.1.0"
+ info:
+ title: Example API
+ version: "1.0.0"
+ description: "RESTful API for Example SaaS"
+
+ paths:
+ /api/v1/users:
+ get:
+ operationId: listUsers
+ summary: List all users
+ tags: [Users]
+ security: [{ bearerAuth: [] }]
+ parameters:
+ - name: page
+ in: query
+ schema: { type: integer, minimum: 1, default: 1 }
+ - name: pageSize
+ in: query
+ schema: { type: integer, minimum: 1, maximum: 100, default: 20 }
+ responses:
+ "200":
+ description: Users list
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/UserListResponse"
+ "401":
+ $ref: "#/components/responses/Unauthorized"
+
+ components:
+ securitySchemes:
+ bearerAuth:
+ type: http
+ scheme: bearer
+ bearerFormat: JWT
+ ```
+
+ ---
+
+ <a name="bahasa-indonesia"></a>
+ ## Bahasa Indonesia
+
+ ### Integrasi Orkestrasi
+ Terhubung dan mengorkestrasi skill domain yang relevan seperti `brainstorming`, `zero-to-prod-orchestrator`, dan `session-memory-manager` untuk memastikan eksekusi yang kohesif.
+
+ ### Deskripsi
+ Panduan ahli untuk merancang, mendokumentasikan, dan mengembangkan API berkualitas produksi. Mencakup pemodelan resource **REST** dan semantik HTTP, desain skema **GraphQL**, **gRPC** dengan protobuf, dan **tRPC** untuk API end-to-end type-safe di TypeScript. Termasuk dokumentasi OpenAPI 3.1, strategi versioning API, rate limiting, idempotency, dan alur kerja contract-first.
+
+ ### Kondisi Pemicu
+ - Merancang API baru dari nol (REST, GraphQL, gRPC, atau tRPC).
+ - Mengembangkan API yang ada tanpa merusak klien.
+ - Mendokumentasikan API dengan OpenAPI/Swagger.
+ - Mengimplementasikan rate limiting, throttling, atau idempotency.
+ - Memilih antara REST, GraphQL, gRPC, dan tRPC.
+ - Merancang sistem webhook.
+
+ ### Panduan Pemilihan Protokol API
+
+ - **REST**: API publik, klien mobile, konsumsi universal.
+ - **GraphQL**: Data graph kompleks, kebutuhan query fleksibel dari klien.
+ - **gRPC**: Komunikasi layanan-ke-layanan dengan performa tinggi.
+ - **tRPC**: Proyek full-stack TypeScript monorepo (Next.js + backend).
+
+ ### Prinsip REST
+
+ 1. **Penamaan resource**: Gunakan kata benda jamak (`/posts`, bukan `/getPost`).
+ 2. **Status HTTP**: Gunakan kode yang tepat (201 untuk create, 204 untuk delete).
+ 3. **Konsistensi respons**: Selalu kembalikan struktur `data` + `meta` yang konsisten.
+ 4. **Versioning**: Gunakan URL path (`/api/v1/`) untuk API publik.
+ 5. **Idempotency**: Implementasikan `Idempotency-Key` header untuk operasi mutasi yang kritis.
+ 6. **Rate Limiting**: Selalu sertakan header `X-RateLimit-*` dan kode `429` yang benar.
+
+
+ ## Orchestration & Integration
- Connects to other backend skills as part of the orchestration flow.
-