Dev.to WebDev πŸ›  Dev πŸ‘ 0 πŸ“– 3 min read

The app keeps loading. Did my order go through?

The kitchen has your order. Your phone is still waiting. Watch the short illustrated example on LinkedIn. Imagine ordering lunch through an app. You tap Place order, but nothing seems to happen. After a while, you try

The kitchen has your order. Your phone is still waiting.

Watch the short illustrated example on LinkedIn.

Imagine ordering lunch through an app. You tap Place order, but nothing seems to happen. After a while, you try again.

The server may have saved the first order. Its reply just never reached your phone.

From your side, that looks much like an order that failed. You probably aren't thinking about the server. You want to know whether lunch is coming.

What should happen when you try again?

For this example, say the first request created order 041.

If the app sends the same request again, the server needs a way to recognise it. Otherwise, it might create order 042 as well.

Give each order attempt a unique ID before sending it. Keep that ID if you retry, along with the same order details. The server can then check whether it has already handled that attempt.

This ID is often called an idempotency key.

For an API that supports it, a request might look like this:

POST /orders
Idempotency-Key: 9de69b3a-6ca8-4d9d-a62c-cf34ce127487
Content-Type: application/json

{"cartId":"cart-17"}

The server creates order 041. The reply gets lost. The app retries with the same key and cart, and the server returns order 041.

One detail is easy to miss here: a new key on every retry defeats the purpose. The key belongs to the order attempt, not to each network request.

The header alone won't prevent duplicates, either. The server has to support this behaviour.

Before trusting that retry

There are a few things to check on the server.

Keep the key tied to the authenticated caller. If someone sends the same key with different order details, reject the mismatch or follow the API's documented rules.

Two requests can also arrive together. Both must not pass an β€œorder doesn't exist yet” check and create separate orders. The server needs to handle that race, and a crash must not leave it with an order it has forgotten how to recognise.

Check how long the server remembers a key. After that time, the same key may be treated as a new request. A genuinely new order needs its own key.

There is a phone-side detail too. If someone closes the app while it is waiting, the pending attempt ID and order details need to survive that restart if the app will retry them later.

Disabling the button can help with repeated taps. It won't settle what happened to a request whose reply went missing.

A small test worth trying

Let the server create the order, then drop the reply before the app receives it.

Retry with the same key and order details. Check that the server still has one order and returns that order to the app.

Then send two requests with the same key at once. Also try reusing the key with different details. Those are different cases, and passing the first test doesn't prove the others work.

Stripe documents one implementation of idempotent requests. Its rules for stored results, key expiry and concurrent requests are specific to Stripe, so check the API you actually use.

Back at the lunch counter, the person is still looking at their phone. β€œTry again” should be a useful next step, not a decision about whether to risk ordering twice.

πŸ“° Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes β€” full credit and traffic to the original publisher.