FastAPI Dependency Injection for Database Sessions
FastAPI utilizes a robust dependency injection system powered by the
Depends class and Python generator functions to manage
database sessions seamlessly across endpoints. By defining a dependency
that yields a database session, FastAPI ensures that each incoming HTTP
request receives an isolated session that automatically handles commit,
rollback, and cleanup logic when the request lifecycle concludes.
The Session Generator Function
The foundation of sharing a database session lies in a generator
function, commonly named get_db. Using an ORM like
SQLAlchemy, this function creates a session instance, yields it to the
route handler, and ensures the session is closed afterward using a
try...finally block.
from sqlalchemy import create_engine
from sqlalchemy.orm import declarative_base, sessionmaker
DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()The yield statement is critical. Code execution pauses
at yield db, passing the active session object to whichever
route requested it. Once the route finishes processing and sends an HTTP
response, execution resumes immediately after the yield,
executing the finally block to close the database
connection.
Injecting Sessions into Routes
To consume the database session within an API endpoint, declare a
parameter in the route function and assign it to
Depends(get_db). FastAPI automatically evaluates the
dependency, invokes the generator, and injects the resulting session
object into the route parameter.
from fastapi import Depends, FastAPI
from sqlalchemy.orm import Session
app = FastAPI()
@app.get("/items/")
def read_items(db: Session = Depends(get_db)):
items = db.query(ItemModel).all()
return itemsRequest Lifecycle and Concurrency
FastAPI ensures thread-safety and proper scoping for each connection:
- Per-Request Isolation: Each route invocation calls
get_dbindependently, creating a dedicated database session for that specific HTTP request. This prevents data leaks and race conditions between concurrent requests. - Error Handling: If an unhandled exception occurs
inside the route, the
finallyblock inget_dbstill executes, guaranteeing that database connections are never left dangling or exhausted in the connection pool. - Sub-dependency Reusability: If a route depends on
multiple services that all require a database connection, FastAPI caches
the result of
get_dbfor the duration of that single request by default, allowing all sub-dependencies to share the exact same session instance.
Overriding for Testing
A major advantage of this architecture is testability. FastAPI allows
dependency overrides without altering production code. During automated
tests, you can swap the production get_db dependency with a
test-specific session connected to a mock or an in-memory database:
app.dependency_overrides[get_db] = get_test_dbThis modular approach keeps route handlers lightweight, enforces separation of concerns, and simplifies connection lifecycle management across the application.