A comprehensive guide to the 8 REST API design laws, focusing on designing around resources, predictable URLs, proper HTTP method usage, and consistent error handling.
Intro
Designing a REST API is more than just exposing endpoints to your database; it is about creating a predictable, maintainable, and intuitive interface for developers to interact with your system. A well-designed API reduces friction, minimizes the need to constantly consult documentation, and establishes a clear mental model.
In this article, we will explore the 8 REST API Design Laws that set the foundation for a cohesive API framework.
1. Design Around Resources, Not Actions
This is the first law of REST API design. It establishes that URLs should identify the resource being acted upon, while HTTP methods (verbs) describe the operation being performed.
Core Concept & Common Pitfalls
A common mistake in API design is putting the action directly into the URL path, resulting in endpoints like getUsers, createOrder, or deleteProduct. This design is redundant because HTTP was explicitly built to communicate actions through standard methods.
Instead, a clean RESTful design uses noun-based resources for the path (such as users, orders, or products) and lets the HTTP verb specify the action:
- GET
/orders: Retrieves orders. - POST
/orders: Creates a new order. - DELETE
/orders/{id}: Removes a specific order.
Key Benefits
- Scalability: As the API expands, the same resource endpoint can support multiple operations without creating a separate URL for every action.
- Simplicity & Predictability: Developers don’t have to guess or memorize custom endpoint URLs for every new feature.
2. Make URLs Predictable
Use consistent resource naming conventions. Developers should be able to guess the URL for a resource without looking at the documentation.
Best Practices
- Use Plural Nouns: Collections should be named with plural nouns. For example, use
/usersinstead of/user, and/ordersinstead of/order. - Standard Identifier Structures: When targeting a specific item in a collection, append the identifier to the path:
/users/123. - Nested Resources: Represent relationships logically. If an order belongs to a user, a predictable path would be
/users/123/orders.
// GoodGET /api/v1/productsGET /api/v1/products/42GET /api/v1/products/42/reviews
// BadGET /api/v1/getAllProductsGET /api/v1/product?id=423. Use HTTP Methods for Their Actual Purpose
Respect standard HTTP semantics and idempotency. HTTP provides verbs designed for specific operations.
- GET: Retrieve a resource. Should be safe and idempotent (repeated calls don’t change state).
- POST: Create a new resource or trigger processing. Not idempotent.
- PUT: Update an existing resource completely, or create it if it doesn’t exist. Idempotent.
- PATCH: Partially update an existing resource.
- DELETE: Remove a resource. Idempotent.
[ApiController][Route("api/users")]public class UsersController : ControllerBase{ [HttpGet] // GET /api/users public IActionResult GetAll() { /* ... */ return Ok(); }
[HttpPost] // POST /api/users public IActionResult Create(UserDto user) { /* ... */ return CreatedAtAction(nameof(GetAll), new { id = 1 }, user); }
[HttpPut("{id}")] // PUT /api/users/123 public IActionResult Update(int id, UserDto user) { /* ... */ return NoContent(); }}4. Make Status Codes Useful
Communicate overall outcome categories with standard HTTP status codes rather than masking errors behind a 200 OK body. Using correct status codes helps clients handle responses automatically (like retrying on 500s or redirecting to login on 401s).
- 200 OK: Request succeeded.
- 201 Created: Resource successfully created (usually via POST).
- 204 No Content: Request succeeded but no response body (common for DELETE).
- 400 Bad Request: Client sent invalid data.
- 401 Unauthorized: Authentication is required and has failed or has not yet been provided.
- 403 Forbidden: Authenticated, but lacks permissions.
- 404 Not Found: Resource does not exist.
- 422 Unprocessable Entity: Validation errors in the payload.
- 500 Internal Server Error: The server encountered an unexpected condition.
5. Keep Errors Consistent
Provide structured error bodies containing failure codes, clear messages, and specific field validation details. An API should have one unified error format.
In .NET Core, you can achieve this easily using the standard ProblemDetails format (RFC 7807).
{ "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1", "title": "One or more validation errors occurred.", "status": 400, "traceId": "00-84c1...-00", "errors": { "Email": [ "The Email field is not a valid e-mail address." ] }}6. Don’t Put Everything into the URL Path
Use URL paths exclusively to identify resources, and rely on query parameters for filtering, sorting, or searching.
When clients need to narrow down a list, the URL path should not become a complex command.
// Bad: Action and filters in pathGET /users/active/sort/asc
// Good: Query parameters for filtering and sortingGET /users?status=active&sort=createdAt:asc&limit=107. Treat API Changes Carefully
Manage API evolution thoughtfully through deliberate versioning strategies so updates do not break existing clients.
Always version your API from day one. You can use URL versioning, Header versioning, or Query string versioning. URL versioning is the most explicit and easiest to explore.
[ApiController][Route("api/v{version:apiVersion}/[controller]")][ApiVersion("1.0")]public class ProductsController : ControllerBase{ // Controller actions...}8. Keep Request and Response Formats Consistent
Enforce uniform conventions for JSON property casing, date formats, pagination structures, and error payloads across every endpoint.
- Casing: Stick to one naming convention for JSON properties, typically
camelCase. - Dates: Use ISO 8601 format (e.g.,
2026-09-09T14:30:00Z). - Pagination: Standardize how paginated data is returned. Always include metadata like
totalItems,totalPages,currentPage.
{ "data": [ { "id": 1, "name": "Laptop" }, { "id": 2, "name": "Mouse" } ], "meta": { "page": 1, "pageSize": 10, "totalItems": 45, "totalPages": 5 }}Summary
By defining resource-centric URLs first, the API creates a clear mental model that makes applying the remaining laws—such as method semantics, parameter filtering, and error handling—far more straightforward and predictable. By adhering to these 8 REST API Design Laws, you will build systems that developers will actually enjoy consuming.





