| name | api-design |
| description | REST API design best practices for consistent, intuitive APIs |
API Design Principles
Design APIs that are intuitive, consistent, and a joy to use.
URL Structure
Resources as Nouns
# GOOD - nouns
GET /users
GET /users/123
GET /users/123/orders
# BAD - verbs
GET /getUsers
GET /fetchUserById/123
POST /createNewUser
Plural Resource Names
# GOOD - plural
GET /users
GET /orders
GET /products
# BAD - singular
GET /user
GET /order
Hierarchical Relationships
# Parent-child relationships
GET /users/123/orders # Orders for user 123
GET /orders/456/items # Items in order 456
# Avoid deep nesting (max 2 levels)
# BAD
GET /users/123/orders/456/items/789/reviews
# GOOD - flatten when needed
GET /order-items/789/reviews
HTTP Methods
| Method | Usage | Idempotent | Safe |
|---|---|---|---|
| GET | Read resource | Yes | Yes |
| POST | Create resource | No | No |
| PUT | Replace resource | Yes | No |
| PATCH | Partial update | Yes | No |
| DELETE | Remove resource | Yes | No |
GET /users # List users
POST /users # Create user
GET /users/123 # Get user 123
PUT /users/123 # Replace user 123
PATCH /users/123 # Update user 123
DELETE /users/123 # Delete user 123
Request/Response Format
Consistent JSON Structure
// Success response
{
"data": {
"id": "123",
"name": "John Doe",
"email": "john@example.com"
}
}
// Collection response
{
"data": [
{ "id": "123", "name": "John" },
{ "id": "456", "name": "Jane" }
],
"meta": {
"total": 100,
"page": 1,
"perPage": 20
}
}
// Error response
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid email format",
"details": [
{ "field": "email", "message": "Must be a valid email" }
]
}
}
Use camelCase
// GOOD
{
"firstName": "John",
"lastName": "Doe",
"emailAddress": "john@example.com"
}
// BAD - inconsistent
{
"first_name": "John",
"LastName": "Doe",
"email-address": "john@example.com"
}
Status Codes
Success (2xx)
200 OK - GET, PUT, PATCH success
201 Created - POST success (include Location header)
204 No Content - DELETE success
Client Errors (4xx)
400 Bad Request - Invalid syntax, validation error
401 Unauthorized - No/invalid authentication
403 Forbidden - Authenticated but not allowed
404 Not Found - Resource doesn't exist
409 Conflict - State conflict (duplicate, version)
422 Unprocessable - Valid syntax but semantic error
429 Too Many Requests - Rate limited
Server Errors (5xx)
500 Internal Server Error - Unexpected error
502 Bad Gateway - Upstream service failed
503 Service Unavailable - Temporarily unavailable
504 Gateway Timeout - Upstream timeout
Pagination
Offset-based (simple)
GET /users?page=2&perPage=20
Response:
{
"data": [...],
"meta": {
"total": 100,
"page": 2,
"perPage": 20,
"totalPages": 5
},
"links": {
"first": "/users?page=1&perPage=20",
"prev": "/users?page=1&perPage=20",
"next": "/users?page=3&perPage=20",
"last": "/users?page=5&perPage=20"
}
}
Cursor-based (scalable)
GET /users?cursor=eyJpZCI6MTIzfQ&limit=20
Response:
{
"data": [...],
"meta": {
"hasMore": true,
"nextCursor": "eyJpZCI6MTQzfQ"
}
}
Filtering & Sorting
Filtering
GET /users?status=active
GET /users?role=admin&status=active
GET /users?createdAt[gte]=2024-01-01
GET /users?name[contains]=john
Sorting
GET /users?sort=name # Ascending
GET /users?sort=-createdAt # Descending (prefix -)
GET /users?sort=lastName,firstName
Field Selection
GET /users?fields=id,name,email
GET /users/123?fields=id,name,email
Versioning
URL Path (recommended)
GET /v1/users
GET /v2/users
Header
GET /users
Accept: application/vnd.api+json;version=2
Authentication
Bearer Token
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
API Key
X-API-Key: sk_live_abc123
# Or in query (less secure)
GET /users?api_key=sk_live_abc123
Rate Limiting
Include headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1640995200
Retry-After: 60
Documentation
Every endpoint needs:
- Description of what it does
- Request parameters with types
- Request body schema
- Response schema for each status code
- Example request/response
- Error cases
# OpenAPI example
/users:
post:
summary: Create a new user
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUser'
responses:
'201':
description: User created
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'400':
description: Validation error
Common Mistakes
| Mistake | Problem | Fix |
|---|---|---|
| Verbs in URLs | /getUser |
Use /users/:id |
| Inconsistent naming | Mix of cases | Pick one (camelCase) |
| Wrong status codes | 200 for errors | Use 4xx/5xx appropriately |
| No pagination | Memory issues | Always paginate collections |
| Breaking changes | Clients break | Version your API |
| No rate limiting | Abuse | Implement limits |
| Exposing internals | Security risk | Transform responses |
Checklist
- URLs use nouns, not verbs
- HTTP methods used correctly
- Consistent response format
- Appropriate status codes
- Pagination for collections
- Filtering and sorting support
- Rate limiting implemented
- Authentication documented
- Errors are descriptive
- API is versioned