Step 2
Step 2 — Folder structure
20 min
Step 2 — Folder structure
A main.py is fine to start, but split by domain as it grows.
Recommended layout
my-api/
├── pyproject.toml
├── main.py ← FastAPI app + router registration
├── routers/ ← HTTP endpoints (per domain)
├── services/ ← business logic
├── db/connection.py ← pool
├── schemas/ ← Pydantic models
├── utils/
├── schedulers/
└── tests/
Domain (users, posts) splits first; type (router/service/repo) splits after.
main.py — register routers only
from fastapi import FastAPI
from routers import users, posts, auth
app = FastAPI(title="My API")
app.include_router(users.router, prefix="/api/users", tags=["users"])
app.include_router(posts.router, prefix="/api/posts", tags=["posts"])
app.include_router(auth.router, prefix="/api/auth", tags=["auth"])
Router
# routers/posts.py
from fastapi import APIRouter, Depends
from services.post_service import PostService
from schemas.post import PostCreate, PostOut
router = APIRouter()
@router.get("", response_model=list[PostOut])
def list_posts(limit: int = 20, service: PostService = Depends()):
return service.find_recent(limit)
@router.post("", response_model=PostOut, status_code=201)
def create_post(payload: PostCreate, service: PostService = Depends()):
return service.create(payload)
Depends(PostService) injects the instance — like @Autowired.
Try it
Move step 1's /items route into routers/, services/, schemas/.
Next
Step 3 connects PostgreSQL with a real pool.