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 will not auto-retry a POST unless it knows the server never processed it.
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/42GET /users/42 HTTP/1.1HTTP/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 |
Create a user, then fetch it
POST asks the server to create user Alice; 201 returns the location of the new user, and GET reads it back with 200.
POST sends Alice’s data because the client wants to create a user.
Text version
- POST sends Alice’s data because the client wants to create a user.
- Status two hundred one confirms creation, and the Location header gives the new resource’s address.
- GET requests that resource because the client wants to read it.
- The server returns Alice’s user data with status two hundred, which means the request succeeded.
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 99Frameworks 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
Trace the missing-order response
In this example run, order 99 is absent; the Flask handler takes the not-found branch and returns 404.
The handler receives order ID ninety-nine from the GET request.
Text version
- The handler receives order ID ninety-nine from the GET request.
- The database returns no order for that identifier.
- The condition is true because the lookup found no order.
- The handler returns the error with status four hundred four.
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 not be auto-retried. Auto-retry it only when the client knows a retry is safe (an idempotency key, or proof the server never processed it).
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.
Retry a payment without creating a duplicate
After a dropped response, the client retries POST with the same idempotency key, and the server returns the original response.
POST is not idempotent, so the client adds an idempotency key that lets the server spot a retry.
Text version
- POST is not idempotent, so the client adds an idempotency key that lets the server spot a retry.
- The network drops after payment creation, so the client misses the response.
- The client retries the same payment request with the same key to avoid creating a duplicate.
- The server returns the original response instead of creating a duplicate payment.
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?