6 min read
Web Backend Fundamentals Index
Tier 1 -- Core Web & API Basics
Authentication & Authorization
Tier 2 -- Communication Models
Tier 3 -- Production & API Hardening
Web Backend Fundamentals Index
Tier 1 -- Core Web & API Basics
Authentication & Authorization
Tier 2 -- Communication Models
Tier 3 -- Production & API Hardening
HTTP Methods and Status Codes
1. What It Is
methods (also called verbs) define the intent of a request. Status codes tell the client what happened as a result. Together they form the fundamental communication contract between a client (browser, mobile app, service) and a backend server.
When you build an API, every endpoint has two questions to answer:
- What action is the client asking to perform? → method
- What was the outcome? → Status code
Getting these right makes your API predictable, debuggable, and compatible with browsers, caches, proxies, and client libraries — getting them wrong causes subtle bugs that are painful to diagnose.
A frontend developer notices that an API call sometimes succeeds silently and sometimes fails, but both cases return a 200 OK status. Debugging takes hours because nothing looks wrong at first glance. What fundamental API design principle has been violated?
2. How It Works in Practice
HTTP Methods
| Method | Meaning | Body? | Safe? | Idempotent? |
|---|---|---|---|---|
| GET | Retrieve a resource | No | Yes | Yes |
| POST | Create or submit data | Yes | No | No |
| PUT | Replace a resource entirely | Yes | No | Yes |
| PATCH | Partially update a resource | Yes | No | No (usually) |
| DELETE | Remove a resource | No | No | Yes |
| HEAD | Like GET but no body in response | No | Yes | Yes |
| OPTIONS | Ask what methods are allowed | No | Yes | Yes |
Safe = the method does not modify server state (read-only).
= calling it multiple times has the same effect as calling it once.
These properties matter because proxies, browsers, and retry logic rely on them. A browser will automatically retry a failed GET but never auto-retry a POST.
Example: creating a user vs. fetching one
POST /users HTTP/1.1 Content-Type: application/json { "email": "alice@example.com", "name": "Alice" }
HTTP/1.1 201 Created Location: /users/42
GET /users/42 HTTP/1.1
HTTP/1.1 200 OK Content-Type: application/json { "id": 42, "email": "alice@example.com", "name": "Alice" }
HTTP Status Codes
Status codes are grouped into five classes:
| Range | Class | Meaning |
|---|---|---|
| 1xx | Informational | Request received, continuing |
| 2xx | Success | Request succeeded |
| 3xx | Redirection | Further action needed by the client |
| 4xx | Client Error | Bad request, unauthorized, not found |
| 5xx | Server Error | Server failed to fulfill a valid request |
Most common codes you'll encounter daily:
| Code | Name | When to use |
|---|---|---|
| 200 | OK | Generic success (GET, PATCH, DELETE with body response) |
| 201 | Created | Resource created (response to POST) |
| 204 | No Content | Success but no body (DELETE, some PUT/PATCH) |
| 301 | Moved Permanently | Permanent redirect (update bookmarks/links) |
| 302 | Found | Temporary redirect |
| 400 | Bad Request | Malformed input, validation failure |
| 401 | Unauthorized | Not authenticated (send credentials) |
| 403 | Forbidden | Authenticated but not authorized |
| 404 | Not Found | Resource does not exist |
| 409 | Conflict | State conflict (duplicate email, version mismatch) |
| 422 | Unprocessable Entity | Semantically invalid input (passes parsing, fails logic) |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Unexpected server failure |
| 503 | Service Unavailable | Server overloaded or down for maintenance |
A client sends a POST request to create a new order, but the network drops the response before it arrives. The client's retry logic automatically resends the identical POST request. What is the likely risk of this behavior?
3. Common Real-World Usage
APIs follow a resource-oriented pattern:
GET /orders → list orders
POST /orders → create an order
GET /orders/99 → fetch order 99
PUT /orders/99 → replace order 99
PATCH /orders/99 → update part of order 99
DELETE /orders/99 → delete order 99
Frameworks map methods to handlers automatically:
# Flask example @app.route("/orders/<int:order_id>", methods=["GET"]) def get_order(order_id): order = db.get(order_id) if not order: return jsonify({"error": "not found"}), 404 return jsonify(order), 200
// Express example router.post("/orders", async (req, res) => { const newOrder = await OrderService.create(req.body); res.status(201).json(newOrder); });
Status codes trigger client-side behavior:
301/302→ browser follows theLocationheader automatically401→ many API clients pop up an auth dialog or redirect to login429+Retry-Afterheader → rate-limiting clients know when to retry
An Express.js route handler creates a new resource in the database and needs to return a response to the client. Which HTTP status code should it send back to correctly signal that the resource was successfully created?
4. Trade-offs and Common Mistakes
Using the wrong method
- POST for everything — common in legacy APIs. Breaks caching, idempotency, and makes intent opaque.
- GET with a body — technically valid per spec but widely unsupported by proxies and clients. Use POST for search endpoints that need complex filters.
Using the wrong status code
- Returning
200 OKwith{ "success": false }in the body — forces clients to parse the body to detect errors rather than checking the status code. Breaks clients, monitoring tools, and retry logic. - Returning
404when you mean403to hide resource existence — acceptable for security-sensitive cases, but document this explicitly. - Using
500for client errors (validation failures) — misrepresents who is at fault and makes alerting noisy.
PUT vs. PATCH confusion
PUTreplaces the entire resource. Omit a field and it gets nulled/deleted.PATCHupdates only the provided fields. Use it for partial updates.
Idempotency in practice
DELETE /orders/99called twice should still return success (or404on the second call, not500). Design your endpoints to be where the method contract requires it.- For
POSTendpoints that create resources, use idempotency keys (a client-generated UUID in the header) to safely allow retries without duplicate creation.
An API endpoint returns HTTP 200 OK for every request, including failed ones, with a JSON body like { "success": false, "error": "Invalid input" }. What is the primary problem with this approach?
5. Interview Angle
How to explain it
" methods express intent — GET reads, POST creates, PUT replaces, PATCH partially updates, DELETE removes. Status codes communicate outcome: 2xx means success, 4xx means the client did something wrong, 5xx means the server failed. Getting these right makes APIs self-documenting and compatible with the ecosystem including caches and proxies."
Common interview questions
Q: What is the difference between PUT and PATCH?
PUT replaces the entire resource. PATCH applies a partial update. If you PUT a user object and omit the
phonefield, the phone gets wiped. PATCH only touches what you send.
Q: What is the difference between 401 and 403?
401 means the client is not authenticated — it hasn't proven who it is yet. 403 means the client is authenticated but is not allowed to access the resource. Think of 401 as "who are you?" and 403 as "I know who you are, but no."
Q: When would you use 204 vs 200?
204 when the operation succeeds but there is nothing meaningful to return — like a DELETE. 200 when you return a body. Some teams always return 200 with a body even for deletes; the important thing is to be consistent.
Q: Is GET always safe to retry?
Yes, GET is safe (read-only) and . That's why browsers, proxies, and HTTP clients retry GET automatically. POST is neither safe nor , so it should never be auto-retried.
6. Practical Examples
Validation error response (400 vs 422)
POST /users HTTP/1.1 Content-Type: application/json { "email": "not-an-email" }
HTTP/1.1 422 Unprocessable Entity Content-Type: application/json { "errors": [ { "field": "email", "message": "must be a valid email address" } ] }
Use 400 when the request body is malformed (bad JSON). Use 422 when the JSON parses fine but the values fail business validation.
Idempotency key for payment creation
POST /payments HTTP/1.1 Idempotency-Key: a3f8c2d1-0011-4b2e-9e2a-112233445566 Content-Type: application/json { "amount": 5000, "currency": "USD", "recipient_id": 7 }
If the network drops and the client retries with the same Idempotency-Key, the server returns the original response instead of creating a duplicate payment.
Rate limit response
HTTP/1.1 429 Too Many Requests Retry-After: 30 Content-Type: application/json { "error": "rate limit exceeded", "retry_after_seconds": 30 }
Clients should read Retry-After and back off instead of hammering the server.
A client sends a POST request to create a user with a properly formatted JSON body: { "email": "not-an-email" }. The server can parse the JSON without error, but the email value fails validation. Which HTTP status code should the server return?
Glossary History
Click dotted jargon to save explanations here.
Glossary History
Click dotted jargon to save explanations here.