LevelUpWith

Explore / REST APIs: Design, Build, Document and Test / Lesson 2

Lesson 2: HTTP Methods, Safety and Idempotency

Understand what GET, POST, PUT, PATCH and DELETE are meant to do, and which methods are safe or idempotent so clients and proxies know when a request can be retried.

Free to read, no account needed. Part of REST APIs: Design, Build, Document and Test.

By the end of this level you'll be able to

  • Pick the right method for reading, creating, replacing, partly updating and deleting a resource
  • Say which methods RFC 9110 defines as safe and which as idempotent, and why that decides whether a retry is harmless
  • Show with curl against a test API that repeating a PUT leaves the same result while repeating a POST creates duplicates

Why the method matters more than you think

In Level 1 you saw that every HTTP request starts with a method: GET /books/1 HTTP/1.1. The method looks like a label, but clients, proxies, browsers and retry libraries all read it as a promise about what the request will do.

That promise matters because networks fail. Say your app sends a request, the connection drops, and no response comes back. Did the server act on the request or not? You can't tell. Whether it's safe to send the request again depends on the method. Pick the wrong one and a retry can charge a customer twice.

The five everyday methods

Think of a library catalogue:

Method Meaning Library analogy
GET /books/1 Read a resource Look up a catalogue card
POST /books Create a new item in a collection (or run a server-defined action) Hand the librarian a new book; they assign the shelf number
PUT /books/1 Replace the resource at this URL with what I send Swap the whole card for a new one
PATCH /books/1 Change part of the resource Correct one line on the card
DELETE /books/1 Remove the resource Throw the card away

Notice who chooses the URL. With POST you send to a collection and the server picks the new item's id. With PUT you name the exact URL yourself, and the server makes that resource match what you sent.

Safe and idempotent: the two properties RFC 9110

RFC 9110 (HTTP Semantics) defines two properties.

Safe means the method is intended only to retrieve information and should not change server state. The safe methods are GET, HEAD, OPTIONS and TRACE.

Idempotent means making the same request once or many times has the same intended effect as making it once. The idempotent methods are PUT and DELETE, plus all the safe methods.

POST is neither. PATCH is defined in its own RFC (RFC 5789), which says plainly that PATCH is "neither safe nor idempotent". A patch such as "append this tag" or "add 1 to stock" gives a different result every time you repeat it.

Method Safe? Idempotent?
GET, HEAD, OPTIONS ✅ ✅
PUT ❌ ✅
DELETE ❌ ✅
POST ❌ ❌
PATCH ❌ ❌ (not guaranteed)

Gotcha: idempotent is about the effect, not the response. The first DELETE /books/1 removes the book. The second finds nothing to remove and may get a different response. The state is the same either way: the book is gone. That's what counts.

Gotcha: "safe" is a promise you keep. Nothing stops you writing GET /books/1/delete. Crawlers, link prefetchers and caches assume GET is harmless, so sooner or later one of them will "click" it. Never change state on a GET.

This is why idempotency decides retries. RFC 9110 allows clients to retry idempotent requests automatically after a connection failure, because a repeat can't cause extra harm. A client should not retry a POST automatically unless it has some other way to know the first one didn't take effect. A common pattern is an Idempotency-Key header: the client sends a unique key with the POST and the server ignores repeats that carry the same key. That header is still an IETF draft, not a finished standard, but many payment APIs use the idea.

Hands-on: prove it with curl

We'll use json-server, a small Node tool that turns a JSON file into a REST API you can write to. You need Node.js installed.

# 1. Create a data file with one book
echo '{ "books": [ { "id": "1", "title": "Dune", "stock": 3 } ] }' > db.json

# 2. Start the API (serves http://localhost:3000 and saves changes back to db.json)
npx json-server db.json

In a second terminal:

Repeat a PUT three times

# Replace book 1 completely. Run this exact command three times.
curl -X PUT http://localhost:3000/books/1 \
  -H "Content-Type: application/json" \
  -d '{"title": "Dune (2nd ed.)", "stock": 5}'
{ "id": "1", "title": "Dune (2nd ed.)", "stock": 5 }

Check the collection:

curl http://localhost:3000/books

You still have one book with the same content. Three PUTs had the same effect as one.

Repeat a POST three times

# Create a new book. Run this exact command three times.
curl -X POST http://localhost:3000/books \
  -H "Content-Type: application/json" \
  -d '{"title": "Neuromancer", "stock": 2}'

Each response has a different auto-generated id. json-server's ids are short random strings, so yours will differ from these:

{ "id": "a3f9", "title": "Neuromancer", "stock": 2 }
curl http://localhost:3000/books   # now 4 books: Dune + three Neuromancers

That's the duplicate-order bug in miniature. If a retry library had resent this POST after a timeout, you'd have the same mess.

PUT replaces, PATCH changes part

# PATCH sends only the field that changes; title is kept
curl -X PATCH http://localhost:3000/books/1 \
  -H "Content-Type: application/json" -d '{"stock": 9}'

# PUT sends a full replacement. Leave out a field and expect it to be gone
curl -X PUT http://localhost:3000/books/1 \
  -H "Content-Type: application/json" -d '{"stock": 1}'
curl http://localhost:3000/books/1   # title has disappeared

Pitfall: using PUT for partial updates is a classic bug. A client that sends only the changed fields with PUT quietly wipes everything else. Partial update? Use PATCH.

Check your results

  • After the PUT runs: GET /books shows exactly one Dune.
  • After the POST runs: three Neuromancer entries with three different ids.
  • After the last PUT: book 1 has stock but no title.
  • Open db.json: it matches what the API returns.

Key takeaways

  • GET reads, POST creates in a collection (the server picks the id), PUT replaces at a URL you name, PATCH changes part of a resource, DELETE removes it.
  • RFC 9110: safe = GET, HEAD, OPTIONS, TRACE. Idempotent = those plus PUT and DELETE.
  • POST and PATCH are not idempotent, so don't retry them blindly. An idempotency key is the usual fix.
  • Idempotency is about the effect on server state, not about getting an identical response.
  • Never change state with GET. Crawlers, prefetchers and caches assume it's harmless.

A 6-question knowledge check follows this lesson in the app, free and without an account.

Keep going: levels 3 and 4 are free

Create a free account to open the next two levels, save your progress and pick up where you left off. No card needed.

Next: Level 3, Status Codes That Tell the Truth.

Create a free account →See the whole course

More like this

  • GitHub Copilot (GH-300) Exam Prep

    Learn GitHub Copilot hands-on in the editor, in the CLI and on github.com, and work through every skill in the GH-300 study guide (skills measured as of August…

    Exam prep · GH-300 · Software & Engineering · Capable · 18 levels · 4 free · Professionally curated by levelupwith.com

  • Scaling Apps Beyond the Chat Window: Part 3, Mobile Apps, Games and Growth

    Turn your first live app into a real product. Learn to choose between web and app store apps, publish a browser game, take payments safely, run and monitor a l…

    Course · Software · Software & Engineering · Capable · 24 levels · 4 free · Professionally curated by levelupwith.com

  • Scaling Apps Beyond the Chat Window: Part 2, Online, Secure and AI-Powered

    Take one small app from your GitHub repository to a public web address. You will host it on Vercel and give it a Supabase database, sign-in and file storage, w…

    Course · Software · Software & Engineering · Capable · 16 levels · 4 free · Professionally curated by levelupwith.com

  • Scaling Apps Beyond the Chat Window: Part 1, From Prompt to Project

    Move an app you built in an AI chat onto your own computer and work on it step by step with a coding agent. Save your work with Git, keep secrets out of your c…

    Course · Software · Software & Engineering · Capable · 19 levels · 4 free · Professionally curated by levelupwith.com

  • Right Chip, Right Job: CPUs, GPUs, TPUs and Beyond

    Profile a workload, place it on a roofline and pick the processor that actually suits it, whether CPU, GPU, TPU, ASIC, inference chip, NPU, FPGA or DPU. You wi…

    Beyond the Obvious · Software & Engineering · Expert · 61 levels · 4 free · Professionally curated by levelupwith.com

  • Build Your First Website with HTML and CSS

    Start from a blank file and build a real, accessible personal or small-business website that works on phones. Each level adds to the same site, covering semant…

    Course · Software · Software & Engineering · Capable · 18 levels · 4 free · Professionally curated by levelupwith.com