10 KiB
10 KiB
REST API Design Rules Reference
Core Principles
1. Resources, Not Actions
REST APIs should focus on resources (nouns) rather than actions (verbs). The HTTP methods provide the actions.
✅ Good:
GET /users # Get all users
GET /users/123 # Get user 123
POST /users # Create new user
PUT /users/123 # Update user 123
DELETE /users/123 # Delete user 123
❌ Bad:
POST /getUsers
POST /createUser
POST /updateUser/123
POST /deleteUser/123
2. Hierarchical Resource Structure
Use hierarchical URLs to represent resource relationships:
/users/123/orders/456/items/789
But avoid excessive nesting (max 3-4 levels):
❌ Too deep: /companies/123/departments/456/teams/789/members/012/tasks/345
✅ Better: /tasks/345?member=012&team=789
Resource Naming Conventions
URLs Should Use Kebab-Case
✅ Good:
/user-profiles
/order-items
/shipping-addresses
❌ Bad:
/userProfiles
/user_profiles
/orderItems
Collections vs Individual Resources
Collection: /users
Individual: /users/123
Sub-resource: /users/123/orders
Pluralization Rules
- Use plural nouns for collections:
/users,/orders - Use singular nouns for single resources:
/user-profile,/current-session - Be consistent throughout your API
HTTP Methods Usage
GET - Safe and Idempotent
- Purpose: Retrieve data
- Safe: No side effects
- Idempotent: Multiple calls return same result
- Request Body: Should not have one
- Cacheable: Yes
GET /users/123
GET /users?status=active&limit=10
POST - Not Idempotent
- Purpose: Create resources, non-idempotent operations
- Safe: No
- Idempotent: No
- Request Body: Usually required
- Cacheable: Generally no
POST /users # Create new user
POST /users/123/activate # Activate user (action)
PUT - Idempotent
- Purpose: Create or completely replace a resource
- Safe: No
- Idempotent: Yes
- Request Body: Required (complete resource)
- Cacheable: No
PUT /users/123 # Replace entire user resource
PATCH - Partial Update
- Purpose: Partially update a resource
- Safe: No
- Idempotent: Not necessarily
- Request Body: Required (partial resource)
- Cacheable: No
PATCH /users/123 # Update only specified fields
DELETE - Idempotent
- Purpose: Remove a resource
- Safe: No
- Idempotent: Yes (same result if called multiple times)
- Request Body: Usually not needed
- Cacheable: No
DELETE /users/123
Status Codes
Success Codes (2xx)
- 200 OK: Standard success response
- 201 Created: Resource created successfully (POST)
- 202 Accepted: Request accepted for processing (async)
- 204 No Content: Success with no response body (DELETE, PUT)
Redirection Codes (3xx)
- 301 Moved Permanently: Resource permanently moved
- 302 Found: Temporary redirect
- 304 Not Modified: Use cached version
Client Error Codes (4xx)
- 400 Bad Request: Invalid request syntax or data
- 401 Unauthorized: Authentication required
- 403 Forbidden: Access denied (user authenticated but not authorized)
- 404 Not Found: Resource not found
- 405 Method Not Allowed: HTTP method not supported
- 409 Conflict: Resource conflict (duplicates, version mismatch)
- 422 Unprocessable Entity: Valid syntax but semantic errors
- 429 Too Many Requests: Rate limit exceeded
Server Error Codes (5xx)
- 500 Internal Server Error: Unexpected server error
- 502 Bad Gateway: Invalid response from upstream server
- 503 Service Unavailable: Server temporarily unavailable
- 504 Gateway Timeout: Upstream server timeout
URL Design Patterns
Query Parameters for Filtering
GET /users?status=active
GET /users?role=admin&department=engineering
GET /orders?created_after=2024-01-01&status=pending
Pagination Parameters
# Offset-based
GET /users?offset=20&limit=10
# Cursor-based
GET /users?cursor=eyJpZCI6MTIzfQ&limit=10
# Page-based
GET /users?page=3&page_size=10
Sorting Parameters
GET /users?sort=created_at # Ascending
GET /users?sort=-created_at # Descending (prefix with -)
GET /users?sort=last_name,first_name # Multiple fields
Field Selection
GET /users?fields=id,name,email
GET /users/123?include=orders,profile
GET /users/123?exclude=internal_notes
Search Parameters
GET /users?q=john
GET /products?search=laptop&category=electronics
Response Format Standards
Consistent Response Structure
{
"data": {
"id": 123,
"name": "John Doe",
"email": "john@example.com"
},
"meta": {
"timestamp": "2024-02-16T13:00:00Z",
"version": "1.0"
}
}
Collection Responses
{
"data": [
{"id": 1, "name": "Item 1"},
{"id": 2, "name": "Item 2"}
],
"pagination": {
"total": 150,
"page": 1,
"pageSize": 10,
"totalPages": 15,
"hasNext": true,
"hasPrev": false
},
"meta": {
"timestamp": "2024-02-16T13:00:00Z"
}
}
Error Response Format
{
"error": {
"code": "VALIDATION_ERROR",
"message": "The request contains invalid parameters",
"details": [
{
"field": "email",
"code": "INVALID_FORMAT",
"message": "Email address is not valid"
}
],
"requestId": "req-123456",
"timestamp": "2024-02-16T13:00:00Z"
}
}
Field Naming Conventions
Use camelCase for JSON Fields
✅ Good:
{
"firstName": "John",
"lastName": "Doe",
"createdAt": "2024-02-16T13:00:00Z",
"isActive": true
}
❌ Bad:
{
"first_name": "John",
"LastName": "Doe",
"created-at": "2024-02-16T13:00:00Z"
}
Boolean Fields
Use positive, clear names with "is", "has", "can", or "should" prefixes:
✅ Good:
{
"isActive": true,
"hasPermission": false,
"canEdit": true,
"shouldNotify": false
}
❌ Bad:
{
"active": true,
"disabled": false, // Double negative
"permission": false // Unclear meaning
}
Date/Time Fields
- Use ISO 8601 format:
2024-02-16T13:00:00Z - Include timezone information
- Use consistent field naming:
{
"createdAt": "2024-02-16T13:00:00Z",
"updatedAt": "2024-02-16T13:30:00Z",
"deletedAt": null,
"publishedAt": "2024-02-16T14:00:00Z"
}
Content Negotiation
Accept Headers
Accept: application/json
Accept: application/xml
Accept: application/json; version=1
Content-Type Headers
Content-Type: application/json
Content-Type: application/json; charset=utf-8
Content-Type: multipart/form-data
Versioning via Headers
Accept: application/vnd.myapi.v1+json
API-Version: 1.0
Caching Guidelines
Cache-Control Headers
Cache-Control: public, max-age=3600 # Cache for 1 hour
Cache-Control: private, max-age=0 # Don't cache
Cache-Control: no-cache, must-revalidate # Always validate
ETags for Conditional Requests
HTTP/1.1 200 OK
ETag: "123456789"
Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT
# Client subsequent request:
If-None-Match: "123456789"
If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT
Security Headers
Authentication
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Authorization: Basic dXNlcjpwYXNzd29yZA==
Authorization: Api-Key abc123def456
CORS Headers
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Rate Limiting
Rate Limit Headers
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1640995200
X-RateLimit-Window: 3600
Rate Limit Exceeded Response
HTTP/1.1 429 Too Many Requests
Retry-After: 3600
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "API rate limit exceeded",
"details": {
"limit": 1000,
"window": "1 hour",
"retryAfter": 3600
}
}
}
Hypermedia (HATEOAS)
Links in Responses
{
"id": 123,
"name": "John Doe",
"email": "john@example.com",
"_links": {
"self": {
"href": "/users/123"
},
"orders": {
"href": "/users/123/orders"
},
"edit": {
"href": "/users/123",
"method": "PUT"
},
"delete": {
"href": "/users/123",
"method": "DELETE"
}
}
}
Link Relations
- self: Link to the resource itself
- edit: Link to edit the resource
- delete: Link to delete the resource
- related: Link to related resources
- next/prev: Pagination links
Common Anti-Patterns to Avoid
1. Verbs in URLs
❌ Bad: /api/getUser/123
✅ Good: GET /api/users/123
2. Inconsistent Naming
❌ Bad: /user-profiles and /userAddresses
✅ Good: /user-profiles and /user-addresses
3. Deep Nesting
❌ Bad: /companies/123/departments/456/teams/789/members/012
✅ Good: /team-members/012?team=789
4. Ignoring HTTP Status Codes
❌ Bad: Always return 200 with error info in body
✅ Good: Use appropriate status codes (404, 400, 500, etc.)
5. Exposing Internal Structure
❌ Bad: /api/database_table_users
✅ Good: /api/users
6. No Versioning Strategy
❌ Bad: Breaking changes without version management
✅ Good: /api/v1/users or Accept: application/vnd.api+json;version=1
7. Inconsistent Error Responses
❌ Bad: Different error formats for different endpoints
✅ Good: Standardized error response structure
Best Practices Summary
- Use nouns for resources, not verbs
- Leverage HTTP methods correctly
- Maintain consistent naming conventions
- Implement proper error handling
- Use appropriate HTTP status codes
- Design for cacheability
- Implement security from the start
- Plan for versioning
- Provide comprehensive documentation
- Follow HATEOAS principles when applicable