f5ba8e97f43961145aa0c82d507f53fa98b89650
FastAPI/Best Practices for Structuring Your FastAPI Projects.md
| ... | ... | @@ -0,0 +1,243 @@ |
| 1 | +https://blog.stackademic.com/best-practices-for-structuring-your-fastapi-projects-e66482b27d02 |
|
| 2 | + |
|
| 3 | +# Best Practices for Structuring Your FastAPI Projects | by Joël-Steve N. | Stackademic |
|
| 4 | +A Guide to Organizing Folders and Files |
|
| 5 | +--------------------------------------- |
|
| 6 | + |
|
| 7 | +[ |
|
| 8 | + |
|
| 9 | + |
|
| 10 | + |
|
| 11 | + |
|
| 12 | + |
|
| 13 | +](https://jnikenoueba.medium.com/?source=post_page---byline--e66482b27d02--------------------------------) |
|
| 14 | + |
|
| 15 | +[ |
|
| 16 | + |
|
| 17 | + |
|
| 18 | + |
|
| 19 | + |
|
| 20 | + |
|
| 21 | +](https://blog.stackademic.com/?source=post_page---byline--e66482b27d02--------------------------------) |
|
| 22 | + |
|
| 23 | +Properly structuring a FastAPI project is crucial for maintaining clean, understandable, and scalable code. A well-organized project structure facilitates collaboration among developers and reduces the time needed to add new features or debug issues. In this article, we’ll explore best practices for structuring your FastAPI projects with code examples to help you effectively organize your folders and files. |
|
| 24 | + |
|
| 25 | +1\. Basic Structure of a FastAPI Project |
|
| 26 | +---------------------------------------- |
|
| 27 | + |
|
| 28 | +The basic structure of a FastAPI project can be simplified as follows: |
|
| 29 | + |
|
| 30 | +``` |
|
| 31 | +my_project/ |
|
| 32 | +├── app/ |
|
| 33 | +│ ├── main.py |
|
| 34 | +│ ├── api/ |
|
| 35 | +│ │ ├── __init__.py |
|
| 36 | +│ │ └── controllers/ |
|
| 37 | +│ │ ├── __init__.py |
|
| 38 | +│ │ └── items.py |
|
| 39 | +│ ├── core/ |
|
| 40 | +│ │ ├── __init__.py |
|
| 41 | +│ │ └── config.py |
|
| 42 | +│ ├── models/ |
|
| 43 | +│ │ ├── __init__.py |
|
| 44 | +│ │ └── item.py |
|
| 45 | +│ ├── schemas/ |
|
| 46 | +│ │ ├── __init__.py |
|
| 47 | +│ │ └── item.py |
|
| 48 | +│ ├── crud/ |
|
| 49 | +│ │ ├── __init__.py |
|
| 50 | +│ │ └── item.py |
|
| 51 | +│ ├── db/ |
|
| 52 | +│ │ ├── __init__.py |
|
| 53 | +│ │ └── session.py |
|
| 54 | +│ └── tests/ |
|
| 55 | +│ ├── __init__.py |
|
| 56 | +│ └── test_items.py |
|
| 57 | +├── .env |
|
| 58 | +├── requirements.txt |
|
| 59 | +└── README.md |
|
| 60 | +``` |
|
| 61 | + |
|
| 62 | + |
|
| 63 | +2\. Details of Folder Structure |
|
| 64 | +------------------------------- |
|
| 65 | + |
|
| 66 | +2.1 `main.py` |
|
| 67 | +------------- |
|
| 68 | + |
|
| 69 | +The `**main.py**` file is the entry point of your FastAPI application. It initializes the app and includes the routes. |
|
| 70 | + |
|
| 71 | +**Example:** `**main.py**` |
|
| 72 | + |
|
| 73 | +``` |
|
| 74 | +from fastapi import FastAPI |
|
| 75 | +from app.api.controllers import items |
|
| 76 | +app = FastAPI() |
|
| 77 | +app.include_router(items.router) |
|
| 78 | +@app.get("/") |
|
| 79 | +def read_root(): |
|
| 80 | + return {"message": "Welcome to FastAPI"} |
|
| 81 | +``` |
|
| 82 | + |
|
| 83 | + |
|
| 84 | +2.2 `api/` |
|
| 85 | +---------- |
|
| 86 | + |
|
| 87 | +The `**api/**` folder contains all the API endpoints. It is divided into subfolders for each specific entity or feature of your application. |
|
| 88 | + |
|
| 89 | +**Example:** `**items.py**` **in** `**api/controllers**` |
|
| 90 | + |
|
| 91 | +``` |
|
| 92 | +from fastapi import APIRouter, Depends, HTTPException |
|
| 93 | +from sqlalchemy.orm import Session |
|
| 94 | +from app.schemas.item import Item |
|
| 95 | +from app.crud.item import get_item, create_item |
|
| 96 | +from app.db.session import get_db |
|
| 97 | +router = APIRouter() |
|
| 98 | +@router.post("/items/", response_model=Item) |
|
| 99 | +def create_new_item(item: Item, db: Session = Depends(get_db)): |
|
| 100 | + db_item = get_item(db, item_id=item.id) |
|
| 101 | + if db_item: |
|
| 102 | + raise HTTPException(status_code=400, detail="Item already exists") |
|
| 103 | + return create_item(db=db, item=item) |
|
| 104 | +``` |
|
| 105 | + |
|
| 106 | + |
|
| 107 | +2.3 `core/` |
|
| 108 | +----------- |
|
| 109 | + |
|
| 110 | +The `**core/**` folder contains the configurations and settings of the application, such as database settings, secret keys, etc. |
|
| 111 | + |
|
| 112 | +**Example:** `**config.py**` **in** `**core/**` |
|
| 113 | + |
|
| 114 | +``` |
|
| 115 | +import os |
|
| 116 | +from dotenv import load_dotenv |
|
| 117 | +load_dotenv() |
|
| 118 | +class Settings: |
|
| 119 | + PROJECT_NAME: str = "FastAPI Project" |
|
| 120 | + SQLALCHEMY_DATABASE_URI: str = os.getenv("DATABASE_URL") |
|
| 121 | +settings = Settings() |
|
| 122 | +``` |
|
| 123 | + |
|
| 124 | + |
|
| 125 | +2.4 `models/` |
|
| 126 | +------------- |
|
| 127 | + |
|
| 128 | +The `**models/**` folder contains the database model definitions. Each model represents a table in the database. |
|
| 129 | + |
|
| 130 | +**Example:** `**item.py**` **in** `**models/**` |
|
| 131 | + |
|
| 132 | +``` |
|
| 133 | +from sqlalchemy import Column, Integer, String |
|
| 134 | +from app.db.session import Base |
|
| 135 | +class Item(Base): |
|
| 136 | + __tablename__ = "items" |
|
| 137 | + id = Column(Integer, primary_key=True, index=True) |
|
| 138 | + name = Column(String, index=True) |
|
| 139 | + description = Column(String, index=True) |
|
| 140 | +``` |
|
| 141 | + |
|
| 142 | + |
|
| 143 | +2.5 `schemas/` |
|
| 144 | +-------------- |
|
| 145 | + |
|
| 146 | +The `**schemas/**` folder contains Pydantic schemas used for validating incoming and outgoing data. |
|
| 147 | + |
|
| 148 | +**Example:** `**item.py**` **in** `**schemas/**` |
|
| 149 | + |
|
| 150 | +``` |
|
| 151 | +from pydantic import BaseModel |
|
| 152 | +class Item(BaseModel): |
|
| 153 | + id: int |
|
| 154 | + name: str |
|
| 155 | + description: str |
|
| 156 | + class Config: |
|
| 157 | + orm_mode = True |
|
| 158 | +``` |
|
| 159 | + |
|
| 160 | + |
|
| 161 | +2.6 `crud/` |
|
| 162 | +----------- |
|
| 163 | + |
|
| 164 | +The `**crud/**` folder contains the CRUD (Create, Read, Update, Delete) operations to interact with the database. |
|
| 165 | + |
|
| 166 | +**Example:** `**item.py**` **in** `**crud/**` |
|
| 167 | + |
|
| 168 | +``` |
|
| 169 | +from sqlalchemy.orm import Session |
|
| 170 | +from app.models.item import Item as ItemModel |
|
| 171 | +from app.schemas.item import Item as ItemSchema |
|
| 172 | +def get_item(db: Session, item_id: int): |
|
| 173 | + return db.query(ItemModel).filter(ItemModel.id == item_id).first() |
|
| 174 | +def create_item(db: Session, item: ItemSchema): |
|
| 175 | + db_item = ItemModel(id=item.id, name=item.name, description=item.description) |
|
| 176 | + db.add(db_item) |
|
| 177 | + db.commit() |
|
| 178 | + db.refresh(db_item) |
|
| 179 | + return db_item |
|
| 180 | +``` |
|
| 181 | + |
|
| 182 | + |
|
| 183 | +2.7 `db/` |
|
| 184 | +--------- |
|
| 185 | + |
|
| 186 | +The `**db/**` folder contains the database configurations, including the database session and initialization files. |
|
| 187 | + |
|
| 188 | +**Example:** `**session.py**` **in** `**db/**` |
|
| 189 | + |
|
| 190 | +``` |
|
| 191 | +from sqlalchemy import create_engine |
|
| 192 | +from sqlalchemy.ext.declarative import declarative_base |
|
| 193 | +from sqlalchemy.orm import sessionmaker |
|
| 194 | +from app.core.config import settings |
|
| 195 | +SQLALCHEMY_DATABASE_URL = settings.SQLALCHEMY_DATABASE_URI |
|
| 196 | +engine = create_engine(SQLALCHEMY_DATABASE_URL) |
|
| 197 | +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) |
|
| 198 | +Base = declarative_base() |
|
| 199 | +def get_db(): |
|
| 200 | + db = SessionLocal() |
|
| 201 | + try: |
|
| 202 | + yield db |
|
| 203 | + finally: |
|
| 204 | + db.close() |
|
| 205 | +``` |
|
| 206 | + |
|
| 207 | + |
|
| 208 | +2.8 `tests/` |
|
| 209 | +------------ |
|
| 210 | + |
|
| 211 | +The `**tests/**` folder contains unit and integration tests for your application. Testing your code is crucial to ensure its reliability and stability. |
|
| 212 | + |
|
| 213 | +**Example:** `**test_items.py**` **in** `**tests/**` |
|
| 214 | + |
|
| 215 | +``` |
|
| 216 | +from fastapi.testclient import TestClient |
|
| 217 | +from app.main import app |
|
| 218 | +client = TestClient(app) |
|
| 219 | +def test_create_item(): |
|
| 220 | + response = client.post("/items/", json={"id": 1, "name": "Item 1", "description": "A sample item"}) |
|
| 221 | + assert response.status_code == 200 |
|
| 222 | + assert response.json()["name"] == "Item 1" |
|
| 223 | +``` |
|
| 224 | + |
|
| 225 | + |
|
| 226 | +3\. Conclusion |
|
| 227 | +-------------- |
|
| 228 | + |
|
| 229 | +A good project structure is essential for maintaining clean and scalable code. By following these best practices, you can ensure that your FastAPI project is well-organized, making development, debugging, and collaboration easier. |
|
| 230 | + |
|
| 231 | +**Want to stay updated on FastAPI best practices and tutorials? Subscribe to our newsletter for more insights, tips, and exclusive content.** |
|
| 232 | + |
|
| 233 | +**Subscribe now and enhance your FastAPI projects!** |
|
| 234 | + |
|
| 235 | +Stackademic 🎓 |
|
| 236 | +-------------- |
|
| 237 | + |
|
| 238 | +Thank you for reading until the end. Before you go: |
|
| 239 | + |
|
| 240 | +* Please consider **clapping** and **following** the writer! 👏 |
|
| 241 | +* Follow us [**X**](https://twitter.com/stackademichq) | [**LinkedIn**](https://www.linkedin.com/company/stackademic) | [**YouTube**](https://www.youtube.com/c/stackademic) | [**Discord**](https://discord.gg/in-plain-english-709094664682340443) |
|
| 242 | +* Visit our other platforms: [**In Plain English**](https://plainenglish.io/) | [**CoFeed**](https://cofeed.app/) | [**Differ**](https://differ.blog/) |
|
| 243 | +* More content at [**Stackademic.com**](https://stackademic.com/) |
|
| ... | ... | \ No newline at end of file |