
Common Dependency Use Cases: Databases and Auth
See Dependency Injection in action. Learn how to manage database sessions and protect routes with authentication checks using Depends.
Common Dependency Use Cases: Databases and Auth
Now that you understand the "Why" of Dependency Injection (DI), let's look at the "How" for the two most critical parts of any production API: Database Sessions and Security.
In this lesson, we explore how to use Depends to keep your routes clean and your resources managed.
1. Database Session Management
Opening and closing a database connection for every single request is inefficient and dangerous (you might run out of connections). Using the yield keyword in a dependency allows FastAPI to handle the "Lifecycle" of that connection for you.
from sqlalchemy.orm import Session
from .database import SessionLocal # Your DB setup code
def get_db():
db = SessionLocal()
try:
yield db # Provide the connection to the endpoint
finally:
db.close() # Automatically runs AFTER the request is finished!
@app.get("/users")
def list_users(db: Session = Depends(get_db)):
return db.query(User).all()
2. Authentication Checks
You don't want every user to see every piece of data. DI allows you to write a single check that you can "Inject" into any route that needs protection.
from fastapi import Header, HTTPException
async def verify_token(x_token: str = Header(...)):
if x_token != "fake-super-secret-token":
raise HTTPException(status_code=400, detail="X-Token header invalid")
@app.get("/protected-items", dependencies=[Depends(verify_token)])
async def read_protected_items():
return [{"item": "Portal Gun"}, {"item": "Plumbus"}]
Note: Using dependencies=[Depends(...)] in the decorator is perfect when you need the check to run but don't need the resulting value inside your function.
3. Shared Services (e.g., Mailing)
If your app needs to send emails, you can inject a "Mail Client" dependency. This is huge for testing—you can inject a real client in production and a "Mock" client during tests so you don't actually send emails every time you run your test suite.
def get_mail_client():
return MailtrapClient(api_key="123")
@app.post("/contact")
def send_message(mail = Depends(get_mail_client)):
mail.send("Hello!")
4. The Annotated Upgrade
In modern FastAPI (and Python 3.9+), we use Annotated to make our code even cleaner.
from typing import Annotated
from sqlalchemy.orm import Session
# Create a reusable Database type
db_dep = Annotated[Session, Depends(get_db)]
@app.get("/users")
def list_users(db: db_dep):
return db.query(User).all()
Visualizing the Authentication Flow
graph LR
A["Request (Header: Token)"] --> B["verify_token Dependency"]
B -- "Token Valid" --> C["Endpoint Logic"]
B -- "Token Invalid" --> D["400 Error (Immediate Stop)"]
C --> E["200 Response"]
Summary
yield: Use it in dependencies to handle setup and cleanup (like closing DBs).- Header/Token logic: Centralize your security checks.
- Testing: DI makes it trivial to swap real services for mocks.
Annotated: Use it to create reusable, typed dependencies.
In the next lesson, we’ll look at Dependency Chains: what happens when a dependency has its own dependencies?
Exercise: The Header Guard
Write a dependency called get_api_key that looks for a header named X-API-KEY. If the key is not "shshell-rocks", raise a 403 Forbidden error. How would you apply this to a specific route?