skip to content

HTTP Verbs and Status Codes

Choosing verbs and status codes as a deliberate API contract rather than reciting the spec: which verb an operation deserves, PUT versus PATCH versus POST, promising idempotency, and picking a code for a real scenario. Interviewers ask because the same HTTP knowledge looks different when you are the one designing the endpoint.

part ofAPI stylesoverview, primer and where to startread it →
on this pageshow

questions

22

In an HTTP API contract, what is the difference between a method being safe and being idempotent, and which of GET, POST, PUT, PATCH and DELETE are which?

level: juniorimportance: must knowfreq 70%

answer

  1. safe = read-only (GET, HEAD, OPTIONS)
  2. idempotent = same state after N calls (GET, HEAD, PUT, DELETE)
  3. safe implies idempotent, never the reverse
  4. POST and PATCH: neither by default
  5. state, not status code: DELETE gives 204 then 404 and is still idempotent

basics

~20 s

Safe means the request does not change server state - GET and HEAD. Idempotent means doing it N times leaves the same state as doing it once - GET, HEAD, PUT and DELETE. POST and PATCH are neither by default. Safe implies idempotent.

solid answer

~50 s

Two separate promises the API makes about a method. - **Safe**: the request is read-only; it must not modify server state. GET, HEAD and OPTIONS. Anything safe is automatically idempotent, since it changes nothing. - **Idempotent**: applying the request once or many times leaves the resource in the same state. GET, HEAD, PUT and DELETE. - **Neither by default**: POST and PATCH. `POST /orders` twice creates two orders; a PATCH body like `{"op":"increment","amount":1}` applies twice. Two clarifications interviewers look for. First, idempotency is about **resulting state, not the response**: `DELETE /orders/42` returns 204 then 404, but the state - order gone - is identical, so it is still idempotent. Second, these are **contract promises, not enforcement**. HTTP cannot stop you writing a GET handler that charges a card; it just means every cache, crawler and retry layer will now do the wrong thing, because they all trust the declaration.

code

http · 7 lines
http
DELETE /orders/42 HTTP/1.1

HTTP/1.1 204 No Content

DELETE /orders/42 HTTP/1.1

HTTP/1.1 404 Not Found

go deeper

for a junior

Give the two definitions crisply and classify the five methods correctly; that alone is a pass.

for a middle

Add that idempotency is about resulting state rather than response status, and explain why PUT's full-representation semantics make it repeatable.

for a senior

Emphasise that these are declarations infrastructure acts on - caches, prefetchers, retrying proxies - so violating them is an operational hazard, not a style issue.

for a principal

Position them as the contract that lets generic intermediaries and client retry policies exist at all, and discuss what breaks system-wide when a handler lies about its method's properties.

