How to Build an Idempotency-Key POST Handler in Python
Python HTTP server mock that accepts POST requests and deduplicates them using an Idempotency-Key header, returning the same response for repeated calls.
Python code
38 linesimport hashlib
import json
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import urlparse
class MockAPI(BaseHTTPRequestHandler):
responses = {}
def do_POST(self):
length = int(self.headers.get("Content-Length", 0))
body = self.rfile.read(length).decode("utf-8")
idempotency_key = self.headers.get("Idempotency-Key")
if not idempotency_key:
self.send_error(400, "Missing Idempotency-Key header")
return
cache_key = (self.path, idempotency_key)
if cache_key in self.responses:
response_data = self.responses[cache_key]
status = 200
else:
digest = hashlib.sha256(body.encode()).hexdigest()[:8]
response_data = {"id": digest, "received": body, "cached": False}
self.responses[cache_key] = response_data
status = 201
self.send_response(status)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(json.dumps(response_data).encode())
if __name__ == "__main__":
server = HTTPServer(("localhost", 8000), MockAPI)
print("Mock API running on port 8000")
server.serve_forever()
Output
Mock API running on port 8000
# First POST (no cache)
HTTP/1.0 201 Created
Content-Type: application/json
{"id": "a1b2c3d4", "received": "{\"name\": \"Ada\"}", "cached": false}
# Second POST with same key
HTTP/1.0 200 OK
Content-Type: application/json
{"id": "a1b2c3d4", "received": "{\"name\": \"Ada\"}", "cached": false}
How it works
The handler reads the Idempotency-Key header and uses it as a cache key along with the request path. On the first POST it computes an 8-character SHA-256 digest of the body, stores the response, and returns 201. On subsequent POSTs with the same key, it returns the stored response with status 200, ensuring clients don't apply duplicate effects. Because the cache is a class-level dict, it persists across requests in a single process — exactly what a mock server needs for testing idempotent API behavior.
Common mistakes
- Forgetting to set Content-Length when sending the response, causing clients to hang.
- Using a new dict per request, so idempotency never works.
- Not decoding the request body before hashing, which produces inconsistent digests.
Variations
- Use Flask or FastAPI with a decorator to implement idempotency keys on a real API.
- Store responses in a database or Redis instead of an in-memory dict for multi-process deployments.
Real-world use cases
- Mocking a payment gateway to verify duplicate charges are prevented in test suites.
- Simulating a REST API that must return the same resource for retries on network failures.
- Building a stub server to test client idempotency handling in integration tests.
Sponsored
More from API design & gRPC
- Build a Bulk Array POST Mock Server in Python medium
- Build a Mock REST API with PUT and GET in Python medium
- Convert Protobuf to JSON and Dict in Python easy
- Create a Data Helper in Python for gRPC-style APIs easy
- Format data in Python using dataclasses like gRPC messages easy
- Generate an OpenAPI Spec from Mock Routes in Python easy
Keep learning
Related tutorials and quizzes for this topic.