Chapter 5: HTTP Methods Beyond Reading Data
1. Beyond read-only APIs
In this chapter you'll learn to write to APIs as well as read from them -- creating users with POST, updating them with PUT, removing them with DELETE, and combining all four methods into full CRUD flows. By the end you'll have the same defensive patterns from Chapter 4 applied to every method, plus the judgment to pick the right one for the job.
Chapters 3 and 4 taught you to read. Reading is only a quarter of what real applications do; the other three quarters are what this chapter unlocks.
Think of HTTP methods as verbs in a conversation with a server. GET means "show me." POST means "create this." PUT means "replace that." DELETE means "remove this." Learning these four verbs transforms you from someone who can only read APIs into someone who can build interactive applications that actually change data on servers.
There's one important twist compared to Chapter 3: from here on, you'll be using methods that modify data, not just read it. That makes the defensive techniques from Chapter 4 (timeouts, status checks, validation, careful error handling) even more important. When your code creates, updates, or deletes resources, you want to be very sure you know what happened.
- Choose the right HTTP method for a given task and explain why
- Send data with
POSTin both JSON and form-encoded formats - Update existing resources completely using
PUT - Remove resources safely using
DELETE, with clear user feedback - Apply Chapter 4's defensive patterns (timeouts, status checks, validation) to every method
- Handle method-specific errors: validation failures, conflicts, permissions
- Combine all four methods into full CRUD flows
create_user.py— POST with validation, status handling, and structured returnsupdate_user_profile.py— PUT with 404, 409, and 403 branchespost_vs_put.py— a side-by-side of collection vs resource URLsdelete_resource.py— DELETE with 404-as-success and dependency conflictssafe_delete.py— the verify, confirm, delete workflowblog_manager.py— a complete CRUD class tying all four methods together
Why reading data isn't enough
Imagine social media where you could only read posts but never create your own. Email where you could view messages but never reply. Real applications require the ability to create, update, and delete data, and the sections below map out exactly how each method works. For now, the important thing is that every interactive app you've ever used is built on just four operations.
In Chapter 4 you learned the Make → Check → Extract pattern and how to validate responses defensively. Those habits aren't just for GET, they're more critical when your requests modify data. Throughout this chapter you'll see how professional developers apply validation, error handling, and status code checking to POST, PUT, and DELETE operations. We'll keep using httpbin.org, the safe echo service from Chapter 3, so you can experiment without breaking a real system.
CRUD: the vocabulary you'll hear everywhere
Every interactive application, from social media to e-commerce to project management, performs the same four fundamental operations on data: creating new items, reading existing items, updating current items, and deleting old items. HTTP provides specific methods for each. The mapping is so standard that once you know it, you can predict how almost any REST API will work:
| CRUD operation | HTTP method | What it does | Example |
|---|---|---|---|
| Create | POST |
Make a new resource | Register a new user account |
| Read | GET |
Retrieve existing data | Load user profile information |
| Update | PUT |
Replace an entire resource | Update a complete user profile |
| Delete | DELETE |
Remove a resource | Delete a user account |
CRUD → HTTP is the one table in this chapter worth committing to memory. It shows up in job descriptions ("experience with CRUD APIs"), in API documentation, in code review comments, and in every REST API you'll ever touch. Once the mapping clicks, new APIs stop feeling like strangers, they're just variations on a vocabulary you already speak.
HTTP method characteristics
Each method has specific characteristics that determine how it should be used and what behaviour to expect. These characteristics matter because they affect how you write error handling, when you can safely retry a request, and what "success" looks like.
| Method | CRUD | Sends data? | Modifies server? | Idempotent? | Success codes |
|---|---|---|---|---|---|
GET |
Read | No (URL only) | No | Yes | 200 OK |
POST |
Create | Yes (body) | Yes | No | 200 OK, 201 Created |
PUT |
Update | Yes (body) | Yes | Yes | 200 OK, 204 No Content |
DELETE |
Delete | Optional | Yes | Yes | 200 OK, 204 No Content |
Two columns in that table deserve closer attention: whether a method modifies the server (which determines risk level) and whether it's idempotent (which affects retry safety). Both show up in the rest of the chapter, so let's pin down what they mean.
Safe vs unsafe methods
HTTP classifies methods by whether they change server state. Safe methods (GET) read without modifying anything, so you can call them repeatedly with no side effects. Because a GET is safe and idempotent, a client can retry one after a network hiccup without risking duplicate side effects, which is exactly why retry logic (the kind you build in this chapter) leans on it. Unsafe methods (POST, PUT, DELETE) change server state by creating, modifying, or removing data. These need more careful handling because a failure might leave data in an inconsistent state, or create a partially-completed operation that nobody knows about.
Understanding idempotency
Idempotency is a word that gets thrown around in API design, and it's simpler than it sounds. An operation is idempotent if calling it multiple times with the same data produces the same result as calling it once. That single property determines whether it's safe to automatically retry a failed request.
Imagine your request times out and you don't know whether it succeeded. Can you safely retry? The answer depends on idempotency:
- GET is idempotent, safe to retry. Requesting the same data 100 times returns the same data 100 times. No harm done.
- POST is NOT idempotent, dangerous to retry. Sending the same POST twice creates two resources. A timed-out "create user" request that gets blindly retried might produce duplicate accounts.
- PUT is idempotent, safe to retry. Replacing a resource with the same data multiple times leaves it in the same final state. If a PUT times out, retrying is safe.
- DELETE is idempotent, safe to retry. Deleting a resource once or ten times produces the same outcome: the resource is gone. The first DELETE succeeds (200 or 204), later ones return 404, but the goal is achieved either way.
Network issues are constant in production. Requests time out, connections drop, packets get lost. Idempotent operations (GET, PUT, DELETE) can be safely retried by automated systems, worst case, you do the same thing twice. Non-idempotent operations (POST) need special handling: checking whether the first attempt succeeded before retrying, or using unique request IDs so the server can recognise a duplicate. Professional retry logic is built around idempotency.
A quick method-selection guide
When working with any API, use this decision framework to pick the right method:
- Are you changing anything on the server? No → use
GETto read, search, or download. Yes → continue. - Are you creating something new? Yes → use
POST. No → continue. - Are you updating an existing resource? Yes → use
PUTfor whole-resource updates, or PATCH for partial updates if your API supports it. No → continue. - Are you removing something? Yes → use
DELETE. No → review the operation; you may need POST for complex actions that don't fit the CRUD shape.
The rest of this chapter explores each method in detail, showing both the bare-bones "here's how to call it" version and the professional pattern with defensive error handling. We'll start with POST, because creating things is where most real work begins.