## Two distinct promises **Safe** means the method is essentially read-only: issuing the request should not change observable server state. GET, HEAD and OPTIONS are safe. "Essentially" allows harmless byproducts - access logs, hit counters, cache warming - because the *client* is not asking for a change. **Idempotent** means the effect on server state of N identical requests (N greater than or equal to 1) is the same as that of one request. GET, HEAD, OPTIONS, PUT and DELETE are idempotent. POST and PATCH are not, by definition of the method. Safe implies idempotent: a request that changes nothing trivially leaves the same state however many times you send it. The reverse does not hold - DELETE is idempotent but very much not safe. ## Method by method **GET / HEAD** - safe and idempotent. Read the resource; HEAD returns headers only. **PUT** - idempotent, not safe. PUT carries the complete intended representation: "make the resource at this URL look like this". Sending it five times leaves the resource in exactly the state the body describes. The result does not depend on the prior state, which is precisely why repetition is harmless. **DELETE** - idempotent, not safe. After the first successful delete the resource is gone; further deletes cannot remove it more thoroughly. The end state - absent - is stable. **POST** - neither. POST means "process this payload according to the resource's own semantics", and the usual semantics is to create something new or run an action. `POST /orders` twice yields two orders. That is not a flaw; it is what the method promises. **PATCH** - not idempotent in general. It carries a *modification*, and whether repeating a modification is harmless depends entirely on the patch. `{"status":"SHIPPED"}` happens to be repeatable; `{"op":"increment","path":"/qty","value":1}` is not. Because it is not guaranteed, the specification declines to declare PATCH idempotent, and infrastructure must assume it is not. ## The definition is about state, not the response The most common misunderstanding. `DELETE /orders/42` returns 204 the first time and 404 the second. Different status codes - identical resulting state. The method is idempotent. Likewise a PUT may return 201 on first call and 200 afterwards. Idempotency constrains the **effect**, never the response body or status. ## They are promises, not enforcement Nothing in HTTP prevents you writing `GET /orders/42/cancel` that cancels an order. The protocol will not stop you - but the entire ecosystem is built on trusting the declaration: - **Caches** may store and replay GET responses without contacting your server. - **Crawlers, prefetchers and link scanners** follow GET links freely; the historic case of a web accelerator following GET-based "delete" links and wiping a CMS is the standard cautionary tale. - **Proxies, load balancers and HTTP client libraries** retry idempotent methods automatically on connection failures and timeouts. So a state-changing GET is not a style violation - it is a live production hazard, because generic infrastructure will exercise it. ## How to say it in an interview Give both definitions in one sentence each, list which methods fall where, then volunteer the two clarifications: idempotency is about resulting state rather than the response, and these are contractual declarations that infrastructure trusts rather than behaviours the protocol enforces. That last point is what separates a recited answer from an understood one.

  • Is PATCH idempotent?
    Not in general, so infrastructure must assume it is not. A PATCH body that sets an absolute value, such as `{"status":"SHIPPED"}`, happens to be repeatable, but one expressing a relative change, such as incrementing a quantity, is not. Because the guarantee depends on the payload rather than the method, HTTP does not declare PATCH idempotent.
  • What is wrong with a GET endpoint that deletes a resource, given it works when you test it?
    Every generic HTTP participant assumes GET is safe. Shared caches may serve and replay it, prefetchers and crawlers will follow the link unprompted, and clients or proxies retry it on failure. The endpoint will be triggered without any user intent, which is how link-prefetching agents have historically wiped data through GET-based delete links.

saying these in an interview costs you the question

  • Saying idempotent means 'returns the same response every time' rather than leaves the same state
  • Claiming DELETE is not idempotent because the second call returns 404
  • Calling GET idempotent but not safe, or confusing the two terms
  • Asserting PATCH is idempotent because a particular PATCH body happens to be repeatable
  • Believing HTTP enforces these properties rather than the handler having to honour them

context

open as a page

When you design a write endpoint in an HTTP API, how do you choose between the PUT, PATCH and POST methods, and what does each one promise the client?

level: juniorimportance: must knowfreq 82%

basics

~20 s

POST creates a resource or runs a process; the server picks the URL and repeating it repeats the effect. PUT sends the complete new representation to a URL you already know; repeating it is harmless. PATCH sends only the fields to change.

open as a page

You are specifying the successful responses for create, update and delete endpoints in an HTTP API. How do you choose between status 200, 201 with a Location header, and 204, and when would you return a body at all?

level: juniorimportance: must knowfreq 74%

basics

~20 s

201 plus a Location header when the request created a new resource; 200 with a body when you have something useful to return; 204 when the operation succeeded and there is genuinely nothing to send. Deletes typically return 204.

open as a page

Why can a client safely retry an HTTP PUT or DELETE after a timeout, but not a bare POST? Explain what actually goes wrong.

level: middleimportance: must knowfreq 65%

basics

~20 s

A timeout hides whether the server applied the request. PUT and DELETE describe an end state, so reapplying converges to the same result. POST creates something new each time, so a retry after a lost response creates a duplicate.

open as a page

Your API lets clients create resources with HTTP PUT to a URL they choose, instead of POSTing to a collection. What does that buy you, what identifier scheme does it require, and what should the server return?

level: middleimportance: must knowfreq 62%

basics

~20 s

