# FastApiDDD **Repository Path**: LI_Mowu/fastapiDDD ## Basic Information - **Project Name**: FastApiDDD - **Description**: 使用fastAPI构建的微服务应用程序架构 - **Primary Language**: Python - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 0 - **Created**: 2026-05-26 - **Last Updated**: 2026-07-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: ddd, FastAPI ## README # FastDDD > 一个生产级 **FastAPI** 快速启动模板,采用 **领域驱动设计(DDD)** 分层架构。 [![Python](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/) [![FastAPI](https://img.shields.io/badge/FastAPI-0.139+-009688.svg)](https://fastapi.tiangolo.com/) [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE) --- ## 特性 - ⚡ **异步 FastAPI** + Uvicorn — 高性能异步 Web 服务 - 🗄️ **SQLAlchemy 2.0 异步** + **SQLModel** ORM + **PostgreSQL** + asyncpg - 🔐 **JWT 认证**,支持角色权限控制(普通用户 / 超级管理员) - 🏗️ **领域驱动设计**分层:core / models / schemas / services / dependences / middlewares / routers - 📦 **统一响应格式**中间件 — 一致的 `{code, message, data}` JSON 响应 - 🔍 **请求 ID 中间件** — X-Request-ID 请求头,方便链路追踪 - 📝 **Loguru** 结构化日志,支持按日期滚动、自动压缩 - ⚙️ **pydantic-settings** 类型安全的 `.env` 配置管理 - ♻️ **CRUDBase** 泛型服务基类 — 任意模型复用 CRUD 逻辑 - 📌 **版本化 API 路由** (`/api/v1`),为后续 API 版本迭代做好准备 - 📖 **Swagger UI** 内建 OAuth2 Bearer 认证,开箱即用 - 🔧 **极低样板代码** — 快速开始编写你的业务逻辑 ## 技术栈 | 层级 | 技术选型 | |---|---| | Web 框架 | FastAPI + Uvicorn | | ORM | SQLAlchemy 2.0 (异步) + SQLModel | | 数据库 | PostgreSQL + asyncpg | | 认证 | JWT (PyJWT) + OAuth2PasswordBearer + passlib (bcrypt) | | 配置 | pydantic-settings | | 日志 | Loguru | | Python | 3.12+ | ## Python 依赖 所有直接依赖在 `backend/pyproject.toml` 中声明版本范围,由 `backend/uv.lock` 锁定精确版本,同时导出为 `backend/requirements.txt` 供 pip 用户使用。 | 包名 | 版本约束 | 锁定版本 | 用途 | |---|---|---|---| | fastapi | `>=0.136.0` | 0.139.0 | Web 框架 | | uvicorn[standard] | `>=0.46.0` | 0.50.2 | ASGI 服务器 | | sqlmodel[asyncio] | `>=0.0.38` | 0.0.39 | 异步 ORM (SQLAlchemy + Pydantic) | | asyncpg | `>=0.30.0` | 0.31.0 | 异步 PostgreSQL 驱动 | | pydantic[email] | `>=2.13.4` | 2.13.4 | 数据校验与邮箱 | | pydantic-settings | `>=2.0.0` | 2.14.2 | 类型安全的环境变量配置 | | python-jose[cryptography] | `>=3.3.0` | 3.5.0 | JWT 编解码 | | pyjwt | `>=2.13.0` | 2.13.0 | JWT 工具库 | | passlib[bcrypt] | `>=1.7.4` | 1.7.4 | 密码哈希上下文 | | **bcrypt** | **`>=4.0.0,<4.4.0`** | **4.3.0** | **bcrypt 哈希后端** | | httpx | `>=0.28.0` | 0.28.1 | HTTP 客户端 | | greenlet | `>=3.0.0` | 3.5.3 | 异步支持 | | python-multipart | `>=0.0.32` | 0.0.32 | 表单数据解析 | | loguru | `>=0.7.0` | 0.7.3 | 结构化日志 | > ⚠️ **bcrypt 版本注意:** bcrypt 锁定在 `>=4.0.0,<4.4.0` 范围。版本 **5.0.0** 引入了严格的 72 字节密码长度检查,会在 passlib 验证密码时抛出 `ValueError`。除非同时在 `UserService` 中添加密码截断逻辑,否则不要移除版本上限。 ## 项目结构 ``` fastapiDDD/ ├── README.md ├── README_zh.md ├── LICENSE ├── .gitignore ├── backend/ │ ├── run.py # 开发启动入口 │ ├── pyproject.toml # 项目元数据与依赖声明 │ ├── requirements.txt # 依赖锁定版本 │ ├── .env.example # 环境变量配置模板 │ └── app/ │ ├── main.py # FastAPI 应用工厂 │ ├── core/ │ │ ├── config.py # pydantic-settings 配置 │ │ ├── database.py # 异步引擎与会话管理 │ │ ├── exception_handlers.py # 全局异常处理 │ │ └── log.py # Loguru 日志初始化 │ ├── dependences/ │ │ └── __init__.py # 依赖注入(数据库、服务、认证守卫) │ ├── middlewares/ │ │ ├── __init__.py # 中间件注册(CORS、请求ID、响应包装) │ │ ├── request_id.py # X-Request-ID 中间件 │ │ └── response_wrapper.py # 统一响应格式中间件 │ ├── models/ │ │ ├── base.py # 基础模型(UUID主键 + 时间戳) │ │ └── user.py # 用户领域模型 │ ├── schemas/ │ │ ├── response_model.py # BaseResponse 通用响应与错误模型 │ │ ├── token.py # Token 与 OAuth2 表单模型 │ │ ├── user.py # UserCreate / UserUpdate / UserRead │ │ └── page.py # 分页模型 │ ├── services/ │ │ ├── base.py # CRUDBase 泛型服务基类 │ │ ├── user.py # 用户服务(密码哈希、校验等) │ │ └── token.py # 令牌服务(登录、JWT 生成) │ └── v1/api/ │ ├── __init__.py # setup_routers() 路由注册 │ ├── route.py # 子路由聚合 │ └── routers/ │ ├── health.py # 健康检查接口 │ ├── token.py # 登录接口 │ └── users.py # 用户 CRUD 接口 └── frontend/ # React + TypeScript + Vite(规划中) └── .gitkeep ``` ## 快速开始 ### 前置条件 - Python 3.12+ - PostgreSQL(已运行实例) - [uv](https://docs.astral.sh/uv/) 或 pip ### 安装步骤 ```bash # 1. 克隆仓库 git clone https://github.com//fastapiDDD.git cd fastapiDDD/backend # 2. 创建虚拟环境并安装依赖 uv sync # 使用 uv # 或:python -m venv .venv && source .venv/bin/activate && pip install -r requirements.txt # 3. 配置环境变量 cp .env.example .env # 编辑 .env 填入你的 PostgreSQL 连接信息 # 4. 创建数据库 createdb fastddd # 或与 .env 中 POSTGRES_DB 保持一致 # 5. 启动开发服务器 python run.py ``` 访问 **http://127.0.0.1:8000/docs** 进入 Swagger UI 交互式文档。 ### Windows ```bash cd backend python -m venv .venv .venv\Scripts\activate pip install -r requirements.txt cp .env.example .env python run.py ``` ## 配置说明 所有配置通过 pydantic-settings 从 `backend/.env` 文件加载。复制 `.env.example` 作为起点: | 变量 | 说明 | 默认值 | |---|---|---| | `SERVICE_NAME` | 应用名称 | `fastDDD` | | `SERVICE_MODE` | 运行模式(`dev`/`test`/`prod`) | `dev` | | `SERVICE_HOST` | 绑定地址 | `0.0.0.0` | | `SERVICE_PORT` | 绑定端口 | `8000` | | `CORS_ORIGINS` | 允许的跨域来源(逗号分隔) | `*` | | `API_V1_STR` | API 版本前缀 | `/api/v1` | | `JWT_SECRET_KEY` | JWT 签名密钥(**生产环境务必修改!**) | `change-me-in-production` | | `JWT_ALGORITHM` | JWT 签名算法 | `HS256` | | `JWT_ACCESS_TOKEN_EXPIRE_MINUTES` | 令牌过期时间(分钟) | `1440` | | `POSTGRES_USER` | 数据库用户名 | `postgres` | | `POSTGRES_PASSWORD` | 数据库密码 | `password` | | `POSTGRES_DB` | 数据库名称 | `fastddd` | | `POSTGRES_HOST` | 数据库主机 | `localhost` | | `POSTGRES_PORT` | 数据库端口 | `5432` | | `SQLALCHEMY_ECHO` | 是否打印 SQL 语句 | `False` | | `LOGURU_LEVEL` | 日志级别 | `INFO` | ## 测试 ```bash cd backend python -m unittest discover -t . -s test # 激活 venv 后执行 ``` - 全部测试基于**内存 SQLite**(aiosqlite),无需 PostgreSQL - 路由测试通过 `httpx.ASGITransport` 直连 app,不启动真实服务 - 目录结构:`test/base_tsst`(公共基建)、`test/app`(应用级行为)、`test/token`、`test/user`(与路由结构对齐) ## Docker 部署 ```bash bash display.sh # 检查 .env → 自动生成 JWT 密钥 → compose down/build/up → 健康检查 ``` > 启动时(lifespan)自动创建缺失的数据表,无需手动建表。 compose 编排**不内置数据库服务**——请接入你自己的 PostgreSQL,并按部署形态设置 `POSTGRES_HOST`: | 数据库位置 | `POSTGRES_HOST` 取值 | |---|---| | 本机直跑应用 | `localhost` | | 应用在 Docker、数据库在宿主机 | `host.docker.internal`(Linux 需给 backend 服务加 `extra_hosts: ["host.docker.internal:host-gateway"]`) | | 远程 / 托管实例 | 实际地址 | ## API 接口 | 方法 | 路径 | 认证 | 说明 | |---|---|---|---| | `GET` | `/api/v1/health` | — | 健康检查 | | `POST` | `/api/v1/token/login` | — | 用户登录(包装响应) | | `POST` | `/api/v1/token/login_swagger` | — | Swagger OAuth2 登录(裸 Token) | | `GET` | `/api/v1/users` | 管理员 | 用户列表(分页,offset≥0,1≤limit≤100) | | `GET` | `/api/v1/users/{id}` | 管理员 | 根据 ID 获取用户 | | `POST` | `/api/v1/users` | 管理员 | 创建用户 | | `PATCH` | `/api/v1/users/{id}` | 管理员 | 更新用户 | | `DELETE` | `/api/v1/users/{id}` | 管理员 | 删除用户 | ## 统一响应格式 所有 API 响应(除 `/token/login_swagger` 外)均包装为统一格式: **成功响应:** ```json { "code": 200, "message": "Success", "data": { ... }, "detail": "" } ``` **错误响应:** ```json { "code": 422, "message": "Unprocessable Entity", "data": null, "detail": [{ "loc": ["body", "email"], "msg": "field required" }] } ``` ## 认证机制 - **JWT Bearer Token** — 通过 `POST /api/v1/token/login` 提交邮箱和密码获取令牌 - **两种角色:** - 普通用户(`is_active=True`)— 可登录获取令牌 - 超级管理员(`is_superuser=True`)— 可访问全部 `/users` 接口(查询/创建/更新/删除) - Swagger UI 支持 OAuth2 认证:点击 **Authorize**,使用 `/api/v1/token/login_swagger` 接口获取令牌 ## 架构设计 FastDDD 遵循 **领域驱动设计(DDD)** 原则,针对 FastAPI 做了适配: | 分层 | 目录 | 职责 | |---|---|---| | **基础设施** | `app/core/` | 横切关注点:配置、数据库、日志、异常处理 | | **领域模型** | `app/models/` | 领域实体与 ORM 映射(SQLModel) | | **数据模型** | `app/schemas/` | Pydantic DTO,请求校验与响应序列化 | | **应用服务** | `app/services/` | 业务逻辑(继承 `CRUDBase[ModelType]` 泛型基类) | | **依赖注入** | `app/dependences/` | FastAPI Depends 注入与认证守卫 | | **中间件** | `app/middlewares/` | HTTP 层横切:兜底异常、CORS、请求ID、响应包装 | | **路由层** | `app/v1/api/routers/` | API 路由处理(表现层) | 添加一个新的领域实体只需五步: 1. 在 `app/models/` 中创建数据模型 2. 在 `app/schemas/` 中创建 Pydantic 模型 3. 在 `app/services/` 中创建服务类(继承 `CRUDBase`) 4. 在 `app/dependences/` 中添加依赖注入 5. 在 `app/v1/api/routers/` 中创建路由处理 ## 前端 React + TypeScript + Vite 前端正在规划中,尚未实现。`frontend/` 目录目前仅包含占位文件。 ## 改进记录(dev_master) 自初始版本以来的关键修复与增强: | 分类 | 项目 | 说明 | |---|---|---| | **安全** | 500 响应脱敏 | 内部错误详情不再泄露到 API 响应,仅暴露 `request_id` 关联 UUID | | **安全** | 用户接口管理员收敛 | `GET /users` 和 `GET /users/{id}` 现在要求管理员角色 | | **安全** | JWT 密钥自动生成 | `display.sh` 首次部署时自动生成随机 JWT 密钥 | | **数据完整性** | 事务提交时机 | `commit()` 从依赖 teardown 移至 CRUDBase 方法内,防止"响应成功但数据未写入" | | **可靠性** | 唯一约束冲突处理 | 重复用户名/邮箱现在返回 400 而非 500 | | **可靠性** | 校验错误编码 | 自定义 Pydantic 校验器抛出 `ValueError` 不再导致 500 错误 | | **基础设施** | 兜底异常中间件 | 未处理异常现在携带 CORS 头,避免浏览器在 500 响应时出现 CORS 错误 | | **基础设施** | Docker 代理头 | uvicorn CMD 增加 `--proxy-headers`,nginx 的 `X-Forwarded-For` 可传递到应用 | | **配置** | CORS 来源可配置 | 新增 `CORS_ORIGINS` 字段,逗号分隔,默认 `*` | | **配置** | `SERVICE_MODE` | 新增运行模式配置(`dev`/`test`/`prod`) | | **配置** | `SQLALCHEMY_ECHO` 默认值 | 从 `True` 改为 `False`(更安全的生产默认值) | | **修复** | 页码计算 | `page_num` 改为 `offset // limit + 1` 而非原始偏移量 | | **新增** | httpx 客户端管理器 | 共享 `httpx.AsyncClient` 单例 + lifespan 管理(外部 HTTP 调用延迟降低 50-70 倍) | ## 开源协议 本项目基于 [MIT License](LICENSE) 开源。