HTTP Methods: GET vs POST vs PUT vs PATCH vs DELETE

Published July 25, 2026By Samson PG

Quick answer

GET reads, POST creates, PUT replaces, PATCH updates part of a resource, DELETE removes it. The details that trip people up are safety and idempotency — not the names.

HTTP Status Codes

An HTTP method tells the server what kind of operation a request is. The five you’ll use constantly — GET, POST, PUT, PATCH, DELETE — sound self-explanatory, but two properties underneath them (safety and idempotency) are what actually determine how browsers, proxies, and retry logic are allowed to treat each one. Getting those wrong is a common source of caching bugs, duplicate charges, and flaky retries.

The five methods

Method Purpose Safe? Idempotent? Typical body
GET Read a resource Yes Yes None
POST Create a resource / trigger an action No No Yes
PUT Replace a resource entirely No Yes Yes
PATCH Update part of a resource No No (usually) Yes
DELETE Remove a resource No Yes Usually none

Safe vs idempotent — the part that actually matters

Safe means the request doesn’t change server state — it’s read-only. Only GET (and HEAD, OPTIONS) are safe. This is why browsers pre-fetch links, proxies cache GET responses, and search engine crawlers follow GET links freely but never click a POST button on your behalf.

Idempotent means making the same request multiple times has the same effect as making it once. GET, PUT, and DELETE are idempotent by definition: fetching a resource twice doesn’t change it further, replacing a resource with the same data twice leaves it in the same state, and deleting an already-deleted resource is still “deleted” either way. POST is not idempotent — submitting the same order-creation POST twice creates two orders, which is exactly why browsers warn you before resubmitting a form.

PATCH is usually not idempotent either, depending on what the update describes. PATCH { "views": views + 1 } applied twice increments twice — not idempotent. PATCH { "status": "shipped" } applied twice ends in the same state either time — idempotent in practice, even though the method doesn’t guarantee it.

Why this distinction breaks things when ignored

  • Automatic retries: HTTP clients and proxies are allowed to silently retry a failed idempotent request (network blip, timeout) because doing so twice is harmless. Retrying a non-idempotent POST automatically is not safe — that’s how duplicate orders and double-charges happen when a retry layer doesn’t respect this rule.
  • Caching: only safe methods are cacheable by default. A GET response can sit in a CDN edge cache; a POST response generally can’t (and shouldn’t) be cached the same way.
  • CSRF and browser behavior: browsers only auto-repeat safe requests (prefetching, <link rel=prefetch>, crawler link-following). This is why state-changing actions must never be wired to a GET — a crawler following links could delete data it was only supposed to read.

PUT vs PATCH, specifically

This is the most common real mix-up. PUT replaces the whole resource — you send the complete representation, and anything you omit is treated as removed or reset. PATCH sends only the fields that changed. Using PUT with a partial body is a common bug: fields you didn’t include can get wiped out because the server (correctly, per the PUT contract) treats the request as the full new state.

FAQ

Is POST always non-idempotent?

By definition, yes — POST has no idempotency guarantee, even if a particular API happens to behave idempotently for some request. Don’t rely on that without the API explicitly documenting it (e.g., via an idempotency key).

Can GET have a request body?

Technically the HTTP spec doesn’t forbid it, but it’s unreliable in practice — many servers, proxies, and clients ignore or strip a GET body. Use query parameters for GET, and a real body only on methods designed for one.

What’s the difference between 200 and 201 for a POST that creates something?

201 Created is the more correct response for a successful creation — see the status codes reference for the full breakdown of what each response code should signal back.

← More from the blog

TryDevSnip