PUT-as-upsert makes creation idempotent: the client generates the id (usually a UUID), so a retried request lands on the same URL and cannot create a duplicate. Return 201 when it created, 200 or 204 when it replaced.

open as a page

A request to your API is syntactically valid JSON but fails a business rule — for example an end date before the start date. Would you answer with HTTP status 400 or 422, and how do you draw the line between them in a contract?

level: middleimportance: must knowfreq 56%

basics

~20 s

400 for a request the server cannot parse or that is malformed — bad JSON, wrong type, missing required field. 422 for a well-formed request whose content violates semantic rules. Both are client errors; consistency and a machine-readable error body matter more than the choice.

open as a page

How do you decide between HTTP status 401, 403 and 404 when a caller is refused, and when would you deliberately return 404 for something that exists but the caller may not see?

level: middleimportance: must knowfreq 64%

basics

~20 s

401 means "I don't know who you are — authenticate" and must carry WWW-Authenticate. 403 means "I know who you are and you still may not". 404 hides existence: return it instead of 403 when merely confirming a resource exists leaks information.

open as a page

A search endpoint needs a complex filter object that no longer fits comfortably in a query string. Would you keep it as an HTTP GET or switch to POST, and what do you lose either way?

level: middleimportance: must knowfreq 52%

basics

~20 s

GET keeps the search cacheable, linkable and obviously read-only, but URL length limits and logging of query strings constrain it. POST allows an arbitrary JSON filter body but is not cacheable or safe by default, so it hides a read behind a write method. The proposed QUERY method exists to close that gap.

open as a page

A batch endpoint processes 100 items and 3 of them fail validation. How do you report that over HTTP - what does status 207 Multi-Status mean, and when would you return a plain 200 with a per-item status array instead?

level: seniorimportance: must knowfreq 50%

basics

~20 s

Never a bare 200 or a bare 400 - both lie. Return one overall status plus a per-item result array where each entry carries its own status and error. 207 Multi-Status signals mixed outcomes explicitly; a plain 200 with the same array is the pragmatic, better-supported alternative.

open as a page

What do proxies, message queues and SDK retry policies assume about HTTP method idempotency, and how does that break an API that exposes state-changing operations as POST?

level: seniorimportance: must knowfreq 50%

basics

~20 s

They assume the method declaration is true: GET/PUT/DELETE are replayable, POST is not. Queues add at-least-once delivery, so any POST-shaped consumer duplicates. The result is duplicate writes appearing under load or partial failure, with no single component at fault.

open as a page

You need an HTTP API endpoint that creates or updates several hundred records in one request. How would you shape the URL, the method and the payload, and what limits would you put in the contract?

level: middleimportance: should knowfreq 45%

basics

~20 s

POST to a dedicated collection-level URL such as /orders:batchCreate or /orders/batch with an array of items, each carrying a client-supplied id so results can be correlated. Publish a hard item limit, a body size limit, and a documented failure mode.

open as a page

Two standard patch formats exist for HTTP PATCH bodies: JSON Merge Patch (RFC 7386) and JSON Patch (RFC 6902). How do they differ, and how would you decide which one an API should accept?

level: middleimportance: should knowfreq 48%

basics

~20 s

JSON Merge Patch is a partial object: present fields are set, null deletes a field, arrays are replaced wholesale. JSON Patch is a list of operations (add/remove/replace/move/copy/test) with JSON Pointer paths, so it can edit array elements and assert preconditions — at the cost of verbosity.

open as a page

An API operation cannot finish within the request — it kicks off a video encode that takes minutes. How would you design the response contract around HTTP status 202 Accepted, and what must the client be able to do afterwards?

level: middleimportance: should knowfreq 40%

basics

~20 s

Return 202 Accepted with a pointer to a job or status resource (Location or a body link). The client polls that resource, which reports pending/running/succeeded/failed and links to the result. 202 means accepted for processing, not done and not guaranteed to succeed.

open as a page

Your domain has operations that are not create/read/update/delete — cancel an order, resend an invitation, retry a failed payment. How do you fit them into an HTTP API contract, and which method do you choose?

