HTTP Methods and Status Codes

6 min read

Reading Progress0%
Web Backend Fundamentals Index
Tier 1 -- Core Web & API Basics
Tier 2 -- Communication Models
Tier 3 -- Production & API Hardening
Web Backend Fundamentals Index
Tier 1 -- Core Web & API Basics
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.


QUICK CHECK

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?

Choose one answer

2. How It Works in Practice

HTTP Methods

MethodMeaningBody?Safe?Idempotent?
GETRetrieve a resourceNoYesYes
POSTCreate or submit dataYesNoNo
PUTReplace a resource entirelyYesNoYes
PATCHPartially update a resourceYesNoNo (usually)
DELETERemove a resourceNoNoYes
HEADLike GET but no body in responseNoYesYes
OPTIONSAsk what methods are allowedNoYesYes

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:

RangeClassMeaning
1xxInformationalRequest received, continuing
2xxSuccessRequest succeeded
3xxRedirectionFurther action needed by the client
4xxClient ErrorBad request, unauthorized, not found
5xxServer ErrorServer failed to fulfill a valid request

Most common codes you'll encounter daily:

CodeNameWhen to use
200OKGeneric success (GET, PATCH, DELETE with body response)
201CreatedResource created (response to POST)
204No ContentSuccess but no body (DELETE, some PUT/PATCH)
301Moved PermanentlyPermanent redirect (update bookmarks/links)
302FoundTemporary redirect
400Bad RequestMalformed input, validation failure
401UnauthorizedNot authenticated (send credentials)
403ForbiddenAuthenticated but not authorized
404Not FoundResource does not exist
409ConflictState conflict (duplicate email, version mismatch)
422Unprocessable EntitySemantically invalid input (passes parsing, fails logic)
429Too Many RequestsRate limit exceeded
500Internal Server ErrorUnexpected server failure
503Service UnavailableServer overloaded or down for maintenance

QUICK CHECK

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?

Choose one answer

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 the Location header automatically
  • 401 → many API clients pop up an auth dialog or redirect to login
  • 429 + Retry-After header → rate-limiting clients know when to retry

QUICK CHECK

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?

Choose one answer

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 OK with { "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 404 when you mean 403 to hide resource existence — acceptable for security-sensitive cases, but document this explicitly.
  • Using 500 for client errors (validation failures) — misrepresents who is at fault and makes alerting noisy.

PUT vs. PATCH confusion

  • PUT replaces the entire resource. Omit a field and it gets nulled/deleted.
  • PATCH updates only the provided fields. Use it for partial updates.

Idempotency in practice

  • DELETE /orders/99 called twice should still return success (or 404 on the second call, not 500). Design your endpoints to be where the method contract requires it.
  • For POST endpoints that create resources, use idempotency keys (a client-generated UUID in the header) to safely allow retries without duplicate creation.

QUICK CHECK

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?

Choose one answer

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 phone field, 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.

QUICK CHECK

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?

Choose one answer