Depends and dependency injection
The lifespan loaded the client. Now every route needs a clean way to get at it. You could reach into app.state directly, but that ties every route to the app object. Depends gives you a better answer: declare a function that returns the resource, and any route that lists it as a Depends parameter receives it automatically.
from fastapi import APIRouter, Depends, Request
from models import StoryRequest
from service import build_story_prompt
router = APIRouter(prefix="/bedtime-story", tags=["bedtime-story"])
def get_llm(request: Request):
"""Provider function: pulls the shared client off app.state."""
return request.app.state.llm_provider
@router.post("/stream")
async def stream_story(
body: StoryRequest,
llm = Depends(get_llm),
):
prompt = build_story_prompt(body)
return {"ok": True, "model": llm.model}get_llm is the provider function. Any route that lists Depends(get_llm) as an argument gets the shared client. Swap the provider at test time without touching the routes.
Matching exercise: Match each Depends concept to its job
Loading practice…
FastAPI has a dependency_overrides dict on the app. In tests, you register a fake provider for get_llm, and every route that depends on it gets the fake automatically. No mocks inside your business logic, no patching imports. The route code stays honest and the test stays small.