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/123Use 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 itemsNest 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 789But 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=jsonHTTP 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 resourcePOST — 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 ContentHTTP 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,emailAPI Versioning
APIs evolve. Versioning prevents breaking changes from affecting existing integrations:
URL Path Versioning (Most Common)
GET /v1/users
GET /v2/usersHeader Versioning
GET /users
Accept: application/vnd.myapi.v2+jsonWe 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-hereBearer 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: 1640995200Documentation 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?"
Frequently Asked Questions
What's the difference between PUT and PATCH?
PUT replaces the entire resource — send all fields, missing ones are removed. PATCH applies a partial update — send only the fields you want to change. PUT is idempotent (same result on repeat), PATCH may or may not be. Use PUT for full updates, PATCH for incremental ones, and document the merge strategy clearly.
Should I use singular or plural nouns in URLs?
Plural. /users/123 not /user/123. Reason: /users describes the collection, and /users/123 describes a specific item in that collection — consistent for both list and detail. Singular breaks the symmetry and forces /user/123 vs /users in different endpoints.
How do I version a REST API?
Three options: (1) URL versioning: /v1/users — simple, cacheable, easy to test. (2) Header versioning: Accept: application/vnd.api+json;version=2 — clean URLs, harder to test in browser. (3) Query param: /users?api-version=2 — worst of both worlds. For most APIs, URL versioning wins on simplicity. Maintain at least 2 versions simultaneously for 6-12 months after a new release.
