Theory of Intelligence
BACKEND ENGINEERING•Apis And Python Servers•Api Design•1.3 Idempotency & Rate Limiting

1.3.1 Idempotent

Subtopics: Idempotent and Rate Limiting.

1.3.1 Idempotent

Idempotent means:

lightbulb

You can perform the same operation multiple times, and after the first successful operation, the final result remains the same.

Simple example

Imagine a light switch:

TEXT
Set light = ON

Do it once:

TEXT
OFF → ON

Do it again:

TEXT
ON → ON

Do it 10 times:

TEXT
ON → ON → ON → ON ...

The final state is still ON. Therefore, set light = ON is idempotent.


In APIs

This is especially important in REST APIs.

HTTP methodUsually idempotent?Example
GET✅ YesGet user 123
PUT✅ YesSet user 123's name to "Ali"
DELETE✅ YesDelete user 123
POST❌ Usually noCreate a new user

For example:

HTTP
PUT /users/123

{
  "name": "Ali"
}

Send it once:

TEXT
User 123 → name = Ali

Send the exact same request again:

TEXT
User 123 → name = Ali

Send it 100 times:

TEXT
User 123 → name = Ali

It doesn't create 100 users. That's idempotency.

Why it matters in real systems

Suppose your frontend sends:

HTTP
POST /payments

The network fails and the frontend doesn't know whether the payment succeeded.

If it retries, you could accidentally charge the customer twice.

An idempotency key solves this:

HTTP
POST /payments
Idempotency-Key: abc123

If the same request with abc123 arrives again, the backend recognizes it as the same operation and doesn't perform the payment again.

Important distinction

Idempotent does NOT mean "the request can only be sent once."

It means:

lightbulb

Repeating the same operation produces the same intended final state/effect.

For backend/API development, this concept becomes particularly important with payments, order creation, background jobs, retries, and distributed systems.

Since you're working on the Elara Training Platform, here's a very practical example.


Scenario: Assign Training Modules to a Teacher

Admin clicks:

HTTP
POST /api/v1/integration/users/assign-modules

Request:

JSON
{
  "email": "teacher@school.com",
  "school_name": "Oak Primary School",
  "module_ids": ["module-1", "module-2"]
}

Backend:

  1. Create teacher (if not exists)
  2. Assign Module 1
  3. Assign Module 2

Problem Without Idempotency

Suppose Umaisa sends the request.

Network times out.

Umaisa thinks:

TEXT
Maybe Elara didn't receive it.

So it sends the same request again.

Now your database may contain:

TEXT
Teacher: teacher@school.com

Assignments:
- Module 1
- Module 2
- Module 1   ← duplicate
- Module 2   ← duplicate

Or you might send duplicate emails:

TEXT
Welcome email #1
Welcome email #2

Idempotent Solution

Before creating assignments, check whether they already exist.

Assignment Table

TEXT
teacher_id | module_id
-----------+----------
1          | module-1
1          | module-2

Add a unique constraint:

SQL
UNIQUE (teacher_id, module_id)

Now when the same request arrives again:

TEXT
teacher_id=1
module_id=module-1

Database says:

TEXT
Already exists.

No duplicate assignment is created.


FastAPI Example

PYTHON
for module_id in module_ids:

    existing = await session.scalar(
        select(UserModule)
        .where(
            UserModule.user_id == user.id,
            UserModule.module_id == module_id
        )
    )

    if existing:
        continue

    session.add(
        UserModule(
            user_id=user.id,
            module_id=module_id
        )
    )

First Call

TEXT
Assign Module 1 ✅
Assign Module 2 ✅

Second Call (same request)

TEXT
Module 1 already assigned → skip
Module 2 already assigned → skip

Final state:

TEXT
Teacher has:
- Module 1
- Module 2

Exactly the same as after the first request.


Another Elara Example: Mark Module Complete

Endpoint:

HTTP
POST /modules/1/complete

