Monday, 22 December 2025

FastAPI Project Structure

 

Production Best Practices

1️⃣ Recommended Folder Structure

fastapi-app/ │ ├── app/ │ ├── main.py # Entry point (like SpringBootApplication) │ │ │ ├── core/ # Core configs (security, settings) │ │ ├── config.py # App settings (env based) │ │ ├── security.py # Auth, JWT, OAuth2 │ │ └── logging.py │ │ │ ├── api/ # API layer (Controllers) │ │ ├── v1/ │ │ │ ├── router.py # API router aggregation │ │ │ └── endpoints/ │ │ │ ├── users.py │ │ │ ├── auth.py │ │ │ └── health.py │ │ │ ├── models/ # DB models (Entities) │ │ ├── user.py │ │ └── base.py │ │ │ ├── schemas/ # Pydantic schemas (DTOs) │ │ ├── user.py │ │ └── auth.py │ │ │ ├── services/ # Business logic (Service layer) │ │ ├── user_service.py │ │ └── auth_service.py │ │ │ ├── repositories/ # DB access layer │ │ └── user_repo.py │ │ │ ├── db/ # Database setup │ │ ├── session.py │ │ └── init_db.py │ │ │ ├── middlewares/ # Custom middleware │ │ └── request_log.py │ │ │ ├── utils/ # Utilities/helpers │ │ └── date_utils.py │ │ │ └── tests/ # Unit & integration tests │ └── test_users.py │ ├── requirements.txt ├── Dockerfile ├── docker-compose.yml ├── .env └── README.md

2️⃣ Mapping to Spring Boot (So It Feels Familiar)

Spring BootFastAPI
@SpringBootApplicationmain.py
Controllerapi/endpoints
Serviceservices
Repositoryrepositories
Entitymodels
DTOschemas
application.ymlconfig.py / .env
Filtersmiddlewares

3️⃣ main.py – Application Entry Point

from fastapi import FastAPI from app.api.v1.router import api_router app = FastAPI(title="FastAPI App") app.include_router(api_router, prefix="/api/v1")

➡ Similar to:

@SpringBootApplication public class App { }

4️⃣ Router Aggregation (Like Controller Scanning)

api/v1/router.py

from fastapi import APIRouter from app.api.v1.endpoints import users, auth, health api_router = APIRouter() api_router.include_router(users.router, prefix="/users", tags=["Users"]) api_router.include_router(auth.router, prefix="/auth", tags=["Auth"]) api_router.include_router(health.router, prefix="/health", tags=["Health"])

5️⃣ Controller Layer (Endpoints)

api/v1/endpoints/users.py

from fastapi import APIRouter from app.schemas.user import UserCreate router = APIRouter() @router.post("/") def create_user(user: UserCreate): return {"message": "User created"}

6️⃣ Schema (DTO)

schemas/user.py

from pydantic import BaseModel class UserCreate(BaseModel): name: str email: str

7️⃣ Service Layer (Business Logic)

services/user_service.py

def create_user(user): # business rules here return user

8️⃣ Repository Layer (DB Access)

repositories/user_repo.py

def save(user): pass

9️⃣ Dependency Injection (FastAPI Style)

from fastapi import Depends def get_user_service(): return UserService() @router.get("/{id}") def get_user(id: int, service=Depends(get_user_service)): return service.find(id)

➡ Similar concept to @Autowired.


🔟 Environment Configuration

.env

DB_URL=mongodb://localhost:27017/app JWT_SECRET=secret

config.py

from pydantic import BaseSettings class Settings(BaseSettings): DB_URL: str JWT_SECRET: str settings = Settings()

1️⃣1️⃣ Testing Structure

tests/ ├── test_users.py └── conftest.py

Uses:

  • pytest

  • TestClient


1️⃣2️⃣ Production-Grade Tips

✅ Keep business logic out of controllers
✅ Use async DB drivers
✅ Version your APIs (/v1)
✅ Use dependency injection properly
✅ Add middleware for logging
✅ Use Docker for consistency


1️⃣3️⃣ Minimal Structure (For Small Services)

app/ ├── main.py ├── routes.py ├── schemas.py └── services.py

Use this only for small microservices.


Final Thoughts

FastAPI doesn’t force structure like Spring Boot, but teams must enforce discipline.

If you follow the above structure:

  • Code stays clean

  • Team collaboration improves

  • Scaling becomes easy

No comments:

Post a Comment