The Idempotency Trap

Jul 1, 2014

I just fell into the idempotency trap!

As you may or may not know, one reason HTTP methods exist (GET, POST, PUT, and DELETE being the most prevalent) is because different HTTP methods signal different expectations with regard to what sorts of side-effects a request will cause. GET, PUT, and DELETE are idempotent, which is to say that issuing the same GET, PUT, or DELETE request a jillionty times in a row should have the same observable side-effects as issuing it once. GET is special in that it should be safe: it should not generate any side-effects observable to the client (if this is the case, it is trivially idempotent).

The idempotency trap is when one uses GET as a primary frame of reference for what constitutes idempotency, and confuses safety with idempotency. In the case of the linked PR comment, were an admin to issue the same request to combine two organizations twice, the second one would fail, but that doesn’t mean it’s not idempotent! It just means it’s not safe. Reading through the OrganizationController’s combine method suffices to verify that it is indeed idempotent.

I’d recommend not using GET as a frame of reference for examples of idempotency. Instead, use DELETE. It’s not too surprising that deleting, say, the same Checklist item twice may cause an error, but it’s clear that in a well-behaved system, issuing two such requests would only delete that one item.

To close, I should emphasize that these method types are merely signals. Just because a server implements a given endpoint using an idempotent HTTP method makes no guarantees about its idempotency or safety. Just because there’s a URL that responds to DELETE requests does not mean that anything’s being deleted. Cruel and/or misinformed server developers can do whatever they want.

This post is a flapjack, which means I originally wrote it for the internal FullStack blog and have republished it here. Any mysterious, unexplained context was probably obvious to the team at the time.