Building REST APIs seems simple, but designing them well is an art. In this comprehensive guide, I’ll share the best practices I’ve learned from building APIs that handle millions of requests.
HTTP methods have semantic meaning. Use them correctly:
| Method | Purpose | Example |
|---|---|---|
GET |
Retrieve data | GET /users/123 |
POST |
Create data | POST /users |
PUT |
Replace entire resource | PUT /users/123 |
PATCH |
Partial update | PATCH /users/123 |
DELETE |
Remove resource | DELETE /users/123 |
Common mistake: Using POST for everything. This breaks REST principles and makes your API harder to understand.
APIs change. Versioning prevents breaking changes for existing clients.
Good: /api/v1/users
Bad: /api/users (implicit v1)
Why this matters:
REST is resource-based. Use nouns for your endpoints.
Good: GET /users
Bad: GET /getAllUsers
Good: POST /users
Bad: POST /createUser
Good: DELETE /users/123
Bad: DELETE /deleteUser/123
The HTTP method already tells us what to do. The URL should only tell us what resource we’re working with.
Return meaningful error responses:
{
"error": {
"code": "USER_NOT_FOUND",
"message": "User with ID 123 not found",
"details": {
"requestedId": 123
}
}
}
Use proper HTTP status codes:
200 OK - Success201 Created - Resource created400 Bad Request - Invalid request401 Unauthorized - Missing authentication403 Forbidden - Authenticated but no permission404 Not Found - Resource not found429 Too Many Requests - Rate limit exceeded500 Internal Server Error - Something went wrongNever return all records at once. Use pagination:
GET /users?page=1&limit=20
Response:
{
"data": [...],
"meta": {
"page": 1,
"limit": 20,
"total": 1000,
"totalPages": 50
},
"links": {
"first": "/users?page=1",
"last": "/users?page=50",
"next": "/users?page=2",
"prev": null
}
}
Give clients control over data:
GET /users?status=active&sort=name:asc&page=1&limit=20
Common filters:
status=activecreated_at[gte]=2026-01-01search=johnAuthentication and authorization are critical:
Example header:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Never send sensitive data:
Documentation is not optional. Use:
Example OpenAPI spec:
paths:
/users:
get:
summary: Get all users
parameters:
- name: page
in: query
schema:
type: integer
responses:
'200':
description: Success
content:
application/json:
schema:
type: object
Building a good REST API takes practice. Start with these basics, then iterate based on real-world feedback.
Key takeaways:
Next steps:
Enjoyed this article? Subscribe to get weekly tips on REST API design and backend development.