Published May 26, 2026 ยท 10 min read ยท ๐ท๏ธ Backend
# API Design Best Practices
A well-designed API is intuitive, consistent, and developer-friendly. This guide covers the principles and patterns that make APIs a pleasure to use.
## Use RESTful Conventions
REST APIs use standard HTTP methods and URL structures:
GET /users # list all users
GET /users/123 # get single user
POST /users # create new user
PUT /users/123 # update entire user
PATCH /users/123 # partial update
DELETE /users/123 # delete user
Key principles:
- Use nouns in URLs, not verbs (`/users` not `/getUsers`)
- Use plural nouns consistently
- Use nested resources for relationships (`/users/123/orders`)
- Keep URLs lowercase with hyphens
## Proper HTTP Status Codes
Always return the appropriate status code:
200 OK # successful GET, PUT, PATCH
201 Created # successful POST creating resource
204 No Content # successful DELETE
400 Bad Request # invalid input data
401 Unauthorized # not authenticated
403 Forbidden # authenticated but not authorized
404 Not Found # resource doesn't exist
422 Unprocessable Entity # validation errors
429 Too Many Requests # rate limit exceeded
500 Internal Server Error # server error
## Consistent Error Format
Return errors in a consistent structure:
{
"error": "validation_error",
"message": "The request body contains invalid data",
"details": [
{
"field": "email",
"message": "Email format is invalid"
},
{
"field": "password",
"message": "Password must be at least 8 characters"
}
]
}
Include enough information for developers to debug, but don't expose sensitive internals.
## Pagination
Don't return unlimited results. Use cursor or offset pagination:
### Offset Pagination
GET /users?page=2&per_page=20
# Response
{
"data": [...],
"pagination": {
"page": 2,
"per_page": 20,
"total": 150,
"total_pages": 8
}
}
### Cursor Pagination (Better for Large Datasets)
GET /users?cursor=abc123&limit=20
# Response
{
"data": [...],
"pagination": {
"next_cursor": "def456",
"has_more": true
}
}
Cursor pagination is more efficient for large tables and real-time data.
## API Versioning
Version your API to allow breaking changes without breaking clients:
# URL path (most common)
GET /v1/users
GET /v2/users
# Header approach
Accept: application/vnd.api.v2+json
**Tip:** Start with v1 even if you don't think you'll need versions. Adding versioning later is harder than starting with it.
## Filtering, Sorting, and Field Selection
Give clients control over their queries:
# Filtering
GET /orders?status=pending&created_after=2024-01-01
# Sorting
GET /products?sort=price&order=desc
# Field selection (sparse fieldsets)
GET /users?fields=id,name,email
# Combining
GET /orders?status=completed&sort=created_at&order=desc&limit=50
## Authentication
Use standard authentication methods:
# API Keys (for server-to-server)
X-API-Key: your-api-key
# Bearer Tokens (for user authentication)
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
# Rate Limiting Headers
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1640995200
## Performance Tips
### Response Compression
# Client sends
Accept-Encoding: gzip, deflate, br
# Server responds
Content-Encoding: gzip
### Conditional Requests
# Client sends
If-None-Match: "etag-from-previous-response"
# Server checks, returns 304 if unchanged
HTTP/1.1 304 Not Modified
### Cache Control
Cache-Control: public, max-age=3600
ETag: "abc123"
Last-Modified: Wed, 01 Jan 2024 00:00:00 GMT
## Documentation
Good API documentation includes:
- Authentication instructions
- All endpoints with request/response examples
- Error codes and messages
- Rate limits and quotas
- Try-it-out sandbox
Use OpenAPI/Swagger for machine-readable specs that generate documentation automatically.
Top comments (0)