Structuring a Large FastAPI Project with APIRouter
A single main.py is perfect for a prototype. As the API grows, split it by feature so each area of the product lives together.
A feature-based layout
app/
main.py # creates the app, includes routers
config.py # settings from environment
db.py # engine, session dependency
deps.py # shared dependencies (current user, pagination)
users/
router.py # HTTP layer
schemas.py # Pydantic models
models.py # SQLAlchemy models
service.py # business logic
orders/
router.py
schemas.py
models.py
service.py
tests/
Routers
# app/orders/router.py
from fastapi import APIRouter
from app.deps import CurrentUser, DbSession
from . import service
from .schemas import OrderIn, OrderOut
router = APIRouter(prefix="/orders", tags=["orders"])
@router.get("", response_model=list[OrderOut])
async def my_orders(user: CurrentUser, db: DbSession):
return await service.list_for_user(db, user.id)
@router.post("", response_model=OrderOut, status_code=201)
async def place_order(data: OrderIn, user: CurrentUser, db: DbSession):
return await service.place(db, user, data)
# app/main.py
from fastapi import FastAPI
from app.orders.router import router as orders_router
from app.users.router import router as users_router
app = FastAPI(title="Shop API")
app.include_router(users_router)
app.include_router(orders_router)
Keep routers thin
Routers translate HTTP into function calls. Business rules (stock checks, pricing, emails) belong in service.py, which you can test without HTTP and reuse from background jobs or CLIs.
Settings in one place
# app/config.py
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
database_url: str
jwt_secret: str
debug: bool = False
settings = Settings() # reads environment variables (and .env if configured)
Versioning
To version the API, mount routers under a prefix: app.include_router(orders_router, prefix="/v1"). Add a /v2 router only for endpoints that actually change.
Was this article helpful?
Comments
No comments yet. Have a question or a tip? Be the first to share it.