--- name: api-design description: REST API design patterns — resource naming, pagination (cursor/offset), error response format, versioning, idempotency, HATEOAS. Use when designing new APIs, reviewing existing ones, or standardizing API conventions. --- # API Design Patterns Based on ECC api-design skill. ## RESTful Resource Naming ### Good ``` GET /users # List users POST /users # Create user GET /users/:id # Get user PUT /users/:id # Replace user PATCH /users/:id # Update user (partial) DELETE /users/:id # Delete user GET /users/:id/posts # User's posts POST /users/:id/posts # Create post for user GET /users/:id/posts/:postId # Specific post by user ``` ### Bad ``` GET /getUser # Action-based (wrong) POST /createUser # Verb-based (wrong) GET /posts?userId=123 # Flat when nested makes sense ``` ### Rules - **Nouns for resources**, verbs for HTTP methods - **Plural nouns** for collections: `/users`, not `/user` - **Nested resources** for parent-child: `/users/:id/posts` - **Hyphens** for multi-word resource names: `/blog-posts`, not `/blogPosts` - **Lowercase** only, no trailing slashes ## HTTP Status Codes | Code | When to Use | |------|------------| | 200 | Successful GET, PUT, PATCH | | 201 | Successful POST (created) — include Location header | | 204 | Successful DELETE — no response body | | 400 | Invalid request format, missing required fields | | 401 | Authentication required or failed | | 403 | Authenticated but not authorized | | 404 | Resource not found | | 409 | Conflict (duplicate, version mismatch) | | 422 | Valid JSON but business rule violation | | 429 | Rate limit exceeded | | 500 | Unexpected server error — always log the real cause | ## Error Response Format ```json { "error": { "code": "VALIDATION_ERROR", "message": "Invalid request parameters", "details": [ { "field": "email", "message": "Must be a valid email address" } ], "request_id": "req_abc123" } } ``` ### Error codes to use consistently - `VALIDATION_ERROR` — input validation failed - `NOT_FOUND` — resource doesn't exist - `UNAUTHORIZED` — auth missing or expired - `FORBIDDEN` — lacks permission - `RATE_LIMITED` — too many requests - `CONFLICT` — duplicate or version mismatch - `INTERNAL_ERROR` — unexpected server failure ## Pagination ### Cursor-based (RECOMMENDED for large datasets) ```json { "data": [...], "pagination": { "next_cursor": "eyJpZCI6MTAwfQ==", "has_more": true, "limit": 20 } } ``` ### Offset-based (acceptable for small datasets) ```json { "data": [...], "pagination": { "total": 500, "page": 2, "per_page": 20, "total_pages": 25 } } ``` ## API Versioning ### URL path versioning (simplest) ``` /api/v1/users /api/v2/users ``` ### Header versioning (cleaner) ``` Accept: application/vnd.api+json; version=1 ``` ## Idempotency - **GET, PUT, DELETE** are naturally idempotent - **POST** needs idempotency for safety: - Accept `Idempotency-Key` header - Store hash of request + result - Return cached result if same key received again ## Rate Limiting ``` X-RateLimit-Limit: 1000 X-RateLimit-Remaining: 999 X-RateLimit-Reset: 1625097600 ``` ## Checklist - [ ] Resources use plural nouns - [ ] HTTP methods match CRUD operations - [ ] Consistent error response format - [ ] Pagination on all list endpoints - [ ] Rate limiting on public endpoints - [ ] Authentication on protected endpoints - [ ] API documentation (OpenAPI/Swagger) - [ ] Backward compatibility for version changes