API Design Reviewer
Comprehensive API design analysis for REST conventions, consistency, and industry standards.
REST Design Principles
Resource Naming
✅ Good: ❌ Bad:
/api/v1/users /api/v1/getUsers
/api/v1/user-profiles /api/v1/user_profiles
/api/v1/orders/123/line-items /api/v1/orders/123/lineItems
Rules: Plural nouns for collections. Kebab-case for multi-word resources. CamelCase for JSON fields. Use HTTP methods instead of verbs in URLs.
HTTP Methods
| Method |
Purpose |
Idempotent |
Safe |
| GET |
Retrieve resources |
Yes |
Yes |
| POST |
Create new resources |
No |
No |
| PUT |
Replace entire resource |
Yes |
No |
| PATCH |
Partial update |
No |
No |
| DELETE |
Remove resource |
Yes |
No |
URL Structure
Collection: /api/v1/users
Individual: /api/v1/users/123
Nested: /api/v1/users/123/orders
Action: /api/v1/users/123/activate (POST)
Filtering: /api/v1/users?status=active&role=admin
Pagination Patterns
Cursor-Based (Recommended)
{
"data": [...],
"pagination": {
"nextCursor": "eyJpZCI6MTIzfQ==",
"hasMore": true
}
}
Implementation tip: fetch LIMIT + 1 rows to determine hasMore without a separate count query.
Offset-Based
{
"data": [...],
"pagination": { "offset": 20, "limit": 10, "total": 150, "hasMore": true }
}
When to Use Which
| Use Case |
Pagination Type |
Why |
| Admin dashboards, small datasets (<10K) |
Offset |
Users expect page numbers |
| Infinite scroll, feeds, large datasets |
Cursor |
Consistent performance at any depth |
| Public APIs |
Cursor (default), offset (optional) |
Scalable by default |
| Search results |
Offset |
Users expect "page N of M" |
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"
}
}
Status Code Usage
| Code |
Meaning |
| 200 |
Success (GET, PUT, PATCH) |
| 201 |
Created (POST) |
| 204 |
No Content (DELETE) |
| 400 |
Validation error |
| 401 |
Authentication required |
| 403 |
Permission denied |
| 404 |
Resource not found |
| 409 |
Conflict (duplicate, version mismatch) |
| 422 |
Semantic errors (valid syntax, bad logic) |
| 429 |
Rate limit exceeded |
| 500 |
Internal server error |
Versioning Strategies
| Strategy |
Example |
Pros |
Cons |
| URL (recommended) |
/api/v1/users |
Clear, easy to route |
URL proliferation |
| Header |
Accept: application/vnd.api+json;version=1 |
Clean URLs |
Less visible |
| Query parameter |
/api/users?version=1 |
Simple |
Not RESTful |
Versioning Lifecycle
1. Start with /api/v1/ — version only when breaking changes arise
2. Maintain at most 2 active versions (current + previous)
3. Deprecation timeline (public APIs):
- Announce deprecation with 6 months notice
- Add Sunset header: Sunset: Sat, 01 Jan 2026 00:00:00 GMT
- Return 410 Gone after sunset date
Breaking vs Non-Breaking Changes
Safe (Non-Breaking)
- Adding optional request fields
- Adding response fields
- Adding new endpoints
- Making required fields optional
Breaking (Require Version Bump)
- Removing response fields
- Making optional fields required
- Changing field types
- Removing or renaming endpoints
- Changing URL structure
Rate Limiting
Response Headers
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1640995200
429 Response
{ "error": { "code": "RATE_LIMIT_EXCEEDED", "message": "Too many requests", "retryAfter": 3600 } }
Rate Limit Tiers
| Tier |
Limit |
Window |
Use Case |
| Anonymous |
30/min |
Per IP |
Public endpoints |
| Authenticated |
100/min |
Per user |
Standard API access |
| Premium |
1000/min |
Per API key |
Paid API plans |
| Internal |
10000/min |
Per service |
Service-to-service |
Filtering, Sorting, and Search
# Equality filters
GET /api/v1/orders?status=active&customer_id=abc-123
# Comparison operators (bracket notation)
GET /api/v1/products?price[gte]=10&price[lte]=100
# Multiple values (comma-separated)
GET /api/v1/products?category=electronics,clothing
# Sorting (prefix - for descending, comma for multi-field)
GET /api/v1/products?sort=-created_at,price
# Full-text search
GET /api/v1/products?q=wireless+headphones
# Sparse fieldsets (reduce payload)
GET /api/v1/users?fields=id,name,email
Authentication Patterns
| Pattern |
Header |
Use Case |
| Bearer Token |
Authorization: Bearer <token> |
JWT, OAuth 2.0 |
| API Key |
X-API-Key: <key> |
Service-to-service |
| Basic Auth |
Authorization: Basic <base64> |
Simple auth (with HTTPS) |
Idempotency
For non-idempotent operations (POST), use idempotency keys:
POST /api/v1/payments
Idempotency-Key: 123e4567-e89b-12d3-a456-426614174000
Review Checklist
Anti-Patterns
| Anti-Pattern |
Fix |
Verb-based URLs (/getUsers) |
Use nouns + HTTP methods |
| Inconsistent response shapes |
Standardize envelope format |
Deep nesting (/a/1/b/2/c/3/d) |
Limit to 2 levels; use query params |
| Ignoring status codes |
Use specific codes per error type |
| Missing pagination |
Always paginate lists |
| No versioning |
Plan for API evolution from day one |
| Exposing internal structure |
Design for external consumption |