π§ Why We Need Routers
Right now:
main.pyhasapp = FastAPI()auth.pyalso hadapp = FastAPI()
That creates two separate applications.
What we want instead:
One FastAPI app π (main.py)
Multiple routers π (auth.py, todos.py, etc.)Routers allow us to:
Keep files separated
Keep logic organized
Share the same app instance
Run everything on one port
This is how real backend systems scale.
ποΈ Step 1 β Create a Routers Package
Inside your Todo project folder:
Create a new folder called:
routers/<aside> π‘
you can also create via the terminal using the command
mkdir routers
</aside>
Inside routers/, move:
auth.pyYour structure should now look like:
TodoApp/
βββ routers/
βββ auth.py
βββ main.py
βββ models.py
βββ database.py
βββ todos.dbThis creates modular separation.
<aside> π‘
Create a init.py inside routers/ incase your IDE doesnβt automatically generate one.
cd routers
ni init.py
</aside>
π§© Step 2 β Convert auth.py into a Router
Open:
routers/auth.pyβ Remove FastAPI App Instance
Delete this (if it exists):
from fastapi import FastAPI
app = FastAPI()We no longer want a new application instance.
β Import APIRouter Instead
Now import APIRouter.
from fastapi import APIRouterβ Create a Router Instance
router = APIRouter()β
Replace @app with @router
Update your endpoint:β
@router.get("/auth/")
async def get_user():
return {"user": "authenticated"}π Final Code should look like this
from fastapi import APIRouter
router = APIRouter()
@router.get("/auth/")
async def get_user():
return {"user": "authenticated"}This router will later be attached to the main app.
ποΈ Step 3 β Update main.py
Now open:
main.pyThen import your router:
from routers import authπ Step 4 β Include the Router
Now attach the router to your application:
app.include_router(auth.router)Your main.py should now look like this (simplified):
from typing import Annotated
from pydantic import BaseModel, Field
from sqlalchemy.orm import Session
from fastapi import FastAPI, Depends, HTTPException, Path
from starlette import status
import models
from models import Todos
from database import engine, SessionLocal
from routers import auth
app = FastAPI()
models.Base.metadata.create_all(bind=engine)
app.include_router(auth.router)
... REST OF THE CODE ...π₯οΈ Step 5 β Run the Application
In your terminal:
uvicorn main:app --reloadNow open:
/docsπ What You Will See
You will now see:
β All Todo endpoints
β /auth/ endpoint
All running:
β On the same port
β Inside one FastAPI application
β Under a clean modular architecture
π§ What Is Happening Internally?
When you call:
app.include_router(auth.router)FastAPI:
Takes all endpoints defined in
auth.routerRegisters them inside the main app
Adds them to the OpenAPI schema
Makes them available on the same ASGI app
You now have:
One ASGI app
Multiple modular route groupsThis is production-grade architecture.
ποΈ Scalable Architecture Concept
As your app grows, you can add:
routers/
β
βββ auth.py
βββ todos.py
βββ admin.py
βββ users.pyThen include them in main.py:
app.include_router(auth.router)
app.include_router(todos.router)
app.include_router(admin.router)Clean. Scalable. Maintainable.
ποΈ main.py
from typing import Annotated
from pydantic import BaseModel, Field
from sqlalchemy.orm import Session
from fastapi import FastAPI, Depends, HTTPException, Path
from starlette import status
import models
from models import Todos
from database import engine, SessionLocal
from routers import auth
app = FastAPI()
models.Base.metadata.create_all(bind=engine)
app.include_router(auth.router)
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
db_dependency = Annotated[Session, Depends(get_db)]
class TodoRequest(BaseModel):
title: str = Field(min_length=3)
description: str = Field(min_length=3, max_length=100)
priority: int = Field(gt=0, lt=6)
complete: bool
@app.get("/", status_code=status.HTTP_200_OK)
async def read_all(db: db_dependency):
return db.query(Todos).all()
@app.get("/todo/{todo_id}", status_code=status.HTTP_200_OK)
async def read_todo(db: db_dependency, todo_id: int = Path(gt=0)):
todo_model = db.query(Todos).filter(Todos.id == todo_id).first()
if todo_model is not None:
return todo_model
else:
raise HTTPException(status_code=404, detail='Todo Not Found')
@app.post("/todo/", status_code=status.HTTP_201_CREATED)
async def create_todo(db: db_dependency, todo_request: TodoRequest):
todo_model = Todos(**todo_request.model_dump())
db.add(todo_model)
db.commit()
@app.put("/todo/{todo_id}", status_code=status.HTTP_204_NO_CONTENT)
async def update_todo(
db: db_dependency,
todo_request: TodoRequest,
todo_id: int = Path(gt=0)):
todo_model = db.query(Todos).filter(Todos.id == todo_id).first()
if todo_model is None:
raise HTTPException(status_code=404, detail="Todo not found.")
todo_model.title = todo_request.title
todo_model.description = todo_request.description
todo_model.priority = todo_request.priority
todo_model.complete = todo_request.complete
db.commit()
@app.delete("/todo/{todo_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_todo(
db: db_dependency,
todo_id: int = Path(gt=0)):
todo_model = db.query(Todos).filter(Todos.id == todo_id).first()
if todo_model is None:
raise HTTPException(status_code=404, detail="Todo not found.")
db.delete(todo_model)
db.commit()ποΈ routers/auth.py
from fastapi import APIRouter
router = APIRouter()
@router.get("/auth/")
async def get_user():
return {"user": "authenticated"}No Changes in Other files
Current Folder Structure
TodoApp/
βββ routers/
βββ auth.py
βββ main.py
βββ models.py
βββ database.py
βββ todos.db