Complete REST API Design
[backend, http]
Designing a REST API is not just about exposing endpoints. It is about designing communication rules that remain predictable, scalable, and easy for other engineers to consume over time.
This guide walks through REST from first principles to practical endpoint design decisions you can apply immediately.
If you are following the HTTP series on this blog, this post acts as the practical design bridge between protocol fundamentals and production API decisions.
Quick Visual Maps
Request flow map
Client
|
| HTTP Request
v
API Gateway / Router
|
v
Middleware Chain (auth, rate limit, logging)
|
v
Controller -> Service -> Repository -> Database
|
v
HTTP Response (status code + body)
Method and idempotency map
GET -> Read resource -> Idempotent
PUT -> Replace full resource -> Idempotent
PATCH -> Update partial fields -> Idempotent (with stable payload semantics)
DELETE -> Remove resource -> Idempotent
POST -> Create resource / custom action-> Non-idempotent (by default)
1) What Is REST? (History and Definition)
In the 1990s, Tim Berners-Lee invented the World Wide Web. As the web grew rapidly, scalability became a major challenge. In 2000, Roy Fielding proposed an architectural style to standardize web communication and improve scalability: REST (Representational State Transfer).
Let’s break down the name:
- Representational: A resource can be represented in different formats depending on the client. An API client may receive JSON, while a browser may receive HTML.
- State: The current condition of a resource, such as the items and total price in a shopping cart.
- Transfer: Moving these representations between client and server using standard HTTP methods.
2) The 6 REST Constraints
To be truly RESTful, a system should follow six constraints proposed by Fielding:
- Client-Server: Strict separation of concerns. The client handles UI/UX; the server handles business logic and data.
- Uniform Interface: A consistent, standardized way for components to communicate.
- Layered System: Requests can pass through layers (proxies, gateways, load balancers), and each layer only interacts with adjacent layers.
- Cache: Responses should clearly declare whether they are cacheable.
- Stateless: The server should not store client session state between requests.
- Code on Demand (Optional): The server can send executable code (such as JavaScript) to extend client behavior temporarily.
3) Anatomy of a RESTful Route
A typical API route follows a predictable structure:
https://api.example.com/v1/books
That includes:
- secure scheme:
https - API subdomain:
api - version:
v1 - resource path:
books
Key route design rules:
- Use plural nouns for resources:
/books,/organizations - Use IDs for single-resource retrieval:
/books/123 - Avoid spaces and underscores in URLs
- Use lowercase and hyphenated slugs:
/books/harry-potter - Use hierarchical nesting when relationships matter:
/organizations/123/projects
4) HTTP Methods and Idempotency
Idempotency means making the same request multiple times has the same server-side effect as making it once.
- GET (Idempotent): Reads data only; repeated calls do not change state.
- PUT (Idempotent): Replaces a full resource representation.
- PATCH (Idempotent in typical update semantics): Updates selected fields; applying the same patch repeatedly should stabilize to the same final state.
- DELETE (Idempotent): First call removes the resource; later calls should not create additional side effects.
- POST (Non-idempotent by default): Usually creates new resources, so repeated calls can create duplicates.
Use this model deliberately when designing retry behavior and client SDKs.
5) Custom Actions (When CRUD Is Not Enough)
Not every domain action maps cleanly to Create/Read/Update/Delete. Some actions trigger workflows, jobs, and side effects beyond standard updates, such as cloning or archiving.
When that happens, model the action as POST on a resource-specific sub-route:
POST /projects/123/clonePOST /organizations/5/archive
This keeps your API expressive while preserving clean resource boundaries.
6) Designing Robust List APIs
List endpoints should be built for large datasets from day one. Three features are essential:
- Pagination
Return chunks, not everything at once. A practical paginated response includes:
data: array for the current pagetotal: total number of matching recordspage: current page numbertotalPages: total number of pages
- Sorting
Allow clients to sort explicitly, e.g. ?sortBy=name&sortOrder=ascending.
- Filtering
Allow query-based filtering, e.g. ?status=active&name=org.
Well-designed list APIs dramatically reduce frontend complexity and bandwidth waste.
7) Handling Status Codes Correctly
Use status codes intentionally and consistently:
200 OK: successful fetch/update/custom action201 Created: successful resource creation via POST204 No Content: successful delete with empty body
A common rule many teams get wrong:
- Return
404 Not Foundwhen a specific single resource does not exist (e.g.GET /users/999) - For list endpoints with no matches, return
200 OKwith an empty list ([]), not404
That distinction keeps API behavior predictable for client code.
8) Golden Rules for API Engineers
- Extract nouns from UI: Look at product wireframes and identify core entities (projects, users, tasks). Those nouns usually become your resources.
- Use sane defaults: If optional inputs are missing, apply defaults (for example, limit = 10, sort by
createdAtdescending, default status =active). - Be relentlessly consistent: Keep naming conventions stable (
camelCasein payloads, same field names across endpoints). - Ship interactive docs: Use Swagger/OpenAPI so consumers can read and test the API in one place.
Consistency is what turns an API from “working” into “pleasant to use.”
Related HTTP Series Reading
- Foundations: HTTP for Backend Engineers (Part 1)
- Methods and idempotency deep dive: HTTP for Backend Engineers (Part 3)
- Status code semantics: HTTP for Backend Engineers (Part 6)
- Caching behavior: HTTP for Backend Engineers (Part 7)
- Routing deep dive: What is Routing in Backend?
- Input handling: Input Validation and Data Transformation
A well-designed REST API is a long-term product, not a one-time implementation detail. The cleaner your resource modeling, method semantics, status codes, and defaults are today, the fewer integration bugs and breaking changes you will fight tomorrow.
Happy hacking!