Bad implementation:

PYTHON
teacher.completed_modules += 1

If frontend accidentally sends the request 3 times:

TEXT
Completed count:
1
2
3

Wrong.


Better:

Store completion as a state.

PYTHON
module_progress.completed = True

Even if called 10 times:

TEXT
True
True
True
True

Final state remains:

TEXT
Completed = True

That's idempotent.


Rule of Thumb

For your school/training platform:

✅ Assign module to teacher ✅ Enroll teacher in programme ✅ Mark module complete ✅ Update profile ✅ Activate account

These should usually be idempotent.

⚠️ Send email ⚠️ Create payment ⚠️ Create audit log entry

These are often not idempotent unless you add an idempotency key or deduplication logic.

Practical Example: Payment API

Suppose you have an e-commerce website.

User clicks "Pay Now".

Frontend sends:

HTTP
POST /payments

Backend:

  1. Charges customer
  2. Creates payment record
  3. Returns success

Problem

Imagine this happens:

TEXT
Frontend  ---> Backend
              Charge successful ✅
              Response lost ❌

The frontend never receives the success response because of a network issue.

It thinks:

TEXT
Maybe payment failed.
Let's try again.

So it sends:

HTTP
POST /payments

again.

Now customer gets charged twice.


Bad Implementation

PYTHON
@app.post("/payments")
async def create_payment(payment: PaymentCreate):
    charge_customer(payment.amount)

    db_payment = Payment(amount=payment.amount)
    session.add(db_payment)
    session.commit()

    return {"success": True}

If the request arrives twice:

TEXT
Request 1 -> Charge $100
Request 2 -> Charge $100 again

Customer pays $200.


Solution: Idempotency Key

Frontend generates a unique UUID:

PYTHON
import uuid

idempotency_key = str(uuid.uuid4())

Example:

TEXT
c8b5e5d0-9f2c-4fd4-a9e2-123456789abc

Request:

HTTP
POST /payments
Idempotency-Key: c8b5e5d0-9f2c-4fd4-a9e2-123456789abc

Backend Logic

Before processing:

PYTHON
existing = db.query(Payment).filter(
    Payment.idempotency_key == key
).first()

if existing:
    return existing

If not found:

PYTHON
charge_customer()

payment = Payment(
    amount=100,
    idempotency_key=key
)

db.add(payment)
db.commit()

What Happens Now?

First Request

TEXT
Key = abc123

Database:

TEXT
No record found

Process payment:

TEXT
Charge customer ✅
Save key abc123 ✅

Retry Request

TEXT
Key = abc123

Database:

TEXT
Record already exists

Backend:

TEXT
Do NOT charge again
Return previous response

Result:

TEXT
Customer charged only once ✅

Another Practical Example: User Registration

Bad:

HTTP
POST /users

Body:

JSON
{
  "email": "ali@gmail.com"
}

User clicks submit 3 times.

Result:

TEXT
Ali #1
Ali #2
Ali #3

Three users created.


Solution

Use a unique constraint:

SQL
UNIQUE(email)

Then:

PYTHON
existing_user = get_user_by_email(email)

if existing_user:
    return existing_user

or let the database reject duplicates.


In Your FastAPI Projects

You will commonly use idempotency for:

  1. Payments
  2. Module assignment APIs
  3. Invite user APIs
  4. Email sending
  5. Background jobs
  6. Webhook processing (Stripe, PayPal, etc.)

A common production pattern is:

TEXT
Client
   |
   | POST + Idempotency-Key
   v
FastAPI
   |
   | Check Redis/Postgres
   |
   +--> Key exists -> Return old response
   |
   +--> Key missing -> Process request
                          |
                          v
                    Store result

This is how systems handle retries safely when networks, browsers, mobile apps, or load balancers resend the same request.

Discuss theoretical concepts, mathematical formulas, and architectural foundations.

Supports inline code with `backticks`
No comments yet. Be the first to start the discussion!