Backend Development 36 min read

Designing Robust and Idempotent APIs: Principles and Practices

This article explores essential API design principles—idempotency, robustness, and security—by discussing practical techniques such as request locks, database unique constraints, Redis distributed locks, token‑based authentication, JWT, and defensive coding practices to ensure reliable, safe, and maintainable backend services.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
Designing Robust and Idempotent APIs: Principles and Practices

Interface Design

Interface design is a crucial discipline that reflects a developer's capability. Inexperienced programmers often focus only on functional implementation, neglecting non‑functional aspects that determine interface quality.

Non‑functional elements of an interface include:

Idempotency

Robustness

Security

Idempotency

If you spend 1,000 yuan at a supermarket and your bank deducts 2,000 yuan, you would feel cheated—this illustrates an idempotency problem.

Idempotency means that a write‑type interface must guarantee data correctness when called repeatedly, which commonly occurs in data‑creation scenarios and some non‑idempotent update scenarios (e.g., balance deduction). Deletion operations are usually idempotent.

Because we cannot predict how callers will invoke an interface—perhaps due to timeouts or rapid clicks—the design must treat repeated calls as normal and place responsibility on the interface implementer.

Idempotency handling can be split into business‑logic level and database level.

Business‑Logic Level: select + insert

This approach checks for existing records based on request parameters (e.g., user ID, order ID) before inserting or updating, preventing duplicate processing such as double credit or double deduction.

Advantages: the logic is part of the business flow and easy to implement. Drawbacks: it cannot solve high‑concurrency duplicate requests, because two nearly simultaneous requests may both see no record and both proceed.

To guarantee exclusivity for critical scenarios (e.g., coupon issuance, points), requests must be serialized per user. A common solution is a Redis distributed lock using a key derived from request parameters (e.g., "userId:sceneId").

Typical Redis lock command:

set lock_key private_val ex 20 nx

Releasing the lock safely requires verifying ownership:

get lock_key del lock_key

Because the two commands are not atomic, a Lua script can ensure atomicity:

eval 'if (redis.call("get", KEYS[1]) == ARGV[1]) then redis.call("del", KEYS[1]); end return 1;' lock_key private_val

Database Level

Unique key constraints can enforce idempotency for insert‑type operations. For example, a prepaid‑card payment creates a transaction record and deducts the card balance; using the order number as a unique key prevents duplicate payments.

If no natural unique field exists, create a dedicated "uniqid" column and let the caller generate a globally unique identifier (e.g., UUID or Snowflake).

Typical unique‑ID generation format: date(8) + sequence(12) + random(4) , with the sequence allocated in batches from Redis to reduce pressure.

Robustness

Robustness (or resilience) describes how well an interface handles abnormal scenarios such as malformed input, external service failures, or performance spikes.

Key robustness concerns:

Input validation (type limits, default handling, malicious input filtering)

Process flow exceptions (disk I/O failures, division by zero, remote call timeouts)

Performance anomalies (code inefficiencies, downstream service latency, traffic spikes)

Best practices include:

Front‑end throttling to prevent rapid repeated clicks

Redis flag verification combined with front‑end controls

Database unique constraints as the final safeguard

Security

Beyond XSS and SQL injection, security also means preventing unauthorized interface calls.

Two main call types:

Frontend‑backend calls (exposed to users)

Backend‑to‑backend calls (internal services)

Session‑based authentication suffers from cross‑domain, distributed‑session, CSRF, and storage overhead issues.

Token‑based authentication solves many of these problems. The server issues a token (often via a custom response header) that the client stores (e.g., localStorage) and sends in subsequent requests.

Stateless JWT (JSON Web Token) is a popular token format. A JWT consists of three Base64‑encoded parts: Header, Payload, and Signature.

Example JWT generation (simplified):

// header
{"alg":"HS256","typ":"JWT"}
// payload
{"user_id":123456,"name":"Zhang San","exp":"2023-04-25 12:00:00"}
// sign with HMAC‑SHA256 using a secret key

The server validates the signature and extracts user info from the payload without storing the token, achieving true statelessness.

Token expiration must be handled gracefully; a refresh‑token header can be sent on each response to extend the session while the user remains active.

Afterword

Good API design also involves usability, consistent response structures, and effective front‑back collaboration. Teams should embed safeguards into frameworks, enforce code reviews, provide security training, and choose frameworks that support XSS/CSRF protection, input validation, signing, queuing, and scheduling.

BackendsecurityAPI designIdempotencyrobustness
Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.