As a best-selling author, I invite you to explore my books on Amazon. Don't forget to follow me on Medium and show your support. Thank you! Your support means the world!
FastAPI has revolutionized Python API development with its modern, async-first approach. I've spent considerable time working with FastAPI, and I'll share advanced patterns that have proven effective in production environments.
Dependency Injection
Dependency injection in FastAPI provides clean separation of concerns and efficient resource management. Here's a practical implementation of a database dependency:
from fastapi import Depends
from sqlalchemy.orm import Session
from contextlib import contextmanager
class Database:
def __init__(self):
self.session = None
@contextmanager
def get_session(self):
session = Session()
try:
yield session
finally:
session.close()
db = Database()
async def get_db():
with db.get_session() as session:
yield session
@app.get("/users/{user_id}")
async def get_user(user_id: int, db: Session = Depends(get_db)):
return db.query(User).filter(User.id == user_id).first()
Response Caching
Implementing Redis caching significantly improves API performance. Here's a robust caching implementation:
from fastapi_cache import FastAPICache
from fastapi_cache.backends.redis import RedisBackend
import pickle
class CustomRedisBackend(RedisBackend):
async def get(self, key: str):
value = await self.redis.get(key)
if value:
return pickle.loads(value)
return None
async def set(self, key: str, value: any, expire: int = None):
value = pickle.dumps(value)
await self.redis.set(key, value, expire)
@app.on_event("startup")
async def startup():
redis = aioredis.Redis(host='localhost', port=6379)
FastAPICache.init(CustomRedisBackend(redis), prefix="fastapi-cache:")
@app.get("/products/{product_id}")
@FastAPICache.cache(expire=300)
async def get_product(product_id: int):
return {"product_id": product_id}
Background Tasks
Managing long-running operations effectively is crucial. Here's a pattern for handling background tasks:
from fastapi import BackgroundTasks
from celery import Celery
celery_app = Celery('tasks', broker='redis://localhost:6379/0')
@celery_app.task
def process_video(video_id: int):
# Video processing logic
pass
@app.post("/videos/")
async def upload_video(
video: UploadFile,
background_tasks: BackgroundTasks
):
video_id = save_video(video)
background_tasks.add_task(process_video.delay, video_id)
return {"status": "processing"}
Rate Limiting
Protecting API resources requires effective rate limiting. Here's a Redis-based implementation:
from fastapi import HTTPException
import time
class RateLimiter:
def __init__(self, redis_client, limit: int, window: int):
self.redis = redis_client
self.limit = limit
self.window = window
async def is_allowed(self, key: str) -> bool:
current = int(time.time())
window_start = current - self.window
async with self.redis.pipeline() as pipe:
pipe.zremrangebyscore(key, 0, window_start)
pipe.zadd(key, {str(current): current})
pipe.zcard(key)
pipe.expire(key, self.window)
results = await pipe.execute()
return results[2] <= self.limit
@app.get("/api/resource")
async def get_resource(
redis: Redis = Depends(get_redis),
user: User = Depends(get_current_user)
):
rate_limiter = RateLimiter(redis, limit=100, window=3600)
if not await rate_limiter.is_allowed(f"rate_limit:{user.id}"):
raise HTTPException(status_code=429, detail="Rate limit exceeded")
return {"data": "resource"}
Custom Middleware
Middleware provides powerful request/response modification capabilities:
from fastapi import Request
from fastapi.middleware.base import BaseHTTPMiddleware
import time
class TimingMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
response.headers["X-Process-Time"] = str(process_time)
return response
app.add_middleware(TimingMiddleware)
API Versioning
Maintaining API versions is essential for backward compatibility:
from fastapi import APIRouter
v1_router = APIRouter(prefix="/v1")
v2_router = APIRouter(prefix="/v2")
@v1_router.get("/users/{user_id}")
async def get_user_v1(user_id: int):
return {"version": "1", "user_id": user_id}
@v2_router.get("/users/{user_id}")
async def get_user_v2(user_id: int):
return {"version": "2", "user_id": user_id}
app.include_router(v1_router)
app.include_router(v2_router)
Error Handling
Consistent error handling improves API reliability:
from fastapi import HTTPException
from fastapi.responses import JSONResponse
class CustomException(Exception):
def __init__(self, message: str, code: str):
self.message = message
self.code = code
@app.exception_handler(CustomException)
async def custom_exception_handler(request, exc):
return JSONResponse(
status_code=400,
content={
"error": {
"code": exc.code,
"message": exc.message
}
}
)
@app.get("/items/{item_id}")
async def get_item(item_id: int):
if item_id < 0:
raise CustomException(
message="Invalid item ID",
code="INVALID_ID"
)
return {"item_id": item_id}
Testing
Comprehensive testing ensures API reliability:
from fastapi.testclient import TestClient
import pytest
client = TestClient(app)
@pytest.fixture
def test_db():
# Setup test database
db = Database()
yield db
# Cleanup
def test_read_item():
response = client.get("/items/1")
assert response.status_code == 200
assert response.json() == {"item_id": 1}
def test_create_item():
response = client.post(
"/items/",
json={"name": "Test Item"}
)
assert response.status_code == 201
Production Deployment
For production deployment, consider these configurations:
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import uvicorn
app = FastAPI(
title="Production API",
description="Production-ready FastAPI application",
version="1.0.0",
docs_url="/documentation",
redoc_url=None
)
app.add_middleware(
CORSMiddleware,
allow_origins=["https://allowed-domain.com"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
if __name__ == "__main__":
uvicorn.run(
"main:app",
host="0.0.0.0",
port=8000,
workers=4,
log_level="info",
reload=False
)
These patterns form the foundation of robust FastAPI applications. The async capabilities, combined with proper resource management and error handling, create highly performant APIs. Regular testing and monitoring ensure reliability in production environments.
Remember to adapt these patterns based on specific requirements and scale. FastAPI's flexibility allows for customization while maintaining performance and code clarity.
101 Books
101 Books is an AI-driven publishing company co-founded by author Aarav Joshi. By leveraging advanced AI technology, we keep our publishing costs incredibly low—some books are priced as low as $4—making quality knowledge accessible to everyone.
Check out our book Golang Clean Code available on Amazon.
Stay tuned for updates and exciting news. When shopping for books, search for Aarav Joshi to find more of our titles. Use the provided link to enjoy special discounts!
Our Creations
Be sure to check out our creations:
Investor Central | Investor Central Spanish | Investor Central German | Smart Living | Epochs & Echoes | Puzzling Mysteries | Hindutva | Elite Dev | JS Schools
We are on Medium
Tech Koala Insights | Epochs & Echoes World | Investor Central Medium | Puzzling Mysteries Medium | Science & Epochs Medium | Modern Hindutva
Top comments (0)