Middleware and Requests

Loading concept...

The Security Guards of Your FastAPI Castle

Imagine your FastAPI app is a magical castle. Visitors (requests) arrive at the gate every second. But wait! You can’t just let everyone walk in without checking them first, right?

That’s where Middleware comes in — they’re like security guards standing at every entrance and exit of your castle!


What is Middleware? (The Security Guard Analogy)

Think of middleware like this:

Visitor arrives → Guard checks them → They enter castle →
They do their thing → Guard checks them again → They leave

Every single request passes through middleware twice:

  1. On the way IN (before your code runs)
  2. On the way OUT (after your code runs)

Your First Middleware

from fastapi import FastAPI, Request

app = FastAPI()

@app.middleware("http")
async def security_guard(request: Request, call_next):
    # Guard checks visitor ENTERING
    print("Someone is entering!")

    # Let them into the castle
    response = await call_next(request)

    # Guard checks visitor LEAVING
    print("Someone is leaving!")

    return response

What happens:

  • request = the visitor trying to enter
  • call_next(request) = letting them inside
  • response = what they’re carrying when they leave

CORS Middleware (The “Who Can Visit” Rule)

Imagine your castle is in Kingdom A. But visitors from Kingdom B want to visit too!

By default, your castle says: “Only people from MY kingdom can enter!”

CORS (Cross-Origin Resource Sharing) is like a special permission slip that says: “It’s okay, let visitors from other kingdoms in too!”

Why Do We Need This?

When your website is at mysite.com and your API is at api.mysite.com:

  • The browser thinks they’re from different kingdoms
  • Without CORS, the browser blocks the request!

Setting Up CORS

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://mysite.com"],
    allow_credentials=True,
    allow_methods=["GET", "POST"],
    allow_headers=["*"],
)

What each setting means:

Setting Meaning
allow_origins Which kingdoms can visit
allow_credentials Can they bring cookies?
allow_methods What actions can they do?
allow_headers What extra info can they send?

Rate Limiting (The “Don’t Overwhelm Us” Rule)

Imagine 1000 visitors trying to enter your castle gate at the SAME SECOND. The guards would be overwhelmed!

Rate Limiting says: “Each person can only knock 10 times per minute. If they knock more, we ignore them.”

Simple Rate Limiter Example

from fastapi import FastAPI, Request, HTTPException
from collections import defaultdict
import time

app = FastAPI()
request_counts = defaultdict(list)

@app.middleware("http")
async def rate_limiter(request: Request, call_next):
    client_ip = request.client.host
    now = time.time()

    # Remove old requests (older than 60 sec)
    request_counts[client_ip] = [
        t for t in request_counts[client_ip]
        if now - t < 60
    ]

    # Check if too many requests
    if len(request_counts[client_ip]) >= 10:
        raise HTTPException(
            status_code=429,
            detail="Too many requests!"
        )

    request_counts[client_ip].append(now)
    return await call_next(request)

The magic:

  • We track when each visitor last knocked
  • If they knocked 10+ times in 60 seconds → BLOCKED!
  • Error code 429 = “Too Many Requests”

Session Management (Remembering Visitors)

When a visitor enters your castle, you give them a special wristband. Next time they come back, you recognize them!

A session is like that wristband — it helps you remember who someone is across multiple visits.

How Sessions Work

1. Visitor logs in
2. Castle gives them a secret code (session ID)
3. Visitor stores code in their pocket (cookie)
4. Next visit, visitor shows code
5. Castle remembers them!

Simple Session Example

from fastapi import FastAPI, Request, Response
from starlette.middleware.sessions import SessionMiddleware

app = FastAPI()

# Add session middleware with a secret key
app.add_middleware(
    SessionMiddleware,
    secret_key="your-super-secret-key"
)

@app.get("/login")
async def login(request: Request):
    request.session["user"] = "Alice"
    return {"message": "Logged in!"}

@app.get("/profile")
async def profile(request: Request):
    user = request.session.get("user", "Guest")
    return {"user": user}

Key points:

  • secret_key encrypts the session (keep it secret!)
  • request.session is like a dictionary per user
  • Data persists between requests

Custom Middleware (Build Your Own Guard)

Now you’re ready to create your OWN security guards with special powers!

Example: Timing Middleware

Want to know how long each request takes? Build a timer!

from fastapi import FastAPI, Request
import time

app = FastAPI()

@app.middleware("http")
async def add_timing(request: Request, call_next):
    start = time.time()

    response = await call_next(request)

    duration = time.time() - start
    response.headers["X-Process-Time"] = str(duration)

    return response

Example: Authentication Checker

@app.middleware("http")
async def check_auth(request: Request, call_next):
    # Skip auth for public paths
    if request.url.path in ["/", "/login"]:
        return await call_next(request)

    # Check for auth token
    token = request.headers.get("Authorization")
    if not token:
        return JSONResponse(
            status_code=401,
            content={"detail": "Not authenticated"}
        )

    return await call_next(request)

Request and Response Objects (The Visitor’s Backpack)

Every visitor carries a backpack (Request) with things inside. And they leave with a gift bag (Response) from the castle!

What’s Inside a Request?

from fastapi import FastAPI, Request

app = FastAPI()

@app.get("/inspect")
async def inspect_request(request: Request):
    return {
        "method": request.method,      # GET, POST, etc.
        "url": str(request.url),       # Full URL
        "path": request.url.path,      # Just the path
        "headers": dict(request.headers),
        "client_ip": request.client.host,
        "cookies": request.cookies,
    }

Reading Request Body

@app.post("/data")
async def read_body(request: Request):
    # For JSON data
    json_data = await request.json()

    # For form data
    form_data = await request.form()

    # For raw bytes
    raw_body = await request.body()

    return {"received": json_data}

Building a Response

from fastapi.responses import JSONResponse, Response

@app.get("/custom")
async def custom_response():
    return JSONResponse(
        content={"message": "Hello!"},
        status_code=200,
        headers={"X-Custom": "My Header"}
    )

The Complete Picture

graph TD A[Request Arrives] --> B[Middleware 1: CORS] B --> C[Middleware 2: Rate Limit] C --> D[Middleware 3: Session] D --> E[Middleware 4: Custom] E --> F[Your Route Handler] F --> G[Response Created] G --> H[Middleware 4: Add Headers] H --> I[Middleware 3: Save Session] I --> J[Middleware 2: Log Request] J --> K[Middleware 1: Add CORS Headers] K --> L[Response Sent]

Remember:

  • Middleware runs in ORDER going in
  • And REVERSE ORDER going out
  • Like guards at the entrance — first one in, last one out!

Quick Reference

Concept Purpose One-Liner
Middleware Process all requests Guards at the gate
CORS Allow cross-origin Permission slips
Rate Limiting Prevent overload “10 knocks/minute max”
Sessions Remember visitors Wristbands
Custom Middleware Your special logic Build your own guard
Request Incoming data Visitor’s backpack
Response Outgoing data Gift bag

You Did It!

You now understand how FastAPI handles every request like a well-guarded castle. Your middleware guards are ready to:

  • Check where visitors come from (CORS)
  • Prevent overwhelming crowds (Rate Limiting)
  • Remember friendly faces (Sessions)
  • Do any custom security check you want!

Now go build something awesome!

Loading story...

No Story Available

This concept doesn't have a story yet.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.

Interactive Preview

Interactive - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.

No Interactive Content

This concept doesn't have interactive content yet.

Cheatsheet Preview

Cheatsheet - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.

No Cheatsheet Available

This concept doesn't have a cheatsheet yet.

Quiz Preview

Quiz - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.

No Quiz Available

This concept doesn't have a quiz yet.