FastAPI File Structure and Design Considerations
Designing an appropriate directory structure for a FastAPI project enhances readability and maintainability. This article provides a detailed explanation of the basic file structure and key points to consider during design.
1. Basic FastAPI Project Structure
For small FastAPI projects, a single main.py
file may suffice. However, as the project grows, organizing directories properly becomes crucial. The following structure is commonly used:
Example Directory Structure
my_fastapi_project/
│── app/
│ │── main.py # Entry point of the application
│ │── routers/ # Directory for splitting routing
│ │ │── __init__.py
│ │ │── user.py # API routes related to users
│ │ │── item.py # API routes related to items
│ │── models/ # Definitions for SQLAlchemy models
│ │ │── __init__.py
│ │ │── user.py
│ │ │── item.py
│ │── schemas/ # Pydantic schema definitions
│ │ │── __init__.py
│ │ │── user.py
│ │ │── item.py
│ │── database.py # Database connection settings
│ │── dependencies.py # Dependency management
│ │── config.py # Configuration file (e.g., environment variables)
│── tests/ # Test-related files
│ │── test_main.py
│── .env # Environment variables
│── requirements.txt # Required packages
│── README.md # Project documentation
│── Dockerfile # Docker configuration
2. Roles of Each File and Directory
1. main.py
This is the entry point of the application. It contains the basic FastAPI startup process.
from fastapi import FastAPI
from app.routers import user, item
app = FastAPI()
# Registering routers
app.include_router(user.router)
app.include_router(item.router)
@app.get("/")
def read_root():
return {"message": "Welcome to FastAPI!"}
2. routers/
(Routing Separation)
By separating API endpoints by function, the code becomes more organized.
routers/user.py
from fastapi import APIRouter
router = APIRouter()
@router.get("/users/")
def get_users():
return [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]
routers/item.py
from fastapi import APIRouter
router = APIRouter()
@router.get("/items/")
def get_items():
return [{"id": 101, "name": "Item A"}, {"id": 102, "name": "Item B"}]
3. models/
(Database Models)
When using SQLAlchemy, define database models here.
models/user.py
from sqlalchemy import Column, Integer, String
from app.database import Base
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, index=True)
4. schemas/
(Data Schemas)
Define request and response data types using Pydantic.
schemas/user.py
from pydantic import BaseModel
class UserSchema(BaseModel):
id: int
name: str
5. database.py
(Database Connection)
Manages the database connection settings.
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
6. dependencies.py
(Dependency Management)
Manages dependencies and sets up Dependency Injection (DI).
from app.database import SessionLocal
from fastapi import Depends
from sqlalchemy.orm import Session
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
3. Design Considerations
1. Separate Routers by Function
Placing all API endpoints in one file makes management difficult. Creating a routers/
directory and organizing routes by function is ideal.
2. Use schemas/
to Standardize Requests/Responses
By defining request and response schemas using Pydantic, data consistency is maintained, and validation becomes easier.
3. Manage Dependencies in dependencies.py
Centralized dependency management improves testability and reusability.
4. Store Environment Variables in .env
Database connection details and API keys should be stored in .env
and excluded from version control using .gitignore
.
.env
DATABASE_URL=postgresql://user:password@localhost/db
config.py
from pydantic import BaseSettings
class Settings(BaseSettings):
database_url: str
class Config:
env_file = ".env"
settings = Settings()
5. Create Test Code in tests/
Using pytest
makes it easy to test FastAPI endpoints.
test_main.py
from fastapi.testclient import TestClient
from app.main import app
client = TestClient(app)
def test_read_root():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"message": "Welcome to FastAPI!"}
4. Summary
- A well-structured directory improves readability and maintainability.
- Separate routes into
routers/
by function. - Define database models in
models/
and schemas inschemas/
. - Manage dependencies in
dependencies.py
and store environment variables in.env
. - Write tests in
tests/
to ensure quality.
By following these guidelines, you can build a scalable FastAPI project!