Last 30 Days
No notifications
REST is an architectural style for designing networked APIs. It treats everything as a resource with standard operations.
| Principle | Meaning |
| Client-Server | Frontend and backend are separate |
| Stateless | Each request contains all info needed |
| Uniform Interface | Consistent URL patterns & methods |
| Resource-Based | Everything is a resource (user, post, order) |
| JSON Format | Standard data exchange format |
GET /api/users β List all users
GET /api/users/42 β Get user #42
POST /api/users β Create new user
PUT /api/users/42 β Replace user #42
PATCH /api/users/42 β Update parts of user #42
DELETE /api/users/42 β Delete user #42GET /api/users/42/posts β Get posts by user #42
| Non-RESTful β | RESTful β |
| GET /getUser?id=42 | GET /users/42 |
| POST /createUser | POST /users |
| POST /deleteUser/42 | DELETE /users/42 |
| GET /getUserPosts?uid=42 | GET /users/42/posts |
REST is just a convention for designing HTTP APIs. It is not a protocol, library, or framework β it is a set of agreements about how to name URLs, which HTTP method to use, and what the response should look like. Once your team agrees, every endpoint becomes predictable: GET /users/42 reads user 42, DELETE /users/42 deletes them. No surprises.
REST = REpresentational State Transfer. The big idea: your server exposes resources (users, posts, orders), and clients use standard HTTP verbs to read or change them. The URL says *what* (the noun); the method says *how* (the verb).
GET /posts β list posts
GET /posts/7 β read post 7
POST /posts β create a new post
PUT /posts/7 β replace post 7
PATCH /posts/7 β update part of post 7
DELETE /posts/7 β delete post 7If you can read those URLs and immediately know what they do, that is REST working as intended.
1. Clientβserver β UI and data live on different machines. 2. Stateless β every request carries everything the server needs (token, body). The server does not remember you between requests. 3. Cacheable β responses say if/how long they can be cached. 4. Uniform interface β same rules everywhere (URLs are nouns, methods are verbs, JSON is JSON). 5. Layered β there can be proxies/CDNs/load balancers in between, the client cannot tell. 6. Code on demand *(optional)* β server can ship JS to the client.
For day-to-day work, stateless + uniform interface are the two that matter most.
A classic beginner mistake: putting verbs in the URL.
β POST /createUser
β GET /getAllPosts
β POST /post/7/deleteβ
POST /users
β
GET /posts
β
DELETE /posts/7
The HTTP method is already the verb. The URL only names *what* you are acting on.
/users, /orders, /posts./blog-posts not /BlogPosts./users/42/posts is fine; /users/42/posts/9/comments/3/replies is a smell β flatten it./users/42 not /users/42.json (use the Accept header instead).1. Using GET to change data. GET must be safe and idempotent. A GET /posts/7/delete will be triggered by browser prefetchers, crawlers, antivirus scanners β and your data will vanish.
2. Returning 200 for errors. A failed request is not OK. Use 4xx/5xx so clients can branch on response.ok.
3. Inconsistent response shapes. Some endpoints return an array, some an object, some { data: [...] }. Pick one envelope and stick to it.
4. Leaking the database. GET /users should not dump every column including password_hash. Map to a DTO.
5. Putting auth in the URL. Tokens belong in the Authorization header, never in query strings (they end up in logs).
6. Versioning by guesswork. Decide /api/v1/... on day one. Adding versions later is painful.
You do not need all 60. These cover ~95% of real APIs:
| Code | Meaning | When |
| 200 | OK | Successful GET / PUT / PATCH |
| 201 | Created | Successful POST that made a resource |
| 204 | No Content | Successful DELETE or empty response |
| 400 | Bad Request | Malformed JSON, missing field |
| 401 | Unauthorized | No / invalid token |
| 403 | Forbidden | Logged in but not allowed |
| 404 | Not Found | Resource does not exist |
| 409 | Conflict | Duplicate (email already taken) |
| 422 | Unprocessable Entity | Validation failed (semantic) |
| 429 | Too Many Requests | Rate limited |
| 500 | Internal Server Error | Your code threw |
| 503 | Service Unavailable | Down for maintenance |
Rule of thumb: 401 = who are you?, 403 = I know you, you cannot do this, 404 = nothing here, 409 = state conflict.
POST /payments
Idempotency-Key: 5b1c-...-f9
β first call: charges $20, returns 201
β retry of same key: returns the original 201, no double chargePick one of these shapes for your whole API:
// Success
{
"data": { "id": 7, "title": "Hello" },
"meta": { "requestId": "req_123" }
}// Error (RFC 7807-ish)
{
"error": {
"code": "VALIDATION_FAILED",
"message": "Email is required",
"details": [{ "field": "email", "issue": "required" }]
}
}
Clients then write one error handler that reads error.code, not 50 special cases.
Never return an unbounded list. Three pagination styles:
?page=2&limit=20 β easy, but slow on huge tables
?offset=40&limit=20 β same problem, classic SQL
?cursor=eyJpZCI6NDB9 β fastest, stable across insertsFiltering and sorting belong in the query string:
GET /posts?author=42&tag=node&sort=-createdAt&fields=id,title&limit=20The - prefix on sort means descending. fields lets clients ask for sparse responses (mobile saves bandwidth).
/api/v1/users β most common, easiest for clients to discover.Accept: application/vnd.myapp.v2+json β cleaner URLs, harder to debug.?version=2 β works but easy to forget.Sunset header.The purest form of REST says responses should include links to next actions:
{
"id": 7,
"status": "draft",
"_links": {
"self": { "href": "/posts/7" },
"publish": { "href": "/posts/7/publish", "method": "POST" }
}
}In practice almost no public API does this β clients hard-code URLs. Know the term, use it for hypermedia-driven internal systems if you ever build one.
Let clients ask "has this changed?" without re-downloading the whole resource:
Server: ETag: "abc123"
Client: If-None-Match: "abc123"
Server: 304 Not Modified β no body, saves bandwidthGreat for read-heavy endpoints (product catalogs, profiles).
REST is awkward for "do 1000 things". Two real-world patterns:
POST /users/bulk accepting an array, returning per-item results.POST /exports returns 202 Accepted with a job URL the client polls (GET /exports/abc) until status is done.1. Design URLs and methods for a blog (posts, comments, likes, users) on paper.
2. Build it in Express, return the same envelope shape everywhere.
3. Add pagination + filtering + sorting on GET /posts.
4. Add an Idempotency-Key flow for POST /comments and prove duplicate calls do not duplicate rows.