Building Scalable APIs with FastAPI
FastAPI has become my go-to framework for building modern APIs in Python. Here's why and how I use it.
Why FastAPI?
FastAPI combines the best aspects of modern Python development:
Getting Started
Installation is straightforward:
pip install fastapi uvicorn
A simple API:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
@app.get("/items/{item_id}")
async def read_item(item_id: int, q: str = None):
return {"item_id": item_id, "q": q}
Type Safety with Pydantic
Define your data models:
from pydantic import BaseModel
class User(BaseModel):
username: str
email: str
full_name: str = None
@app.post("/users/")
async def create_user(user: User):
return user
FastAPI automatically validates the request body and generates documentation.
Database Integration
Using SQLAlchemy with async support:
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker
engine = create_async_engine(DATABASE_URL)
async_session = sessionmaker(
engine, class_=AsyncSession, expire_on_commit=False
)
async def get_db():
async with async_session() as session:
yield session
@app.get("/users/{user_id}")
async def get_user(user_id: int, db: AsyncSession = Depends(get_db)):
result = await db.execute(
select(User).filter(User.id == user_id)
)
return result.scalar_one_or_none()
Authentication
Implementing JWT authentication:
from fastapi.security import OAuth2PasswordBearer
from jose import JWTError, jwt
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
def create_access_token(data: dict):
to_encode = data.copy()
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
user = authenticate_user(form_data.username, form_data.password)
access_token = create_access_token(data={"sub": user.username})
return {"access_token": access_token, "token_type": "bearer"}
Performance Tips
1. Use Background Tasks
For non-blocking operations:
from fastapi import BackgroundTasks
def send_email(email: str, message: str):
# Send email logic
pass
@app.post("/send-notification/")
async def send_notification(
email: str,
background_tasks: BackgroundTasks
):
background_tasks.add_task(send_email, email, "Welcome!")
return {"message": "Notification sent"}
2. Caching
Implement Redis caching:
import redis
from functools import wraps
redis_client = redis.Redis(host='localhost', port=6379, db=0)
def cache(expire=300):
def decorator(func):
@wraps(func)
async def wrapper(*args, **kwargs):
key = f"{func.__name__}:{args}:{kwargs}"
cached = redis_client.get(key)
if cached:
return json.loads(cached)
result = await func(*args, **kwargs)
redis_client.setex(key, expire, json.dumps(result))
return result
return wrapper
return decorator
3. Connection Pooling
Use connection pools for database and external services.
Testing
FastAPI makes testing easy:
from fastapi.testclient import TestClient
client = TestClient(app)
def test_read_main():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"message": "Hello World"}
Deployment
Deploy with Docker:
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Conclusion
FastAPI is an excellent choice for building modern APIs. Its combination of performance, developer experience, and automatic documentation makes it my preferred framework for Python backends.
Start building with FastAPI today and experience the difference!