| name | api-design |
| description | Design APIs that developers love to use. |
| tier | standard |
| applyTo | **/*api*,**/*rest*,**/*endpoint*,**/*route*,**/*schema* |
API Design Skill
Design APIs that developers love to use.
Core Principle
A good API is intuitive, consistent, and hard to misuse. Design for the consumer, not the implementation.
REST Fundamentals
Resource Naming
| Good | Bad | Why |
|---|
/users | /getUsers | Nouns, not verbs |
/users/123 | /user?id=123 | Path params for identity |
/users/123/orders | /getUserOrders | Hierarchical resources |
/search?q=term | /search/term | Query params for filters |
HTTP Methods
| Method | Purpose | Idempotent | Safe |
|---|
| GET | Read resource | Yes | Yes |
| POST | Create resource | No | No |
| PUT | Replace resource | Yes | No |
| PATCH | Partial update | No* | No |
| DELETE | Remove resource | Yes | No |
Status Codes
| Code | Meaning | When to Use |
|---|
| 200 | OK | Successful GET, PUT, PATCH |
| 201 | Created | Successful POST |
| 204 | No Content | Successful DELETE |
| 400 | Bad Request | Validation error |
| 401 | Unauthorized | Missing authentication |
| 403 | Forbidden | Authenticated but not allowed |
| 404 | Not Found | Resource doesn't exist |
| 409 | Conflict | State conflict (duplicate) |
| 429 | Too Many Requests | Rate limited |
| 500 | Internal Error | Server bug |
Contract-First Design
- Define the contract (OpenAPI/Swagger)
- Review with consumers before coding
- Generate server stubs from contract
- Implement business logic
- Validate responses against contract
openapi: 3.0.3
info:
title: My API
version: 1.0.0
paths:
/users:
get:
summary: List users
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/UserList'
Versioning
| Strategy | Example | Recommendation |
|---|
| URL Path | /v1/users | Preferred - explicit |
| Header | Accept: vnd.api.v1+json | Clean but hidden |
| Query | /users?version=1 | Avoid |
Pagination Patterns
Offset-Based
GET /users?offset=40&limit=20
{ "data": [...], "pagination": { "total": 150 } }
Cursor-Based (Preferred for large datasets)
GET /users?cursor=abc123&limit=20
{ "data": [...], "next_cursor": "def456" }
Error Response Design
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request parameters",
"details": [{ "field": "email", "message": "Invalid format" }],
"request_id": "req_abc123"
}
}
Principles:
- Machine-readable code
- Human-readable message
- Request ID for correlation
- Never expose stack traces
Caching
HTTP Cache Headers
| Header | Purpose |
|---|
Cache-Control | Caching directives |
ETag | Content fingerprint |
Vary | Cache key factors |
Cache-Control: public, max-age=3600
Cache-Control: private, max-age=300
Cache-Control: no-store
ETag Flow
GET /users/123
-> 200 OK, ETag: "v1-abc123"
GET /users/123, If-None-Match: "v1-abc123"
-> 304 Not Modified (or 200 with new ETag)
Rate Limiting
Algorithms
| Algorithm | Description |
|---|
| Fixed Window | X requests per minute |
| Token Bucket | Burst-friendly with refill |
| Sliding Window | Rolling time window |
Response Headers
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1706792400
# When exceeded
429 Too Many Requests
Retry-After: 30
Rate Limit Tiers
| Tier | Limit | Use Case |
|---|
| Anonymous | 60/hour | Public exploration |
| Authenticated | 1000/hour | Normal usage |
| Premium | 10000/hour | Power users |
Request/Response Design
- Use camelCase or snake_case consistently
- Timestamps in ISO 8601:
2026-02-01T14:30:00Z
- IDs as strings (future-proof for UUIDs)
- Envelope responses:
{ "data": ..., "meta": ... }
Partial Responses
GET /users/123?fields=id,name,email
Security Checklist
Documentation Requirements
- Authentication: How to get and use tokens
- Quick Start: Working example in < 5 minutes
- Reference: Every endpoint, parameter, response
- Errors: All error codes and recovery steps
- Changelog: What changed in each version
API Review Checklist
Anti-Patterns
- Verbs in URLs (
/getUser)
- Exposing internal IDs (auto-increment)
- Inconsistent naming conventions
- No versioning strategy
- Missing rate limits
- Exposing stack traces in errors
- Breaking changes without version bump