简介:本文详细解析 FastAPI 项目结构搭建方法,提供模块化设计、路由组织、依赖管理等核心实践方案,助力开发者快速构建可维护的 Web API 系统。
FastAPI 作为现代 Python Web 框架的代表,凭借其高性能、自动文档生成和异步支持特性,已成为构建 Web API 的首选工具。然而,随着项目规模扩大,合理的项目结构对代码可维护性和团队协作至关重要。本文将系统阐述 FastAPI 项目结构的构建方法,涵盖模块化设计、路由组织、依赖管理等核心实践。
典型 FastAPI 项目应采用分层架构,建议目录结构如下:
project_root/├── app/ # 主应用目录│ ├── __init__.py # 应用初始化│ ├── main.py # 入口文件│ ├── core/ # 核心配置│ │ ├── config.py # 环境变量配置│ │ └── security.py # 安全相关│ ├── models/ # 数据模型│ │ ├── schemas.py # Pydantic 模型│ │ └── entities.py # 数据库实体│ ├── routers/ # 路由模块│ │ ├── api_v1/ # API 版本控制│ │ │ ├── users.py│ │ │ └── items.py│ │ └── ...│ ├── services/ # 业务逻辑│ │ └── user_service.py│ ├── db/ # 数据库相关│ │ ├── base.py # 数据库基类│ │ └── repository.py # 数据访问层│ └── utils/ # 工具函数│ └── helpers.py└── tests/ # 测试目录
这种结构实现了关注点分离:路由处理、业务逻辑、数据访问各自独立。main.py 仅需负责应用启动和中间件注册:
from fastapi import FastAPIfrom app.routers.api_v1 import api_routerfrom app.core.config import settingsapp = FastAPI(title=settings.PROJECT_NAME)app.include_router(api_router, prefix=settings.API_V1_STR)
FastAPI 的依赖注入系统应集中管理。在 core/dependencies.py 中定义公共依赖:
from fastapi import Depends, HTTPExceptionfrom jose import JWTError, jwtfrom app.core.config import settingsfrom app.models.entities import Userfrom app.db.repository import UserRepositoryasync def get_current_user(token: str = Depends(oauth2_scheme),user_repo: UserRepository = Depends()) -> User:try:payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])user_id = payload.get("sub")if user_id is None:raise HTTPException(status_code=401, detail="Invalid authentication credentials")return await user_repo.get_by_id(user_id)except JWTError:raise HTTPException(status_code=401, detail="Could not validate credentials")
实现版本控制需创建路由前缀:
# app/routers/api_v1/__init__.pyfrom fastapi import APIRouterfrom . import users, itemsapi_router = APIRouter()api_router.include_router(users.router, prefix="/users", tags=["users"])api_router.include_router(items.router, prefix="/items", tags=["items"])
版本升级时,只需创建 api_v2 目录并修改主路由引入,避免破坏性变更。
利用 Pydantic 模型进行请求体验证:
# app/models/schemas.pyfrom pydantic import BaseModel, EmailStrfrom typing import Optionalclass UserCreate(BaseModel):email: EmailStrpassword: strfull_name: Optional[str] = Noneclass UserUpdate(BaseModel):full_name: Optional[str] = Nonebio: Optional[str] = None
路由处理中直接使用模型:
# app/routers/api_v1/users.pyfrom fastapi import APIRouter, HTTPExceptionfrom app.models.schemas import UserCreate, UserUpdatefrom app.services.user_service import UserServicerouter = APIRouter()@router.post("/", response_model=User)async def create_user(user_in: UserCreate) -> User:try:return await UserService.create_user(user_in)except ValueError as e:raise HTTPException(status_code=400, detail=str(e))
服务层应封装核心业务逻辑,保持路由简洁:
# app/services/user_service.pyfrom app.models.schemas import UserCreate, UserUpdatefrom app.db.repository import UserRepositoryfrom app.core.security import get_password_hashclass UserService:@staticmethodasync def create_user(user_in: UserCreate) -> User:user_data = user_in.dict()user_data["password"] = get_password_hash(user_data["password"])return await UserRepository.create(user_data)@staticmethodasync def update_user(user_id: int, user_update: UserUpdate) -> User:# 业务逻辑处理pass
数据访问层使用仓储模式隔离数据库操作:
# app/db/repository.pyfrom typing import Optionalfrom app.models.entities import Userfrom app.db.base import BaseRepositoryclass UserRepository(BaseRepository):async def get_by_email(self, email: str) -> Optional[User]:return await self.db.query(User).filter(User.email == email).first()async def create(self, user_data: dict) -> User:db_user = User(**user_data)self.db.add(db_user)await self.db.commit()return db_user
结合 Celery 处理耗时任务:
# app/worker.pyfrom celery import Celerycelery = Celery("worker",broker=settings.CELERY_BROKER_URL,backend=settings.CELERY_RESULT_BACKEND)@celery.taskdef process_image(image_path: str):# 异步处理逻辑pass
在 FastAPI 中通过后台任务触发:
from fastapi import BackgroundTasks@router.post("/upload")async def upload_image(file: UploadFile,background_tasks: BackgroundTasks):background_tasks.add_task(process_image.delay, file.filename)return {"message": "Image processing started"}
添加 Prometheus 监控端点:
from prometheus_client import Counter, generate_latestfrom fastapi import Request, ResponseREQUEST_COUNT = Counter("app_requests_total","Total number of requests",["method", "endpoint"])@app.get("/metrics")async def metrics(request: Request):REQUEST_COUNT.labels(method=request.method, endpoint=request.url.path).inc()return Response(content=generate_latest(), media_type="text/plain")
典型项目初始化脚本示例:
# scripts/init_db.pyfrom app.db.base import get_dbfrom app.models.entities import Basefrom sqlalchemy.ext.asyncio import AsyncSession, create_async_enginefrom sqlalchemy.orm import sessionmakerasync def init_db():engine = create_async_engine(settings.SQLALCHEMY_DATABASE_URI)async with engine.begin() as conn:await conn.run_sync(Base.metadata.create_all)async def main():async with get_db() as db:# 初始化数据操作passif __name__ == "__main__":import asyncioasyncio.run(init_db())
通过遵循上述结构规范,FastAPI 项目可实现:
这种结构已被多个中大型项目验证,特别适合需要快速迭代且保持代码质量的 Web API 开发场景。建议开发者根据项目规模灵活调整,在保持核心架构不变的前提下进行适当扩展。