The Physics of APIs: Idempotency, Rate Limits & State Machines

REST is not just CRUD. The physics of Idempotency (f(x) = f(f(x))), Leaky Bucket Rate Limiting, and why HATEOAS is a State Machine.

Beginner 40 min read Expert Version →

🎯 What You'll Learn

  • Prove Idempotency mathematically ($f(x) = f(f(x))$)
  • Implement Token Bucket Rate Limiting (Redis Lua Script)
  • Design APIs as Finite State Machines (HATEOAS)
  • Master Versioning Physics (Header-based vs URL-based)
  • Differentiate 429 vs 503 (Backpressure Physics)

Introduction

Most developers treat APIs as “JSON over HTTP”. This is wrong. An API is a Remote Procedure Call with Failure Semantics. When you send a request over a network, three outcomes are possible:

  1. Success.
  2. Failure.
  3. Unknown (The request was sent, but the connection dropped before response).

This “Unknown” state creates the need for Idempotency.


The Physics: Idempotency

Definition: An operation is idempotent if applying it multiple times has the same effect as applying it once. f(x)=f(f(x))f(x) = f(f(x))

  • GET: Idempotent (Read-only).
  • PUT: Idempotent (Replace state). x=5x=5. If I say x=5x=5 twice, xx is still 55.
  • POST: Not Idempotent (Create). If I say “Pay 10"twice,Ipay10" twice, I pay 20.

The Solution: Idempotency Keys. The client generates a UUID (v4) and sends it in the header: Idempotency-Key: <uuid>. The server stores the Key + Response in Redis. If the client retries, the server returns the stored response execution.


Rate Limiting: The Token Bucket

If an API accepts infinite requests, it will crash. We need Backpressure.

Token Bucket Algorithm:

  • Capacity (CC): Maximum burst size.
  • Refill Rate (RR): Tokens added per second.

Physics Metaphor: A bucket leaks water at a constant rate. You can dump a bucket of water in (Burst), but if you pour faster than the leak, it overflows (429 Too Many Requests).

Redis Lua Implementation: To avoid race conditions (Get-then-Set), we use Lua to make the check atomic.

-- Redis Lua Script for Token Bucket
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local current = tonumber(redis.call('get', key) or "0")

if current + 1 > limit then
    return 0 -- Rejected
else
    redis.call("INCR", key)
    redis.call("EXPIRE", key, 1) -- 1 Second Window
    return 1 -- Accepted
end

HATEOAS: The API as a State Machine

REST stands for “Representational State Transfer”. Most APIs are just “RPC over JSON”. True REST uses HATEOAS (Hypermedia As The Engine of Application State).

Physics: The Server dictates the State Machine. The Client just follows transitions.

Response Example:

{
  "order_id": 123,
  "status": "pending_payment",
  "links": [
    { "rel": "pay", "method": "POST", "href": "/orders/123/pay" },
    { "rel": "cancel", "method": "DELETE", "href": "/orders/123" }
  ]
}

If the status changes to paid, the pay link disappears. The Client never needs to know the logic “If pending, show pay button”. It just renders the links.


Practice Exercises

Exercise 1: Idempotency Fail (Beginner)

Task: Write a Python script that POST /charge twice without an Idempotency Key. Observation: You effectively double-charge the user. Fix: Add a UUID header and handle it on the server.

Exercise 2: The 429 Governor (Intermediate)

Task: Use ab (Apache Bench) to hammer your API. Action: Implement the Lua Token Bucket. Result: See requests succeed up to Limit, then fail with 429 immediately.

Exercise 3: State Machine Logic (Advanced)

Task: Design a “Traffic Light” API. Action: Return links for next_state. Rules: Red -> Green (links: next). Green -> Yellow (links: next). Yellow -> Red. Check: Ensure you cannot go from Red to Yellow.


Knowledge Check

  1. Which HTTP method is NOT idempotent?
  2. What is the formula for Idempotency?
  3. Why use Lua for Rate Limiting in Redis?
  4. What does HATEOAS stand for?
  5. Difference between 429 and 503?
Answers
  1. POST. (And PATCH, usually).
  2. f(x) = f(f(x)).
  3. Atomicity. Prevents race conditions between reading usage and incrementing it.
  4. Hypermedia As The Engine of Application State.
  5. 429: Client sending too fast. 503: Server is overloaded/down.

Summary

  • Idempotency: The safety net for network uncertainty.
  • Rate Limiting: Protecting the server from physics (infinite load).
  • HATEOAS: The API tells the Client what is possible.

Questions about this lesson? Working on related infrastructure?

Let's discuss