Scaling Up: Structuring Bigger Applications
Scaling Up: Structuring Bigger Applications
Section titled “Scaling Up: Structuring Bigger Applications”Writing everything in a single main.py file is fine for a “Hello World” app, but as your application grows, this becomes unmanageable. Imagine a book where all chapters are written on a single, infinitely long page. Hard to read, right? In this chapter, we will learn how to organize our code into a professional directory structure.
A Professional Directory Structure
Section titled “A Professional Directory Structure”We should separate our logic into modules. A common pattern in FastAPI is to have a dedicated folder (package) for your application logic and a routers subdirectory for your endpoints.
.├── app│ ├── __init__.py│ ├── main.py # The entry point│ ├── dependencies.py # Shared dependencies│ └── routers # Separate modules for path operations│ ├── __init__.py│ ├── items.py # Endpoints related to items│ └── users.py # Endpoints related to usersUsing APIRouter
Section titled “Using APIRouter”The APIRouter class is the key to this separation. It works exactly like the FastAPI class (you can decorate paths with @router.get, etc.), but it is designed to be included in the main application later. Think of it as a “mini-application”.
Here is an example of app/routers/users.py:
from fastapi import APIRouter
router = APIRouter()
@router.get("/users/", tags=["users"])def read_users(): return [{"username": "Rick"}, {"username": "Morty"}]
@router.get("/users/me", tags=["users"])def read_user_me(): return {"username": "fakecurrentuser"}Integrating Routers into the Main App
Section titled “Integrating Routers into the Main App”Once you have defined your routers, you need to bring them together in your app/main.py. We use the .include_router() method.
You can also use this opportunity to define global configurations for a specific router, such as a URL prefix or tags for the automatic documentation.
from fastapi import FastAPIfrom .routers import users, items
app = FastAPI()
# Include the users router# All paths in 'users' will naturally start with /users due to the router definition,# but we can also enforce prefixes here if we want.app.include_router(users.router)
# Include the items router with a prefix# If items.py has a path "/", it becomes "/items/"app.include_router( items.router, prefix="/items", tags=["items"], responses={404: {"description": "Not found"}},)By structuring your application this way, multiple developers can work on different modules simultaneously without conflicts, and your code remains clean and navigable.