REST API Design Best Practices for 2026
A comprehensive guide to building REST APIs that developers love to use. Learn the patterns that separate good APIs from great ones.
Why API Design Matters
A well-designed API is a joy to work with. It feels intuitive, guides developers toward correct usage, and rarely produces surprising errors. A poorly designed API creates friction at every integration point — documentation gets longer, bugs multiply, and developers grow frustrated.
Your API is a product. It represents your system to the outside world, and like any product, its quality determines adoption. This guide covers the principles that make APIs excellent: clarity, consistency, predictability, and developer experience.
URL Design: The Foundation of Your API
URLs are the primary interface developers interact with. They should be intuitive, consistent, and self-documenting. Think of URLs as sentences describing resources — they should read naturally.
Use Nouns, Not Verbs
HTTP methods already express actions. Your URLs should identify resources, not operations:
// ❌ BAD — Verbs in URLs
GET /getUsers
GET /getUserById/123
POST /createUser
PUT /updateUser/123
DELETE /deleteUser/123
// ✅ GOOD — Nouns and HTTP methods
GET /users
GET /users/123
POST /users
PUT /users/123
DELETE /users/123
Use Plural Nouns
Consistency matters. Always use plural nouns for collections:
GET /users // List users
GET /users/123 // Get specific user
GET /users/123/orders // Get user's orders
GET /orders/456/items // Get order's items
Nest Resources Logically
URL structure should reflect relationships:
/companies/123/employees // Employees of company 123
/companies/123/employees/456 // Specific employee
/repositories/789/issues // Issues in repo 789
But don't nest too deeply. After 2-3 levels, URLs become unwieldy. If you find yourself writing URLs like /a/b/c/d/e, reconsider your resource structure.
Avoid File Extensions
Content negotiation handles different response formats:
// ❌ Avoid
GET /users.json
GET /users.xml
// ✅ Use headers
GET /users
Accept: application/json
// Or query parameters (if you prefer)
GET /users?format=json
HTTP Methods: Use Them Correctly
Each HTTP method has specific semantics. Using them correctly makes your API predictable:
GET — Retrieve Resources
GET requests should be safe (no side effects) and idempotent (multiple calls produce same result). Never modify data in a GET handler.
GET /users // List users
GET /users?page=2 // Paginated list
GET /users/123 // Get specific user
GET /users/123/orders // Nested resource
POST — Create Resources
POST creates new resources. The server generates the identifier:
POST /users
Body: {"name": "John", "email": "john@example.com"}
Response: 201 Created
Location: /users/456
Body: {"id": 456, "name": "John", "email": "john@example.com"}
PUT — Full Replacement
PUT replaces an entire resource. Include all fields — missing fields get nullified:
PUT /users/123
Body: {"name": "John Updated", "email": "john@new.com"}
Response: 200 OK
Body: {"id": 123, "name": "John Updated", "email": "john@new.com"}
PATCH — Partial Update
PATCH updates only specified fields, preserving others:
PATCH /users/123
Body: {"name": "John Patched"}
Response: 200 OK
Body: {"id": 123, "name": "John Patched", "email": "john@example.com"}
DELETE — Remove Resources
DELETE removes resources and should be idempotent (deleting twice returns same result):
DELETE /users/123
Response: 204 No Content
HTTP Status Codes: Communicate Clearly
Status codes tell developers what happened. Use them correctly:
Success Codes
- 200 OK: Successful GET, PUT, PATCH
- 201 Created: Successful POST that created a resource
- 202 Accepted: Request accepted but processing is async
- 204 No Content: Successful DELETE or action with no response body
Client Error Codes
- 400 Bad Request: Invalid request syntax or missing required fields
- 401 Unauthorized: Authentication required or failed
- 403 Forbidden: Authenticated but not authorized
- 404 Not Found: Resource doesn't exist
- 409 Conflict: Request conflicts with current state (duplicate, version conflict)
- 422 Unprocessable Entity: Valid syntax but invalid content (validation errors)
- 429 Too Many Requests: Rate limit exceeded
Server Error Codes
- 500 Internal Server Error: Unexpected server error
- 502 Bad Gateway: Upstream server error
- 503 Service Unavailable: Temporary overload or maintenance
- 504 Gateway Timeout: Upstream request timed out
Error Response Format
Consistent error responses make debugging easier. Use a standard format:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request data",
"details": [
{
"field": "email",
"message": "Must be a valid email address"
},
{
"field": "name",
"message": "Name is required"
}
]
}
}
Always include enough information for developers to understand and fix the issue. But never expose sensitive implementation details.
Pagination and Filtering
Large collections require pagination. Be consistent:
GET /users?page=2&per_page=20
Response:
{
"data": [...],
"pagination": {
"page": 2,
"per_page": 20,
"total": 156,
"total_pages": 8
}
}
Support filtering, sorting, and field selection to give clients flexibility:
GET /users?status=active&sort=name:asc&fields=id,name,email
API Versioning
APIs evolve. Versioning prevents breaking changes from affecting existing integrations:
URL Path Versioning (Most Common)
GET /v1/users
GET /v2/users
Header Versioning
GET /users
Accept: application/vnd.myapi.v2+json
We recommend URL versioning for its simplicity and visibility in logs and browser testing.
Authentication Patterns
Choose authentication based on your use case:
API Keys (For Server-to-Server)
X-API-Key: your-api-key-here
Bearer Tokens (OAuth/JWT)
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Rate Limiting Headers
Always communicate rate limits to clients:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1640995200
Documentation Standards
Great APIs have great documentation. Include:
- Authentication explanation with examples
- All endpoints with request/response examples
- Error codes and what they mean
- Rate limits and best practices
- SDK examples in multiple languages
Summary Checklist
- URLs use nouns, plural forms, logical nesting
- HTTP methods used correctly
- Status codes accurately reflect outcomes
- Errors follow consistent format with actionable details
- Pagination handles large collections
- Versioning prevents breaking changes
- Authentication is clear and secure
- Documentation is comprehensive and examples are working
Great API design isn't about following rules blindly — it's about reducing friction for developers. Every decision should ask: "Would this be obvious to someone using this API for the first time?"