Skip to main content

Step 2

Step 2 — Folder structure

5 views

Table of contents

A main.py is fine to start, but split by domain as it grows.

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.