Topic 32

Retrying Safely

Errors

Vera is rehearsing in the sandbox and sends the POST that reserves bike bk_0977 at Old Market — and nothing comes back. The terminal waits, then times out. Her finger goes to the up-arrow key to bring the command back and send it again — and stops there, because she has just realized she does not know whether the first attempt reserved the bike or not. This page is about that exact hover.

Two things in your house answer this question for you. Hold a light switch down all day and the lamp is simply on; pressing it again changes nothing that was not already changed. Press a doorbell a second time "just to be sure" and somebody comes to the door twice. Requests come in both kinds, and knowing which one your finger is on — before you press again — is the whole of this topic.

The hover moment, decided in four lines
A timeout on a GET, PUT or DELETERetry it, spaced out
A timeout on a POSTDo not resend — go and look first
The look shows attempt one landedYou are done; keep the id
The look shows nothing was createdSend it once more, key if offered

The Verb Answers First

Chapter 2 sorted the verbs by intention, and that sorting turns out to have been about money all along. A GET asks a question; asking twice gets you the same answer twice and changes nothing in the world. A PUT sets a resource to exactly the value you supply, so setting it to the same value again lands you where you already were. A DELETE removes something, and removing an already-removed thing leaves it removed.

POST is the odd one out, because POST creates. Sending it again does not repeat a fact, it manufactures a second thing. Two reservations, two orders, two emails. The verb you used is therefore the first question to ask when a request dies without answering, and most of the time it settles the matter on its own.

The Word for It: Idempotent

The profession has a word for the light-switch property, and it is worth owning because you will meet it in documentation constantly. An action is idempotent when repeating it changes nothing after the first time. Flipping a switch to on is idempotent; ringing a doorbell is not.

GET, PUT and DELETE are idempotent by design, and the people who wrote the rules of HTTP intended them that way. POST is deliberately not. From here on the book uses the real word, and so should you — "is this endpoint idempotent?" is a short question that saves long conversations.

After the Ambiguous POST, Look

So the timeout hit a POST. Do not resend it. Instead go and find out what actually happened, using the safest thing you own: a question. Vera asks Tandem for any reservations attached to bike bk_0977, and the answer settles it in one line.

Check before you act — one GET that answers "did attempt one land?"
curl -i -H "Authorization: Bearer tnd_test_..." \
  "https://sandbox.api.tandem.example/v1/reservations?bike_id=bk_0977"

HTTP/1.1 200 OK
Content-Type: application/json

{"data": [{"id": "res_3f81", "bike_id": "bk_0977",
           "station_id": "st_014", "status": "active"}]}

The reservation is there, and it is res_3f81 — the same sandbox id from Chapter 3, which means the first attempt succeeded and only its answer was lost on the way back. Vera has nothing left to do but keep the id. Had the list come back empty, she would have known the attempt never landed, and could have sent it once more with a clear conscience.

Look before you act. It costs one harmless request and it replaces a guess with a fact, which is the trade this entire book keeps recommending.

How Grown-Up APIs Solve It

Some APIs offer a better tool, and you should recognize it when the documentation hands it to you. The idea is called an idempotency key: a value you invent yourself and attach to a creating request, unique to that one attempt. If the same key arrives twice, the server understands that this is a repeat of a single attempt rather than a second attempt, and returns the original result instead of creating a duplicate.

That turns a doorbell back into a light switch, and it means a lost answer can be safely re-sent. You will find it in the reference page for the endpoint, usually as an optional header, and using it costs you nothing but the discipline of generating a fresh value per real attempt. Designing such a system is a builder's job and lives in a different book; recognizing the offer, and taking it, is squarely yours.

Common Confusions
  • "The request failed, so nothing happened." The response failed to arrive. The action's fate is a separate question with three possible answers, and that gap between the two is the entire reason this page exists.
  • "Idempotency is server magic I can safely ignore." It is a contract you take part in: idempotent verbs you may repeat freely, POST you check on first, and idempotency keys you supply whenever the documentation offers them.
  • "Two reservations is a minor annoyance at worst." Substitute payments, orders, or notification emails and the same double-send becomes a real incident. Chapter 3 let you make that mistake in a sandbox precisely so it would cost nothing there.
  • "If GET is safe to repeat, retrying it endlessly is fine." Repeating a GET is harmless to the data but not to the service, and rate limits count every attempt. Space the retries out, as the previous page insisted.
Why It Matters
  • Retry, check, or stop is the highest-stakes judgment an API consumer makes routinely, and it usually has to be made in a hurry. Having the answer scripted in advance is worth more than any amount of care in the moment.
  • "Is this endpoint idempotent, and does it take an idempotency key?" are the two questions a colleague who has been burned once always asks.

Knowledge Check

Which request is the dangerous one to blindly repeat after a timeout?

  • A GET, because each request costs the provider real money to answer
  • A POST, because repeating it creates a second thing, not a repeat
  • A PUT, because sending it twice applies the change twice over
  • A DELETE, because the second attempt removes a second resource

What does it mean that an action is idempotent?

  • Repeating it is faster the second time, since the server has cached the work
  • It never changes anything at all, which is why it is always safe to send
  • Repeating it changes nothing, because the first time already did the work
  • It can be undone afterwards by sending the opposite request to the same address

A POST that reserves a bike times out. What is the correct next move?

  • Send the identical POST again straight away, before the bike is taken
  • Send a GET for reservations on that bike and see what exists
  • Wait an hour and assume the reservation went through successfully
  • Email the provider to ask whether the reservation was created

What does an idempotency key let you do?

  • Authenticate a creating request without sending your credentials with it
  • Resend a creating request without any risk of creating a duplicate
  • Cancel the first attempt so the second one can safely take its place
  • Send requests past your rate limit, since repeats no longer count

You got correct