Idempotency keys for safe retries in Rest API - Time & Space Complexity
When using idempotency keys in APIs, we want to know how the system handles repeated requests efficiently.
We ask: how does the time to process requests grow when retries happen?
Analyze the time complexity of the following code snippet.
// Pseudocode for handling idempotent requests
function handleRequest(request) {
if (cache.has(request.idempotencyKey)) {
return cache.get(request.idempotencyKey); // Return cached response
}
let response = processRequest(request); // Process new request
cache.set(request.idempotencyKey, response); // Save response
return response;
}
This code checks if a request with the same idempotency key was handled before. If yes, it returns the saved response. Otherwise, it processes the request and saves the result.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Checking and retrieving from the cache (usually a hash map or dictionary).
- How many times: Once per request, whether retry or new.
As the number of unique idempotency keys grows, the cache size grows, but each lookup stays fast.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 cache lookups, mostly fast |
| 100 | 100 cache lookups, still fast |
| 1000 | 1000 cache lookups, still fast |
Pattern observation: Each request requires a single quick lookup, so time grows linearly with requests but each lookup is constant time.
Time Complexity: O(1)
This means each request, including retries, is handled in constant time due to fast cache lookups.
[X] Wrong: "Each retry causes the whole request to be processed again, so time grows with retries."
[OK] Correct: The idempotency key cache prevents reprocessing by returning saved results instantly, so retries do not add processing time.
Understanding how idempotency keys keep retries efficient shows you grasp safe API design and performance, a valuable skill in real projects.
"What if the cache lookup was implemented as a list search instead of a hash map? How would the time complexity change?"
Practice
idempotency key in REST APIs?Solution
Step 1: Understand idempotency key concept
An idempotency key is a unique identifier sent with a request to ensure the server processes it only once.Step 2: Identify the main purpose
This prevents duplicate actions like double payments or repeated orders if the client retries the request.Final Answer:
To prevent duplicate processing of the same request -> Option BQuick Check:
Idempotency key = prevent duplicates [OK]
- Confusing idempotency key with authentication token
- Thinking it speeds up response time
- Assuming it encrypts data
Solution
Step 1: Recall standard header for idempotency
The standard practice is to send the unique idempotency key in theIdempotency-KeyHTTP header.Step 2: Differentiate from other headers
Authorizationis for credentials,Content-Typedefines data format, andCache-Controlmanages caching.Final Answer:
Idempotency-Key -> Option AQuick Check:
Idempotency key header = Idempotency-Key [OK]
- Using Authorization header for idempotency key
- Confusing Content-Type with idempotency key
- Sending key in request body instead of header
stored_keys = {}
def handle_request(idempotency_key, data):
if idempotency_key in stored_keys:
return stored_keys[idempotency_key]
response = process_data(data)
stored_keys[idempotency_key] = response
return response
# Client sends:
print(handle_request('abc123', 'order1'))
print(handle_request('abc123', 'order1'))
print(handle_request('xyz789', 'order2'))
What will be the output?Solution
Step 1: Analyze first call with key 'abc123'
Key not in stored_keys, so process_data('order1') runs, result saved and returned.Step 2: Analyze second call with same key 'abc123'
Key found, stored response returned without reprocessing.Step 3: Analyze third call with new key 'xyz789'
Key not found, process_data('order2') runs, result saved and returned.Final Answer:
process_data output for order1, process_data output for order1, process_data output for order2 -> Option DQuick Check:
Repeated key returns cached response [OK]
- Assuming second call reprocesses data
- Confusing keys and responses
- Thinking None is returned on repeats
cache = {}
def post_request(key, data):
if key not in cache:
process(data)
return cache[key]
What is the bug in this code?Solution
Step 1: Check caching logic
The code checks if key not in cache, then calls process(data), but never saves the result in cache.Step 2: Identify consequence
Since cache[key] is never set, returning cache[key] will cause a KeyError or return None incorrectly.Final Answer:
It never stores the processed result in cache -> Option AQuick Check:
Missing cache storage causes errors [OK]
- Assuming process(data) stores result automatically
- Ignoring missing cache assignment
- Thinking HTTP method affects caching here
Solution
Step 1: Understand safe retry requirements
Safe retries mean the client can resend the same request without causing duplicate charges.Step 2: Evaluate options
Store the payment result linked to the idempotency key and return it on repeated requests stores the payment result linked to the key and returns it on repeats, preventing double charges. Ignore the idempotency key and process every request independently processes every request, risking duplicates. Reject any request with an idempotency key that was seen before rejects repeats, which may cause client errors. Process the payment again but log a warning for duplicate keys processes again, causing duplicates.Final Answer:
Store the payment result linked to the idempotency key and return it on repeated requests -> Option CQuick Check:
Store and reuse result for idempotency [OK]
- Rejecting repeated keys causing client errors
- Processing duplicates causing double charges
- Logging warnings but still charging twice
Ready to prove it?
Pass the test and this pattern moves unknown
