Routers, services, repositories, and the rules that keep a FastAPI codebase from becoming a mess as it grows.
Every FastAPI project starts clean. Then it grows. The first sign of trouble is a router file with five hundred lines and database queries embedded in the handler.
The structure I've landed on is three layers: routers (HTTP only), services (business logic), and repositories (data access). Each returns well-typed objects to the layer above - no raw ORM rows leaking up.
The rule that makes it work: dependency injection via Depends. The session is injected into the repository, the repository into the service, the service into the router. Nothing is global.