fastapi-structure-guide
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseFastAPI Structure Guide (2026 Optimized Edition)
FastAPI 项目结构指南(2026优化版)
Intent
适用场景
Use this guide whenever generating code for a FastAPI project, specifically when:
- Scaffolding a brand new project.
- Adding a new feature (e.g., "Add an Order module").
- Refactoring existing code to meet 2026 clean architecture standards.
You must strictly adhere to the Core Principles, Project Structure, Development Workflow, and Coding Rules defined below.
每当生成FastAPI项目代码时,请遵循本指南,特别是以下场景:
- 搭建全新项目。
- 添加新功能(例如:“添加订单模块”)。
- 重构现有代码以符合2026版整洁架构标准。
你必须严格遵守以下定义的核心原则、项目结构、开发工作流和编码规则。
I. Core Principles
I. 核心原则
Before writing any code, follow these six guiding principles:
-
Separation of Concerns (Clean Architecture)
- API Layer: Only reception, validation, HTTP concerns.
- Service Layer: Pure business logic and orchestration.
- Repository Layer: All data access (SQL, caching, external services).
- DB/Model Layer: Data definition (SQLModel).
- Rule: Never put business logic or raw SQL in API routes or services.
-
Full Async First
- All routes, services, repositories must be by default.
async def - Use +
async_sessionmakereverywhere.await - Only use sync when absolutely necessary (e.g., legacy libs).
- All routes, services, repositories must be
-
Repository Pattern + Dependency Injection
- Services never touch Session directly.
- Use FastAPI +
Dependsfor injection.Annotated - Flow: DB Session → Repository → Service → API Route.
-
Mandatory Use of SQLModel
- All database models and base schemas must use SQLModel (Pydantic v2 + SQLAlchemy 2.0).
- One class serves as both DB table () and API schema base.
table=True - Never use raw SQLAlchemy + separate Pydantic models.
- Always consult for exact syntax, schema variants, relationships, and FastAPI integration patterns.
references/sqlmodel-reference.md
-
Config Centralization
- All config via Pydantic Settings v2 ().
BaseSettings - Never hardcode secrets, URLs, or keys.
- All config via Pydantic Settings v2 (
-
Mirrored & Layered Testing
- mirrors
tests/1:1.app/ - Separate ,
unit/.integration/ - Use SQLite in-memory + dependency overrides + pytest-asyncio.
在编写任何代码之前,请遵循以下六项指导原则:
-
关注点分离(整洁架构)
- API层:仅负责请求接收、验证及HTTP相关处理。
- 服务层:纯业务逻辑与流程编排。
- 仓储层:所有数据访问操作(SQL、缓存、外部服务调用)。
- 数据库/模型层:数据定义(基于SQLModel)。
- 规则:绝不在API路由或服务中编写业务逻辑或原生SQL。
-
全异步优先
- 默认情况下,所有路由、服务、仓储都必须使用定义。
async def - 全程使用+
async_sessionmaker。await - 仅在绝对必要时使用同步代码(例如:遗留库兼容)。
- 默认情况下,所有路由、服务、仓储都必须使用
-
Repository Pattern + 依赖注入
- 服务层绝不直接操作Session。
- 使用FastAPI的+
Depends实现依赖注入。Annotated - 调用流程:数据库Session → 仓储 → 服务 → API路由。
-
强制使用SQLModel
- 所有数据库模型和基础Schema必须使用SQLModel(Pydantic v2 + SQLAlchemy 2.0)。
- 单个类同时作为数据库表()和API Schema基类。
table=True - 禁止同时使用原生SQLAlchemy和独立的Pydantic模型。
- 如需精确语法、Schema变体、关系映射及FastAPI集成模式,请务必参考。
references/sqlmodel-reference.md
-
配置集中化
- 所有配置通过Pydantic Settings v2()管理。
BaseSettings - 绝不硬编码密钥、URL或其他敏感配置。
- 所有配置通过Pydantic Settings v2(
-
镜像分层测试
- 目录结构与
tests/完全1:1镜像。app/ - 分离(单元测试)和
unit/(集成测试)目录。integration/ - 使用SQLite内存数据库、依赖重写及pytest-asyncio。
II. Recommended Project Structure (2026 Standard)
II. 推荐项目结构(2026标准)
text
my-fastapi-project/
├── app/ # Core Application
│ ├── __init__.py
│ ├── main.py # App factory + lifespan
│ ├── api/ # 🌐 API Layer
│ │ ├── __init__.py
│ │ └── v1/
│ │ ├── __init__.py
│ │ ├── api.py # Router aggregation
│ │ └── endpoints/
│ │ ├── __init__.py
│ │ ├── users.py
│ │ └── items.py
│ ├── core/ # ⚙️ Cross-cutting
│ │ ├── __init__.py
│ │ ├── config.py # Settings
│ │ ├── logging.py
│ │ ├── security.py
│ │ └── exceptions.py # Custom HTTP exceptions
│ ├── db/ # 🗄️ Database
│ │ ├── __init__.py
│ │ ├── session.py # async_sessionmaker
│ │ ├── models.py # SQLModel definitions (table=True)
│ │ └── alembic/ # Migrations
│ ├── schemas/ # 📝 API Schemas (DTOs)
│ │ ├── __init__.py
│ │ └── user.py # UserCreate, UserResponse, etc.
│ ├── repositories/ # 🗃️ Data Access Layer (NEW)
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── user_repository.py
│ │ └── item_repository.py
│ ├── services/ # 🧠 Business Logic
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── user_service.py
│ │ └── item_service.py
│ └── dependencies.py # Centralized Depends functions
├── tests/ # ✅ Tests (mirrored)
│ ├── __init__.py
│ ├── conftest.py
│ ├── unit/
│ └── integration/
│ └── api/
│ └── v1/
│ └── endpoints/
│ └── test_users.py
├── .env # Gitignored
├── .env.example
├── .gitignore
├── docker-compose.yaml
├── Dockerfile
├── pyproject.toml # uv + ruff + pyright + pytest-asyncio
└── README.mdtext
my-fastapi-project/
├── app/ # 核心应用代码
│ ├── __init__.py
│ ├── main.py # 应用工厂 + 生命周期管理
│ ├── api/ # 🌐 API层
│ │ ├── __init__.py
│ │ └── v1/
│ │ ├── __init__.py
│ │ ├── api.py # 路由聚合
│ │ └── endpoints/
│ │ ├── __init__.py
│ │ ├── users.py
│ │ └── items.py
│ ├── core/ # ⚙️ 横切关注点
│ │ ├── __init__.py
│ │ ├── config.py # 配置管理
│ │ ├── logging.py
│ │ ├── security.py
│ │ └── exceptions.py # 自定义HTTP异常
│ ├── db/ # 🗄️ 数据库相关
│ │ ├── __init__.py
│ │ ├── session.py # async_sessionmaker配置
│ │ ├── models.py # SQLModel定义(table=True)
│ │ └── alembic/ # 数据库迁移
│ ├── schemas/ # 📝 API Schema(DTO)
│ │ ├── __init__.py
│ │ └── user.py # UserCreate, UserResponse等
│ ├── repositories/ # 🗃️ 数据访问层(新增)
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── user_repository.py
│ │ └── item_repository.py
│ ├── services/ # 🧠 业务逻辑层
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── user_service.py
│ │ └── item_service.py
│ └── dependencies.py # 集中式依赖定义
├── tests/ # ✅ 测试代码(镜像结构)
│ ├── __init__.py
│ ├── conftest.py
│ ├── unit/
│ └── integration/
│ └── api/
│ └── v1/
│ └── endpoints/
│ └── test_users.py
├── .env # 已加入.gitignore
├── .env.example
├── .gitignore
├── docker-compose.yaml
├── Dockerfile
├── pyproject.toml # uv + ruff + pyright + pytest-asyncio配置
└── README.mdDirectory Responsibilities (Updated)
目录职责(更新版)
- : API input/output models (inherits from SQLModel when possible).
app/schemas/ - : All DB operations, caching, external API calls. Thin wrapper around SQLModel.
app/repositories/ - : Business rules, orchestration, validation. Depends on repositories.
app/services/ - : SQLModel classes with
app/db/models.py.table=True - : Custom exceptions + HTTPException handlers.
app/core/exceptions.py
- :API输入/输出模型(尽可能继承自SQLModel)。
app/schemas/ - :所有数据库操作、缓存、外部API调用。是SQLModel的轻量封装。
app/repositories/ - :业务规则、流程编排、校验逻辑。依赖于仓储层。
app/services/ - :带有
app/db/models.py的SQLModel类定义。table=True - :自定义异常 + HTTPException处理器。
app/core/exceptions.py
III. Creation Rules (Development Workflow)
III. 创建规则(开发工作流)
When adding a new feature, follow these 6 Standard Steps in strict order:
Before Step A: Read .
references/sqlmodel-reference.mdStep A: Database Model
Add SQLModel class in (or split file if large).
Add SQLModel class in
app/db/models.pyStep B: API Schemas
Create (Create/Update/Response variants).
Create
app/schemas/resource.pyStep C: Repository
Create (CRUD methods).
Create
app/repositories/resource_repository.pyStep D: Service
Create (business logic using repository).
Create
app/services/resource_service.pyStep E: API Endpoint
Create (thin routes).
Create
app/api/v1/endpoints/resource.pyStep F: Registration & Testing
- Register router in .
app/api/v1/api.py - Write mirrored tests in .
tests/integration/
添加新功能时,请严格按照以下6个标准步骤执行:
步骤A之前:阅读。
references/sqlmodel-reference.md步骤A:数据库模型
在中添加SQLModel类(如果文件过大可拆分)。
在
app/db/models.py步骤B:API Schema
创建(包含Create/Update/Response等变体)。
创建
app/schemas/resource.py步骤C:仓储实现
创建(实现CRUD方法)。
创建
app/repositories/resource_repository.py步骤D:服务实现
创建(基于仓储实现业务逻辑)。
创建
app/services/resource_service.py步骤E:API端点
创建(轻量路由定义)。
创建
app/api/v1/endpoints/resource.py步骤F:注册与测试
- 在中注册新路由。
app/api/v1/api.py - 在中编写镜像结构的测试代码。
tests/integration/
IV. Coding Rules (2026 Modern Examples)
IV. 编码规则(2026现代示例)
Rule 0: SQLModel Strict Compliance
规则0:严格遵守SQLModel规范
All SQLModel code must exactly match patterns in .
Any deviation must be rejected and corrected.
references/sqlmodel-reference.md所有SQLModel代码必须与中的示例完全一致。任何偏差都必须被修正。
references/sqlmodel-reference.mdRule 1: API Routes Must Be Thin & Async
规则1:API路由必须轻量且异步
python
undefinedpython
undefined✅ Correct
✅ 正确示例
@router.post("/users", response_model=UserResponse)
async def create_user(
user_in: UserCreate,
service: UserService = Depends(get_user_service),
):
return await service.create_user(user_in)
undefined@router.post("/users", response_model=UserResponse)
async def create_user(
user_in: UserCreate,
service: UserService = Depends(get_user_service),
):
return await service.create_user(user_in)
undefinedRule 2: Repository Pattern (Data Access)
规则2:Repository Pattern(数据访问)
python
undefinedpython
undefinedapp/repositories/user_repository.py
app/repositories/user_repository.py
from sqlmodel.ext.async_session import AsyncSession
from sqlmodel import select
from app.db.models import User
class UserRepository:
def init(self, session: AsyncSession):
self.session = session
async def create(self, user: User) -> User:
self.session.add(user)
await self.session.commit()
await self.session.refresh(user)
return user
async def get_by_email(self, email: str) -> User | None:
statement = select(User).where(User.email == email)
result = await self.session.exec(statement)
return result.first()undefinedfrom sqlmodel.ext.async_session import AsyncSession
from sqlmodel import select
from app.db.models import User
class UserRepository:
def init(self, session: AsyncSession):
self.session = session
async def create(self, user: User) -> User:
self.session.add(user)
await self.session.commit()
await self.session.refresh(user)
return user
async def get_by_email(self, email: str) -> User | None:
statement = select(User).where(User.email == email)
result = await self.session.exec(statement)
return result.first()undefinedRule 3: Service Layer (Business Logic)
规则3:服务层(业务逻辑)
python
undefinedpython
undefinedapp/services/user_service.py
app/services/user_service.py
class UserService:
def init(self, repo: UserRepository):
self.repo = repo
async def create_user(self, data: UserCreate) -> User:
# Business rules here
if await self.repo.get_by_email(data.email):
raise UserAlreadyExists()
user = User(**data.model_dump(exclude={"password"}))
# hash password etc.
return await self.repo.create(user)undefinedclass UserService:
def init(self, repo: UserRepository):
self.repo = repo
async def create_user(self, data: UserCreate) -> User:
# 业务规则实现
if await self.repo.get_by_email(data.email):
raise UserAlreadyExists()
user = User(**data.model_dump(exclude={"password"}))
# 密码哈希等操作
return await self.repo.create(user)undefinedRule 4: Dependencies (centralized)
规则4:依赖定义(集中化)
python
undefinedpython
undefinedapp/dependencies.py
app/dependencies.py
from fastapi import Depends
from sqlmodel.ext.async_session import async_sessionmaker
async def get_db() -> AsyncSession:
async with sessionmaker() as session: # from db/session.py
yield session
def get_user_repository(db: AsyncSession = Depends(get_db)) -> UserRepository:
return UserRepository(db)
def get_user_service(repo: UserRepository = Depends(get_user_repository)) -> UserService:
return UserService(repo)
undefinedfrom fastapi import Depends
from sqlmodel.ext.async_session import async_sessionmaker
async def get_db() -> AsyncSession:
async with sessionmaker() as session: # 来自db/session.py
yield session
def get_user_repository(db: AsyncSession = Depends(get_db)) -> UserRepository:
return UserRepository(db)
def get_user_service(repo: UserRepository = Depends(get_user_repository)) -> UserService:
return UserService(repo)
undefinedRule 5: SQLModel Usage
规则5:SQLModel使用示例
python
undefinedpython
undefinedapp/db/models.py
app/db/models.py
from sqlmodel import SQLModel, Field
class User(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True)
email: str = Field(index=True, unique=True)
hashed_password: str
undefinedfrom sqlmodel import SQLModel, Field
class User(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True)
email: str = Field(index=True, unique=True)
hashed_password: str
undefined