dependency-injectionpython-asynciofastapi

How do I correctly implement a FastAPI with async db and dependencies?


I get the error 127.0.0.1:35352 - "GET /users/ HTTP/1.1" 422 Unprocessable Entity 2025-01-14 20:51

whenever I visit this route ('/users') in my project. Below is the route method

router = APIRouter(
    prefix="/users",
    tags=["users"]
)

@router.get("/", response_model=List[schemas.UserDetail]) #
async def list_user(db: AsyncSession = Depends(async_db_session_dependency)):
    try:
        users = await crud.get_users(db)
        if not users:
            raise HTTPException(status_code=404, detail="No users found")
        validated_users = [schemas.UserDetail.model_validate(user) for user in users]
        
        return validated_users
    
    except Exception as e:
        print("Error: ", e)
        raise HTTPException(
            status_code=400, 
            detail="Error getting users"
        )

Below here is the dependencies

from typing import Annotated, AsyncGenerator, Generator
from fastapi import Depends
from sqlalchemy.orm import Session
from sqlalchemy.ext.asyncio import AsyncSession
from contextlib import asynccontextmanager

from services.database import SessionLocal, AsyncSessionLocal

# Dependency for synchronous session
def get_db_session() -> Generator[Session, None, None]:
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

# Dependency for asynchronous session
async def get_async_db_session() -> AsyncGenerator[AsyncSession, None]:
    async with AsyncSessionLocal() as session:
        yield session

db_session_dependency = Annotated[Session, Depends(get_db_session)]
async_db_session_dependency = Annotated[AsyncSession, Depends(get_async_db_session)]


I discovered the problem is with the db dependencies as I only get the error when I removed the db deps from the function and make it simpler.

Here is the actual error I get upon making the request.

{ "detail": [ { "type": "missing", "loc": [ "query", "args" ], "msg": "Field required", "input": null }, { "type": "missing", "loc": [ "query", "kwargs" ], "msg": "Field required", "input": null } ] }


Solution

  • You are using Depends twice. Please refer to the example in the FastAPI documentation.

    Your router’s dependency code should be structured as follows:

    @router.get("/", response_model=List[schemas.UserDetail]) #
    async def list_user(db: async_db_session_dependency):
        ...
    

    A clearer way to define dependencies is to use class-like names instead of variables:

    AsyncDatabaseDependency = Annotated[AsyncSession, Depends(get_async_db_session)]
    

    Then, the router code will look like this:

    @router.get("/", response_model=List[schemas.UserDetail]) #
    async def list_user(db: AsyncDatabaseDependency):
        ...
    

    By the way you should remove "/" from router to properly handle "/users" endpoint.

    @router.get("", response_model=List[schemas.UserDetail]) #
    async def list_user(db: AsyncDatabaseDependency):
        ...