level: middleimportance: should knowfreq 50%

basics

~20 s

Use POST on an action sub-resource, such as POST /orders/42/cancel — POST covers any processing, not just creation. Alternatively model the outcome as a resource (POST /orders/42/cancellations) or as a state field changed by PATCH. Never put the action on GET.

open as a page

What decisions does an API contract have to make about HTTP DELETE — repeated deletes, soft deletes, cascades, and whether the request may carry a body?

level: middleimportance: should knowfreq 42%

basics

~20 s

Decide what DELETE returns when the resource is already gone (204 or 404 — pick one), whether it soft-deletes or truly removes, what happens to dependent resources, and whether it is asynchronous. Avoid a request body: DELETE bodies have no defined meaning and intermediaries may drop them.

open as a page

A team exposes only HTTP PUT for updates, and each client sends the full resource representation it knows about. What goes wrong as the schema evolves and multiple clients write concurrently, and how would you fix the contract?

level: seniorimportance: should knowfreq 38%

basics

~20 s

Clients built against an older schema omit newer fields, so every PUT silently deletes them; and read-modify-write races mean the last writer clobbers concurrent edits it never saw. Fix with PATCH for partial edits, ETag plus If-Match for conflict detection, and explicit read-only field rules.

open as a page

In a partial-update API, a client sends a JSON body where a field is missing versus present with the value null. Why does that distinction matter, and how do you handle it on the server?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Missing means "leave it alone"; null usually means "clear it". Most JSON binders collapse both to a null field, so the server cannot tell them apart and silently wipes data. Fix it by parsing into a tri-state (absent / null / value) or a raw node.

open as a page

When is HTTP status 409 Conflict the right answer in an API contract, and how does it differ from 422 and from 412 Precondition Failed?

level: seniorimportance: should knowfreq 42%

basics

~20 s

409 means the request is valid in itself but clashes with the resource's current state — a duplicate unique key, an illegal state transition, a concurrent edit. 422 means the request is invalid on its own terms; 412 means an explicit precondition header the client sent did not hold.

open as a page

Your service is overloaded and starts shedding traffic. How do you decide between HTTP status 429, 503 and 500 for those responses, and what do the codes tell a client to do?

level: seniorimportance: should knowfreq 48%

basics

~20 s

429 means this caller exceeded its rate or quota — retry after backing off. 503 means the service as a whole is unavailable or overloaded — retry later, ideally per Retry-After. 500 means an unexpected bug; retrying probably will not help and it should page someone.

open as a page

You inherit an HTTP API whose mutations are exposed as GET — for example `GET /orders/42/cancel` and `GET /users/9/delete?confirm=true`. Why is that a contract defect, and how would you redesign those routes and migrate existing callers off them?

level: seniorimportance: should knowfreq 52%

basics

~20 s

The verb lives in the path, not in the method, so the contract misdeclares what the request does. Redesign as DELETE /users/9 and POST /orders/42/cancel (or a cancellation sub-resource). Retire the old GETs with HTTP 405 plus an Allow header after a deprecation window.

open as a page

For a bulk-write API endpoint, would you promise all-or-nothing atomicity or best-effort per-item processing? Argue the tradeoff and say how you would express the choice in the contract.

level: principalimportance: should knowfreq 30%

basics

~20 s

Default to best-effort with per-item results: it scales, degrades gracefully and matches how callers actually recover. Offer atomicity only for small batches within one datastore, as an explicit opt-in flag, and reject batches too large to hold in one transaction.

open as a page

Some APIs accept an X-HTTP-Method-Override header (or a _method form field) so a POST can be treated as PUT, PATCH or DELETE. When is that justified, and what risks does it introduce?

level: seniorimportance: nice to knowfreq 26%

basics

~20 s

It exists for clients or intermediaries that cannot send PUT, PATCH or DELETE — old HTML forms, restrictive proxies, some corporate firewalls. The risk is that security controls keyed on the real method (WAF rules, CSRF exemptions, method-based authorization, gateway policy) see a POST while the application performs a delete.

open as a page