FastAPI

Lesson 08

Database session lifecycle

Provide database sessions through a dependency so each request gets a clear unit of work.

Good Code

api/database.py
from typing import Annotated

from fastapi import Depends
from sqlmodel import Session


def get_session():
    with Session(engine) as session:
        yield session


SessionDep = Annotated[Session, Depends(get_session)]


@router.post("/reviews")
def create_review(payload: ReviewCreate, session: SessionDep):
    review = Review.model_validate(payload)
    session.add(review)
    session.commit()
    session.refresh(review)
    return review

Bad Code

api/reviews.py
from sqlmodel import Session

session = Session(engine)


@router.post("/reviews")
def create_review(payload: ReviewCreate):
    review = Review.model_validate(payload)
    session.add(review)
    session.commit()
    return review

Review Notes

What to review

Good Code

The good version gives each request a session through a dependency and makes commit/refresh part of the route workflow.

Bad Code

The bad version keeps a module-level session shared across requests. Cleanup, transaction boundaries, and concurrency behavior are unclear.

Takeaways

  • Database sessions need request-scoped ownership, cleanup, and transaction intent.