This is it-the final stretch! You have built a secure, real-time, database-backed API. But before you can call it "production-ready," you need to answer two questions: "Will it crash if 10,000 people use it at once?" and "How do you know it actually works?"
In this final lesson, we will cover Rate Limiting (to stop abuse),Performance Tuning (to go faster), andTesting (to sleep soundly at night). These are the skills that define a Senior Engineer.
Rate limiting prevents users (or bots) from spamming your API. For example, you might want to limit users to "5 requests per minute."
FastAPI doesn't have this built-in, but the standard solution is the slowapi library (based on Flask-Limiter).
# pip install slowapi
from fastapi import FastAPI, Request
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
# 1. Initialize Limiter
# It identifies users by IP address (get_remote_address)
limiter = Limiter(key_func=get_remote_address)
app = FastAPI()
# 2. Register the global exception handler
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
@app.get("/expensive-task")
@limiter.limit("5/minute") # 3. Apply the limit decorator
def do_work(request: Request): # Request object is REQUIRED here
return {"message": "This works!"}
Sample Output (on 6th request):
{
"error": "Rate limit exceeded: 5 per 1 minute"
}FastAPI is already fast, but bad code can make it slow. When an interviewer asks this, focus on these key areas:
from fastapi import FastAPI
from fastapi.responses import ORJSONResponse
# Using ORJSONResponse is faster for large JSON payloads
app = FastAPI(default_response_class=ORJSONResponse)
@app.get("/fast-data")
def get_data():
return [{"id": i, "name": "item"} for i in range(10000)]
This is the killer feature of FastAPI testing. Normally, your API connects to a real database or calls a real external API. In tests, you don't want that.
With `app.dependency_overrides`, you can force FastAPI to swap a real function for a fake one during tests, without changing a single line of your actual application code.
from typing import Annotated
from fastapi import FastAPI, Depends
app = FastAPI()
# Real dependency (connects to Prod DB)
def get_db():
return "Real Production DB Connection"
@app.get("/users/")
def read_users(db: Annotated[Session, Depends(get_db)]):
return {"db": db}
# --- In your test file ---
def test_read_users():
# 1. Define the override
def override_get_db():
return "Fake Test DB Connection"
# 2. Apply the override
app.dependency_overrides[get_db] = override_get_db
# 3. Run the request (using TestClient)
# ... request logic ...
# 4. Clean up
app.dependency_overrides = {}
pytest is the standard testing framework in Python. You combine it with FastAPI's `TestClient` (which uses `httpx`) to send requests to your app.
Unlike running a real server, `TestClient` runs your FastAPI app directly in the python process. It's fast and doesn't require port binding.
# main.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/ping")
def ping():
return {"msg": "pong"}
# test_main.py
from fastapi.testclient import TestClient
from main import app # Import your app
client = TestClient(app)
def test_ping():
# Send a GET request to the app
response = client.get("/ping")
# Assert the status code
assert response.status_code == 200
# Assert the JSON body
assert response.json() == {"msg": "pong"}
# Run in terminal:
# pytest
Sample Output (Terminal):
$ pytest
================ test session starts ================
collected 1 item
test_main.py . [100%]
================ 1 passed in 0.03s =================TestClient is a helper class provided by `starlette.testclient` (which FastAPI exports). It acts like a web browser or Postman, but it calls your Python functions directly.
It allows you to test:
- Query parameters
- JSON bodies
- Headers & Cookies
- File Uploads
from fastapi import FastAPI, Header
from fastapi.testclient import TestClient
app = FastAPI()
@app.post("/items/")
def create_item(name: str, x_token: str = Header()):
if x_token != "secret":
return {"error": "Invalid Token"}
return {"name": name}
client = TestClient(app)
def test_create_item():
# Simulate a POST request with headers and JSON body
response = client.post(
"/items/",
headers={"X-Token": "secret"},
params={"name": "Hammer"} # Query param
)
assert response.status_code == 200
assert response.json() == {"name": "Hammer"}
This concludes our FastAPI interview series! You have covered everything from "Hello World" to rate limiting and automated testing. Good luck!
3 questions · no sign-up, nothing stored
Progress is stored in this browser only - no sign-up, nothing sent anywhere.
The same topic at architecture level, in the system design curriculum.