REST (Representational State Transfer) is a set of rules for building APIs. Itβs not a technology or a library β itβs a design pattern. When someone says βREST API,β they mean an API that follows these conventions.
Most APIs on the internet are REST APIs. If youβve ever used fetch() to get data from a server, youβve probably used one.
The rules of REST
1. Use URLs to identify resources
Each βthingβ in your system gets its own URL:
/users β all users
/users/42 β user with ID 42
/users/42/posts β posts by user 42
/posts β all posts
/posts/7 β post with ID 7
URLs are nouns, not verbs. /getUser is wrong. /users/42 is right.
2. Use HTTP methods for actions
| Method | What it does | Example |
|---|---|---|
| GET | Read data | GET /users β list users |
| POST | Create new data | POST /users β create a user |
| PUT | Replace data | PUT /users/42 β replace user 42 |
| PATCH | Update part of data | PATCH /users/42 β update user 42βs email |
| DELETE | Remove data | DELETE /users/42 β delete user 42 |
The URL says what, the method says how.
3. Use status codes for results
| Code | Meaning | When to use |
|---|---|---|
| 200 | OK | Successful GET, PUT, PATCH |
| 201 | Created | Successful POST |
| 204 | No Content | Successful DELETE |
| 400 | Bad Request | Invalid input |
| 401 | Unauthorized | Not logged in |
| 403 | Forbidden | Logged in but not allowed |
| 404 | Not Found | Resource doesnβt exist |
| 409 | Conflict | Duplicate entry |
| 422 | Unprocessable | Validation failed |
| 500 | Server Error | Something broke |
Full list: HTTP Status Codes cheat sheet
4. Use JSON for data
Requests and responses use JSON:
// POST /users
// Request body:
{
"name": "Alice",
"email": "alice@example.com"
}
// Response (201 Created):
{
"id": 42,
"name": "Alice",
"email": "alice@example.com",
"createdAt": "2026-03-14T10:30:00Z"
}
5. Stateless
Each request contains everything the server needs. The server doesnβt remember previous requests. Authentication is sent with every request (usually as a token in the header).
A complete example
Letβs design a REST API for a blog:
GET /posts β List all posts
GET /posts/7 β Get post 7
POST /posts β Create a new post
PUT /posts/7 β Replace post 7
PATCH /posts/7 β Update post 7
DELETE /posts/7 β Delete post 7
GET /posts/7/comments β Comments on post 7
POST /posts/7/comments β Add comment to post 7
GET /users/42/posts β Posts by user 42
List posts with filtering and pagination:
GET /posts?page=2&limit=10&sort=createdAt&order=desc
GET /posts?author=42&published=true
Building a REST API (Node.js + Express)
const express = require('express');
const app = express();
app.use(express.json());
let posts = [];
let nextId = 1;
// List all posts
app.get('/posts', (req, res) => {
res.json(posts);
});
// Get one post
app.get('/posts/:id', (req, res) => {
const post = posts.find(p => p.id === parseInt(req.params.id));
if (!post) return res.status(404).json({ error: 'Post not found' });
res.json(post);
});
// Create a post
app.post('/posts', (req, res) => {
const post = { id: nextId++, ...req.body, createdAt: new Date() };
posts.push(post);
res.status(201).json(post);
});
// Update a post
app.patch('/posts/:id', (req, res) => {
const post = posts.find(p => p.id === parseInt(req.params.id));
if (!post) return res.status(404).json({ error: 'Post not found' });
Object.assign(post, req.body);
res.json(post);
});
// Delete a post
app.delete('/posts/:id', (req, res) => {
posts = posts.filter(p => p.id !== parseInt(req.params.id));
res.status(204).send();
});
app.listen(3000);
Consuming a REST API
// JavaScript (fetch)
const posts = await fetch('/posts').then(r => r.json());
const newPost = await fetch('/posts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: 'Hello', body: 'World' }),
}).then(r => r.json());
# cURL
curl http://localhost:3000/posts
curl -X POST http://localhost:3000/posts \
-H "Content-Type: application/json" \
-d '{"title": "Hello", "body": "World"}'
See: cURL cheat sheet for more patterns.
REST API design tips
- Use plural nouns:
/usersnot/user - Use nested routes for relationships:
/users/42/postsnot/getUserPosts?userId=42 - Use query parameters for filtering:
/posts?published=true - Return the created/updated resource in the response body
- Use consistent error format:
{
"error": "Validation failed",
"details": [
{ "field": "email", "message": "Invalid email format" }
]
}
REST vs. GraphQL
For a comparison, see What is an API? β it covers REST vs. GraphQL differences.