REST API Design Best Practices
Designing a good API is crucial for building maintainable and scalable applications. A well-designed API makes life easier for developers and provides a better experience for users. Let's explore best practices for REST API design.
Use Proper HTTP Methods
Each HTTP method has a specific purpose:
GET - Retrieve resources (safe and idempotent)
POST - Create new resources
PUT - Update entire resources (idempotent)
PATCH - Partial updates
DELETE - Remove resources (idempotent)Example endpoints:
GET /api/users - Get all users
GET /api/users/123 - Get user with ID 123
POST /api/users - Create a new user
PUT /api/users/123 - Update user 123 completely
PATCH /api/users/123 - Partially update user 123
DELETE /api/users/123 - Delete user 123Use Nouns, Not Verbs
URLs should represent resources (nouns), not actions (verbs):
❌ Bad:
/api/getUsers
/api/createUser
/api/deleteUser
✅ Good:
GET /api/users
POST /api/users
DELETE /api/users/123Use Plural Nouns
Be consistent with plural resource names:
✅ Good:
/api/users
/api/posts
/api/comments
❌ Bad (mixing):
/api/user
/api/posts
/api/commentNested Resources for Relationships
Show relationships through URL structure:
GET /api/users/123/posts - Get all posts by user 123
GET /api/users/123/posts/456 - Get post 456 by user 123
GET /api/posts/456/comments - Get all comments on post 456But avoid going too deep (max 2-3 levels):
❌ Too nested:
/api/users/123/posts/456/comments/789/repliesUse HTTP Status Codes Correctly
Return appropriate status codes:
200 OK - Successful GET, PUT, PATCH
201 Created - Successful POST
204 No Content - Successful DELETE
400 Bad Request - Invalid request data
401 Unauthorized - Authentication required
403 Forbidden - Authenticated but not authorized
404 Not Found - Resource doesn't exist
422 Unprocessable - Validation errors
500 Internal Error - Server errorConsistent Error Responses
Return errors in a consistent format:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid input data",
"details": [
{
"field": "email",
"message": "Email is required"
},
{
"field": "age",
"message": "Age must be at least 18"
}
]
}
}Filtering, Sorting, and Pagination
Support query parameters for data manipulation:
// Filtering
GET /api/users?role=admin&status=active
// Sorting
GET /api/users?sort=createdAt&order=desc
// Pagination
GET /api/users?page=2&limit=20
// Combining
GET /api/users?role=admin&sort=name&page=1&limit=10Response format for paginated data:
{
"data": [...],
"pagination": {
"page": 1,
"limit": 10,
"total": 100,
"totalPages": 10
}
}Versioning
Version your API to allow for changes without breaking existing clients:
Option 1 - URL versioning (most common):
/api/v1/users
/api/v2/users
Option 2 - Header versioning:
Accept: application/vnd.myapi.v1+json
Option 3 - Query parameter:
/api/users?version=1API Documentation
Document your API thoroughly. Use tools like:
- Swagger/OpenAPI: Interactive API documentation
- Postman Collections: Shareable API collections
- README files: Quick start guides
Example OpenAPI snippet:
paths:
/users:
get:
summary: Get all users
parameters:
- name: page
in: query
schema:
type: integer
responses:
'200':
description: Successful response
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/User'Rate Limiting
Implement rate limiting to prevent abuse:
X-RateLimit-Limit: 100 - Requests allowed per time window
X-RateLimit-Remaining: 75 - Remaining requests
X-RateLimit-Reset: 1633024800 - Reset timestampReturn 429 Too Many Requests when limit is exceeded.
Security Best Practices
- Use HTTPS: Always encrypt data in transit
- Authentication: Use JWT, OAuth 2.0, or API keys
- Authorization: Implement proper access control
- Input Validation: Validate and sanitize all inputs
- CORS: Configure Cross-Origin Resource Sharing properly
// Example: JWT authentication middleware
const authenticate = (req, res, next) => {
const token = req.headers.authorization?.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'No token provided' });
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (error) {
return res.status(401).json({ error: 'Invalid token' });
}
};HATEOAS (Optional)
Include links to related resources:
{
"id": 123,
"name": "John Doe",
"email": "john@example.com",
"_links": {
"self": "/api/users/123",
"posts": "/api/users/123/posts",
"followers": "/api/users/123/followers"
}
}Conclusion
Good API design is about consistency, clarity, and developer experience. Follow these principles:
- Use proper HTTP methods and status codes
- Design intuitive URL structures
- Provide clear error messages
- Document everything
- Version your API
- Implement security from the start
Remember: your API is a contract with your users. Make it reliable, predictable, and well-documented. Your future self (and other developers) will thank you!