Why Idempotency Matters: Designing Safe Backend APIs
This article explains the concept of API idempotency, when it should be applied, practical design patterns—including database checks, unique transaction IDs, and Snowflake ID generation—and the core principles for balancing reliability and cost in backend services.
Preface
Hello, I’m Tianlu. I recently interviewed a Java developer with ten years of experience who didn’t know how to design idempotent interfaces. In this article we discuss a crucial backend principle—API idempotency—and which interfaces actually need idempotent handling.
Should every interface be made idempotent? Should every data‑changing interface be idempotent?
Obviously not. We must consider business scenarios, data importance, and recovery difficulty to decide whether idempotent design is necessary and avoid over‑engineering.
What is API idempotency?
Which interfaces must be idempotent?
Which interfaces can optionally skip idempotency?
General solution: how to design an idempotent API?
How to generate distributed unique IDs for idempotency?
Core principles of idempotent design.
1. What Is API Idempotency?
Idempotency is a concept from mathematics and computer science. In mathematics, a function is idempotent if applying it multiple times yields the same result, e.g., f(x) = f(f(x)) or abs(x) = abs(abs(x)). In computing, an operation is idempotent when one or many requests produce the same side effects as a single request.
For example, if you call a downstream transfer API and the network times out while the transfer actually succeeded, retrying with the same transaction ID without idempotent handling would cause duplicate payments.
2. Which Interfaces Must Be Idempotent
The core criterion is whether repeated calls cause business loss or data anomalies. Typically, financial transactions and order‑related APIs must be idempotent, such as:
Payment interfaces : user payments, refunds, transfers. Without idempotency, duplicate requests can lead to multiple deductions and severe disputes.
Order creation interfaces : repeated submissions can generate duplicate orders, complicating inventory and logistics.
3. Which Interfaces Can Skip Idempotency
Some interfaces have simple business logic, low data importance, and low repeat probability, so the impact of duplication is minimal. Examples include internal OA system approvals where:
The call scope is closed to internal users, reducing repeated external submissions.
Front‑end buttons are disabled after submission, preventing repeats.
Even if duplicates occur, they can be corrected manually or by status checks.
However, this does not mean such interfaces must never be idempotent; simple idempotent solutions (e.g., state‑machine checks) can still be applied.
A status‑sync interface that updates an approval’s state can safely ignore duplicates because the target system can determine whether an update is needed based on “approval ID + current state”.
4. General Solution: Designing an Idempotent API
For critical interfaces like transfers, a common pattern is:
Check the unique transaction number ( bizSeq) in a dedicated sequence table.
If a record exists, treat the request as a duplicate and return success.
If no record exists, attempt an insert. If the insert succeeds, return success; if a primary‑key conflict occurs, catch the exception and also return success.
Flowchart:
Pseudocode:
/**
* Idempotent handling
*/
Rsp idempotent(Request req){
Object requestRecord = selectByBizSeq(bizSeq);
if(requestRecord != null){
// duplicate request
log.info("Duplicate request, return success, bizSeq:{}", bizSeq);
return rsp;
}
try{
insert(req);
}catch(DuplicateKeyException e){
// duplicate request detected by primary‑key conflict
log.info("Primary key conflict, duplicate request, return success, bizSeq:{}", bizSeq);
return rsp;
}
// normal processing
dealRequest(req);
return rsp;
}Why both a select and a try…catch? In high‑concurrency scenarios, two requests may both miss the select and then attempt insert, causing a conflict that the catch block handles.
In practice we often use a unique index (instead of a primary key) to guarantee global uniqueness, typically based on a business transaction number.
5. Generating Distributed Unique IDs for Idempotency
Idempotent designs need globally unique IDs. Options include: UUID – simple but large, random, and non‑incremental.
Snowflake algorithm – 64‑bit IDs composed of a sign bit, 41‑bit timestamp, 10‑bit machine ID, and 12‑bit sequence within the same millisecond.
Snowflake IDs are generated as follows:
Bit 1: sign (0 for positive IDs).
Bits 2‑42: timestamp in milliseconds since a custom epoch.
Bits 43‑52: machine identifier.
Bits 53‑64: per‑machine sequence number.
Other solutions include Baidu’s UidGenerator and Meituan’s Leaf.
6. Core Principles of Idempotent Design
Not every interface needs idempotency. The decision balances business impact against implementation cost:
Core transaction or financial interfaces must be idempotent, preferably using a sequence table to track state.
Simple internal interfaces (e.g., approval flows) can use lightweight or no idempotent handling after evaluating risk.
The ultimate goal is to keep critical interfaces safe while allowing simple interfaces to remain efficient.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
IT Services Circle
Delivering cutting-edge internet insights and practical learning resources. We're a passionate and principled IT media platform.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
