I've designed and consumed hundreds of REST APIs over my career, and I can tell you this: a well-designed API is a joy to work with, while a poorly designed one is a constant source of frustration. The difference often comes down to following a few core principles.
In this guide, I'll share the essential REST API design principles that will help you build APIs that are intuitive, consistent, and easy to maintain. Whether you're building an internal API for your team or a public API used by thousands of developers, these principles will serve you well.
Design Around Resources, Not Actions
The most fundamental principle of REST API design is to think in terms of resources, not actions. Your API should model the entities in your domain, not the operations you perform on them.
Use Nouns, Not Verbs
Instead of endpoints like /createUser, /getUserOrders, or /deleteProduct, use nouns: /users, /users/{id}/orders, /products. The HTTP method tells the client what action to perform.
This consistency makes your API predictable. Once a client understands one endpoint, they understand them all. They know that GET retrieves, POST creates, PUT updates, and DELETE removes.
Model Your Domain
Think about the entities in your application and the relationships between them. If users have orders and orders have items, your API should mirror that structure:
/users/{userId}/orders/{orderId}/items
This hierarchical structure is intuitive and allows clients to navigate your API naturally.
Use HTTP Methods Consistently
Each HTTP method has a specific meaning, and your API should respect those meanings consistently across all endpoints.
The Standard HTTP Methods
- GET: Retrieve a resource or list of resources
- POST: Create a new resource
- PUT: Update an entire resource (full replacement)
- PATCH: Update part of a resource (partial update)
- DELETE: Remove a resource
I can't tell you how many APIs I've seen that use POST for everything because it's easier. Don't be that API. Take the time to implement each method correctly. Your clients will thank you.
When to Use PUT vs PATCH
PUT is for replacing an entire resource. If you send a PUT request with only some fields, the others should be cleared or set to defaults. PATCH is for updating specific fields without affecting the rest.
For example, if you have a user resource with name, email, and bio:
- PUT /users/123 with {name: "Alice"} should update the name and clear email and bio
- PATCH /users/123 with {name: "Alice"} should only update the name
Consistency is key when designing APIs. Define a standard structure for success responses, error responses, and paginated responses, and use them everywhere.
{
"data": {
"id": "123",
"name": "Alice",
"email": "alice@example.com"
},
"meta": {
"timestamp": "2026-01-15T10:30:00Z"
}
}
{
"error": {
"code": "VALIDATION_ERROR",
"message": "The request body contains invalid data",
"details": [
{
"field": "email",
"message": "Must be a valid email address"
}
]
}
}
This consistency makes your API predictable and easier to work with. Clients can write generic error handling code that works for all endpoints.
Paginated Responses
For list endpoints, use a standard pagination format:
{
"data": [...],
"pagination": {
"page": 1,
"limit": 20,
"total": 100,
"totalPages": 5
}
}
Include links for next/previous pages when appropriate. This makes it easy for clients to navigate through large result sets.
Version Your API from Day One
API versioning is one of those things that seems unnecessary until you desperately need it. Version your API from the very first release, even if you think you'll never change it. You will, and when you do, existing clients should not break.
Path-Based Versioning
The simplest approach is path-based versioning: /v1/users, /v2/users. This is easy to implement and easy for clients to understand.
The downside is that it can lead to code duplication if you need to maintain multiple versions simultaneously. But the clarity it provides is worth it.
Header-based versioning is more flexible but harder for clients to discover. The client sends an Accept-Version header to specify which version they want. This keeps your URLs clean but requires more documentation.
My Recommendation
Start with path-based versioning. It's simple, clear, and works well for most APIs. You can always switch to header-based versioning later if you need more flexibility.
Handle Errors Gracefully
Error handling is often an afterthought in API design, but it's one of the most important aspects of the developer experience.
Use Appropriate HTTP Status Codes
Use standard HTTP status codes to indicate the result of the request:
- 200 OK: Request succeeded
- 201 Created: Resource created successfully
- 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 Entity: Validation failed
- 500 Internal Server Error: Server error
These codes give clients a quick understanding of what happened without needing to parse the response body.
Provide Useful Error Messages
Include enough information in the error response for the client to handle the error programmatically. If a field validation fails, tell them which field and what the validation rule is. If a resource is not found, include the resource ID so the client can log it for debugging.
Implement Proper Authentication and Authorization
Security should be built into your API from the start, not added as an afterthought.
Use Industry Standards
Use OAuth 2.0 or JWT tokens for authentication. Never roll your own authentication scheme. These standards have been thoroughly tested and are well-understood by client developers.
Document Your Auth Requirements
Document your authentication and authorization requirements clearly. Include examples of how to obtain tokens, how to include them in requests, and what scopes or permissions are needed for each endpoint.
Rate Limiting and Throttling
Protect your API from abuse by implementing rate limiting. This prevents a single client from overwhelming your servers and ensures fair usage for all consumers.
Include rate limit information in your response headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 2026-01-15T11:00:00Z
This allows clients to implement backoff strategies and avoid hitting limits.
Documentation Is Not Optional
A well-documented API is a joy to use. Use tools like OpenAPI/Swagger to generate interactive documentation that clients can explore and test.
Include:
- Clear descriptions of each endpoint
- Expected request format
- Response format
- Example requests and responses
- Authentication requirements
- Error codes and meanings
Keep your documentation up to date. Outdated documentation is worse than no documentation because it actively misleads developers.
Frequently Asked Questions
Should I use REST or GraphQL?
It depends on your use case. REST is simpler, better cached, and more widely understood. GraphQL is more flexible for clients but adds complexity on the server. For most APIs, REST is the right choice.
How do I handle file uploads?
Use multipart/form-data for file uploads. Accept the file in a POST request, validate it on the server, and return a URL or ID that the client can use to access the file later.
Should I use API versioning?
Yes, always. Even if you think your API won't change, it will. Versioning from day one saves you from breaking existing clients when you need to make changes.
How do I secure my API?
Use HTTPS, implement proper authentication (OAuth 2.0 or JWT), validate all input, implement rate limiting, and keep your dependencies up to date. Follow the OWASP API Security Top 10 guidelines.
What's the best way to test my API?
Write integration tests that cover the happy path, error cases, and edge cases. Use tools like Postman or Insomnia for manual testing. Automate your tests in your CI/CD pipeline.
The Bottom Line
Good REST API design is about consistency, predictability, and developer experience. Design around resources, use HTTP methods correctly, standardize your responses, version your API, handle errors gracefully, and document everything. These principles will help you build APIs that are a joy to use and easy to maintain.
Remember: your API is a user interface for developers. Treat it with the same care you would treat a graphical user interface.