REST APIs power the modern web, but most APIs are designed with subtle flaws that cause pain months later. This guide covers the conventions, patterns, and anti-patterns that separate production APIs from weekend projects.
1. Use Nouns, Not Verbs, for Resources
# Good
GET /users
GET /users/42
POST /users
PUT /users/42
DELETE /users/42
# Bad
GET /getUsers
POST /createUser
GET /users/42/getProfile
2. Version Your API from Day One
Use URL prefix versioning (/v1/users) or header-based versioning (Accept: application/vnd.api.v2+json). URL versioning is simpler for public APIs. Choose one and stick with it everywhere โ mixing strategies is worse than either alone.
3. Consistent Naming Conventions
// JSON: camelCase for properties
{{"userId": 42, "createdAt": "2026-05-07"}}
// URL paths: kebab-case
GET /user-orders/42
// Query parameters: snake_case
GET /users?sort_by=name&page_size=20
4. Use Proper HTTP Status Codes
| Code | When to Use |
|---|---|
| 200 OK | Successful GET, PUT, PATCH |
| 201 Created | Successful POST โ always include Location header |
| 204 No Content | Successful DELETE (no body returned) |
| 400 Bad Request | Malformed input, validation failure |
| 401 Unauthorized | Missing or expired auth token |
| 403 Forbidden | Authenticated but not permitted |
| 404 Not Found | Resource doesn't exist |
| 409 Conflict | Duplicate or state conflict |
| 422 Unprocessable | Valid syntax but semantic error |
| 429 Too Many | Rate limit exceeded โ include Retry-After header |
| 500 Internal Error | Unexpected server failure (never expose stack traces) |
5. Error Response Format
Always return errors in a consistent structure:
{{
"error": {{
"code": "VALIDATION_ERROR",
"message": "Email is required",
"details": [
{{"field": "email", "reason": "must not be empty"}},
{{"field": "age", "reason": "must be positive"}}
],
"requestId": "req_abc123"
}}
}}
6. Pagination, Filtering, and Sorting
# Pagination with cursor (preferred for large datasets)
GET /users?cursor=eyJpZCI6NDJ9&limit=20
Response: {{"data": [...], "nextCursor": "eyJpZCI6NjJ9", "hasMore": true}}
# Or offset-based for simpler use cases
GET /users?offset=0&limit=20
# Filtering
GET /users?status=active&role=admin
# Sorting
GET /users?sort=-createdAt # descending
GET /users?sort=+name # ascending
7. Security Checklist
- Always use HTTPS. No exceptions.
- Set rate limits. At minimum: 60 req/min per IP for unauthenticated, 1000 req/min per user for authenticated.
- Validate Content-Type. Reject requests with wrong Content-Type headers.
- Set CORS explicitly. Never use
Access-Control-Allow-Origin: *with credentials. - Use API keys or OAuth2. Never roll your own auth protocol.
- Keep secrets out of responses. Password hashes, internal IDs, stack traces, server versions.
8. API Documentation
Use OpenAPI 3.1 (Swagger). It's the industry standard and generates interactive docs automatically. Tools like Stoplight, Redoc, and Swagger UI render beautiful docs from a single spec file. If your API doesn't have an OpenAPI spec, it's not ready for production.