FastAPI ORM Session Fix
In this tutorial, you'll learn about FastAPI ORM Session Fix. We cover key concepts, practical examples, and best practices.
The Problem
Database sessions must be created per request and closed after the response. Improper session management causes connection leaks, stale data, and DetachedInstanceError.
Quick Fix
Wrong — global session
from sqlalchemy.orm import Session
# Global session — shared across all requests!
session = Session(engine)
@app.get("/items")
async def get_items():
return session.query(Item).all() # Thread-unsafe, no isolation
Output: Multiple requests share the same session. Concurrent access causes race conditions and stale data.
Correct — dependency-based session
from fastapi import Depends, FastAPI
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, Session
engine = create_engine("sqlite:///./test.db")
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
@app.get("/items")
async def get_items(db: Session = Depends(get_db)):
return db.query(Item).all()
Output: Each request gets its own session. Sessions are closed after the response.
Async SQLAlchemy session
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
async_engine = create_async_engine("sqlite+aiosqlite:///./test.db")
AsyncSessionLocal = sessionmaker(async_engine, class_=AsyncSession)
async def get_async_db():
async with AsyncSessionLocal() as session:
yield session
Nested transactions
def get_db_with_commit():
db = SessionLocal()
try:
yield db
db.commit() # Auto-commit on success
except Exception:
db.rollback() # Rollback on error
raise
finally:
db.close()
Session per request with middleware
from starlette.middleware.base import BaseHTTPMiddleware
class DBSessionMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request, call_next):
request.state.db = SessionLocal()
try:
response = await call_next(request)
request.state.db.commit()
except Exception:
request.state.db.rollback()
raise
finally:
request.state.db.close()
return response
Prevention
- Use
Depends(get_db)for every endpoint that accesses the database. - Always close sessions in a
finallyblock or use context managers. - Use async sessions for async database drivers.
Common Mistakes with orm session
- Forgetting that lazy evaluation defers computation until the value is forced, causing space leaks with unevaluated thunks
- Using
returnto exit a function early instead of wrapping a pure value in the monad - Mixing let bindings with <- bindings in do notation, producing type errors
These mistakes appear frequently in real-world FASTAPI code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro