REST (Representational State Transfer) is an architectural style for building web APIs. It's not a protocol or standard - it's a set of constraints that, when followed, create APIs that are scalable, simple, and easy to understand. Most public APIs you interact with (Twitter, GitHub, Stripe) are REST APIs.
REST API
An architectural style for building web APIs using HTTP methods and stateless communication.
Core Principles
REST isn't just "use HTTP" - it has specific constraints that make APIs predictable:
1. Stateless Each request contains all information needed to process it. The server doesn't remember previous requests. This means you can't say "get the next page" - you must say "get page 2 of users sorted by name". This makes APIs scalable because any server can handle any request.
2. Client-Server Separation The client (frontend) and server (API) evolve independently. The server doesn't care if you're using React, mobile app, or curl. The client doesn't care if the server uses PostgreSQL or MongoDB.
3. Uniform Interface Every REST API works the same way: resources have URLs, you use HTTP methods to interact with them, and responses are self-descriptive. Once you learn one REST API, you can use any REST API.
4. Resource-Based
Everything is a resource with a unique URL. Users, products, orders - each has an address. You don't call functions like getUser() - you access resources like GET /users/123.
HTTP Methods
| Method | Purpose | Idempotent | Example |
|---|---|---|---|
| GET | Read data | Yes | GET /users - list users |
| POST | Create new resource | No | POST /users - create user |
| PUT | Replace entire resource | Yes | PUT /users/1 - replace user 1 |
| PATCH | Update partial resource | No | PATCH /users/1 - update user 1's email |
| DELETE | Remove resource | Yes | DELETE /users/1 - delete user 1 |
Idempotent means calling it multiple times has the same effect as calling once. DELETE /users/1 three times still results in user 1 being deleted. But POST /users three times creates three users.
URL Design
Good REST URLs are intuitive and consistent:
| Pattern | Example | Description |
|---|---|---|
| Collection | /users | All users |
| Single resource | /users/123 | User with ID 123 |
| Nested resource | /users/123/orders | Orders belonging to user 123 |
| Filtered collection | /users?status=active | Active users only |
Naming conventions:
- Use nouns, not verbs:
/usersnot/getUsers - Use plural:
/productsnot/product - Use kebab-case:
/user-profilesnot/userProfiles - Keep it flat when possible: max 2-3 levels of nesting
Status Codes
The response status code tells the client what happened:
| Code | Meaning | When to Use |
|---|---|---|
| 200 | OK | Successful GET, PUT, PATCH |
| 201 | Created | Successful POST that created resource |
| 204 | No Content | Successful DELETE |
| 400 | Bad Request | Invalid input from client |
| 401 | Unauthorized | Missing or invalid authentication |
| 403 | Forbidden | Authenticated but not allowed |
| 404 | Not Found | Resource doesn't exist |
| 409 | Conflict | Resource already exists (duplicate email) |
| 422 | Unprocessable | Valid syntax but semantic error |
| 500 | Server Error | Bug in your code |
Common Mistakes
1. Using verbs in URLs
❌ POST /createUser or GET /getUsers
✅ POST /users and GET /users
2. Not using proper status codes
❌ Returning 200 with {error: "Not found"}
✅ Returning 404 with proper error body
3. Inconsistent naming
❌ /users, /product, /OrderItems
✅ /users, /products, /order-items
4. Deeply nested URLs
❌ /users/1/orders/2/items/3/reviews/4
✅ /order-items/3/reviews or /reviews?order_item=3
5. Ignoring idempotency
PUT should replace the entire resource. If client sends {name: "John"}, don't keep the old email - that's what PATCH is for.
Best Practices
Use consistent response format:
Always return the same structure. If GET /users/1 returns {id, name, email}, then POST /users should return the same shape.
Include pagination for lists:
Never return unbounded lists. Use ?page=1&limit=20 or cursor-based pagination.
Version your API:
Use /v1/users or Accept: application/vnd.api.v1+json. When you need breaking changes, create v2.
Return created/updated resources: After POST or PUT, return the full resource. The client needs the server-generated ID and timestamps.
Use HATEOAS for discoverability:
Include links to related resources: {id: 1, name: "John", links: {orders: "/users/1/orders"}}
Code Examples
Complete REST API Example
# List all users (with pagination)
GET /api/v1/users?page=1&limit=20
Authorization: Bearer <token>
# Response: 200 OK
{
"data": [{"id": 1, "name": "John", "email": "john@example.com"}],
"meta": {"page": 1, "total": 45}
}
# Create a new user
POST /api/v1/users
Content-Type: application/json
{"name": "Jane", "email": "jane@example.com"}
# Response: 201 Created
{"id": 2, "name": "Jane", "email": "jane@example.com", "created_at": "..."}
# Update user's email only
PATCH /api/v1/users/2
Content-Type: application/json
{"email": "jane.doe@example.com"}
# Delete a user
DELETE /api/v1/users/2
# Response: 204 No ContentRelated Terms
Contract Testing
A testing approach that verifies API consumers and providers adhere to a shared contract, ensuring integration compatibility.
HTTP Status Codes
Standard response codes that indicate the result of an HTTP request.
CORS
Cross-Origin Resource Sharing - A security mechanism that controls how web pages can request resources from different domains.
N+1 Problem
A performance anti-pattern where an application makes N additional queries for N items.