Unit 03.00: Methods, and what each one promises
Each HTTP method carries promises, and something on the internet will rely on them without asking you.
Safe and idempotent
Five methods with what each means and what it promises.
The code lists them.
METHODS = [
("GET", "read", "safe, idempotent, cacheable"),
("POST", "create or act", "neither safe nor idempotent"),
("PUT", "replace entirely", "idempotent -- same result if repeated"),
("PATCH", "modify partially", "not necessarily idempotent"),
("DELETE", "remove", "idempotent -- gone stays gone"),
]
print(f"{'method':8} {'means':18} promises")
for method, means, promises in METHODS:
print(f"{method:8} {means:18} {promises}")
print("""
"Safe" means it changes nothing, so a crawler or a prefetcher may call it
freely. "Idempotent" means calling it twice leaves the same state as calling
it once, which is what makes a client retry safe.
A GET that changes something breaks both promises, and something will call it
without asking you.
""")
"Safe" means it changes nothing, so a crawler, a prefetcher or a browser extension may call it freely. "Idempotent" means calling it twice leaves the same state as once, which is what makes a client retry safe.
A GET that changes something breaks both promises. It will be called by something you did not write, at a time you did not choose, and the resulting bug is very hard to attribute.
The mistake this prevents
The mistake is choosing POST for everything because it always works. The method is part of the contract, and a client's retry logic is built on it - using POST for a read means no intermediary can cache it and no client can safely retry.
Takeaway
Methods carry promises about safety and idempotency. A GET that changes state will be triggered by something you did not write.
