Building Bigger FastAPI Applications with Multiple Separate Files in Python
We typically do not keep everything in a single file when building an application or web APIs. In this tutorial, you will learn how to organize code in separate files within a FastAPI project.
Here's a step-by-step guide on how to do this:
- Start by creating a new folder with the name of your project:
- Navigate to your newly created project folder:
- Create a virtual environment inside the project root directory using the following command:
- Activate the virtual environment using the command:
- Install FastAPI:
- Install uvicorn. Uvicorn is an implementation of ASGI server for fast performance. Use the following command to install uvicorn:
- Create a directory structure for your FastAPI project. A common structure should look like this:
- Create a model file named user.py in the src/models directory:
- Create another model file named product.py in the src/models directory:
- Create a service file named user_service.py in the src/endpoints directory:
- Create another service file named product_service.py in the src/endpoints directory:
- Create a route file named api.py in the routes/ directory:
- Create a main file named main.py in the project's root directory:
- Run the application:
mkdir project_name
cd project_name
py -m venv env
python3 -m venv env
.\env\Scripts\activate
source env/bin/activate
pip install fastapi
pip install "uvicorn[standard]"
├── project_name │ │── env │ ├── routes │ │ └── api.py │ ├── src │ │ ├── __init__.py │ │ ├── endpoints │ │ │ ├── __init__.py │ │ │ ├── product_service.py │ │ │ └── user_service.py │ │ │ │ │ └── models │ │ ├── __init__.py │ │ ├── product.py │ │ └── user.py │ ├── __init__.py │ ├── main.py
There are folders named models and endpoints inside the src folder. The models folder contains user.py and product.py files. Similarly, the endpoints folder contains user_service.py and product_service.py files with API endpoints.
There is a __init__.py file in every directory or subdirectory. This presence of __init__.py files allows importing code from one file into another.
from pydantic import BaseModel, Field
from typing import Optional
class UserModel(BaseModel):
user_id: Optional[int] = None
first_name: str
last_name: str
email: str
father_name: Optional[str] = Field(
None, title="The father name of the User", max_length=300
)
age: float = Field(..., gt=0,
description="The age must be greater than zero")
from pydantic import BaseModel, Field
from typing import Optional
class ProductModel(BaseModel):
item_id: Optional[int] = None
name: str
code: str
description: Optional[str] = Field(
None, title="The description of the Product", max_length=300
)
price: float = Field(..., gt=0,
description="The price must be greater than zero")
from fastapi import APIRouter
from fastapi import Query
from src.models.user import UserModel
from typing import Optional
#APIRouter creates path operations for user module
router = APIRouter(
prefix="/users",
tags=["User"],
responses={404: {"description": "Not found"}},
)
@router.get("/")
async def read_root():
return [{"id": 1}, {"id": 2}]
@router.get("/{user_id}")
async def read_user(user_id: int):
return {"id": user_id, "full_name": "Danny Manny", "email": "danny.manny@gmail.com"}
@router.get("/detail")
async def read_users(q: Optional[str] = Query(None, max_length=50)):
results = {"users": [{"id": 1}, {"id": 2}]}
if q:
results.update({"q": q})
return results
@router.post("/add")
async def add_user(user: UserModel):
return {"full_name": user.first_name+" "+user.last_name}
@router.put("/update")
async def read_user(user: UserModel):
return {"id": user.user_id, "full_name": user.first_name+" "+user.last_name, "email": user.email}
@router.delete("/{user_id}/delete")
async def read_user(user_id: int):
return {"id": user_id, "is_deleted": True}
from fastapi import APIRouter
from typing import Optional
from fastapi import Query
from src.models.product import ProductModel
#APIRouter creates path operations for item module
router = APIRouter(
prefix="/products",
tags=["Product"],
responses={404: {"description": "Not found"}},
)
@router.get("/")
async def read_root():
return [{"id":1,"product": "Laptop"}, {"id":2,"product": "Mobile"}]
@router.get("/{product_id}")
async def read_item(product_id: int):
return {"id": product_id, "name": "Mobile", "code": "M12", "price": 200.0}
@router.get("/detail")
async def read_item_detail(q: Optional[str] = Query(None, max_length=50)):
results = {"products": [{"id": 1}, {"id": 2}]}
if q:
results.update({"q": q})
return results
@router.post("/add")
async def add_item(product: ProductModel):
return {"name": product.name+", code:"+product.code}
@router.put("/update")
async def update_item(product: ProductModel):
return {"id": product.item_id, "name": product.name, "code":product.code, "price": product.price}
@router.delete("/{product_id}/delete")
async def delete_item(product_id: int):
return {"id": product_id, "is_deleted": True}
from fastapi import APIRouter
from src.endpoints import product_service, user_service
router = APIRouter()
router.include_router(product_service.router)
router.include_router(user_service.router)
import uvicorn
from fastapi.middleware.cors import CORSMiddleware
from fastapi import FastAPI
from routes.api import router as api_router
app = FastAPI()
origins = ["http://localhost:8005"]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.include_router(api_router)
if __name__ == '__main__':
uvicorn.run("main:app", host='127.0.0.1', port=8005, log_level="info", reload=True)
print("running")
python main.py
Run your application and open http://127.0.0.1:8005/docs in your web browser. You will see list of APIs that you can test.