第 1 章 · FastAPI 简介与环境搭建
本章目标:理解 FastAPI 是什么、它和 Starlette/Pydantic 的关系,装好开发环境,跑起第一个带热重载的最小应用。
1.1 FastAPI 是什么
FastAPI 是一个现代、高性能的 Python Web 框架,专为构建 API 而设计。理解它的关键是看清三层结构:
- Starlette:底层 ASGI 框架,负责路由、请求/响应、中间件、WebSocket 这些 Web 基础设施。FastAPI 的异步能力和性能直接来自它;
- Pydantic:数据校验与序列化库(v2 核心用 Rust 编写),负责把请求里的 JSON 变成带类型校验的 Python 对象;
- FastAPI 本身:把两者粘合起来的"类型驱动"胶水层——你在函数签名上写类型注解,它就自动完成参数解析、校验、序列化和文档生成。
# 一个最小的 FastAPI 应用:main.py
from fastapi import FastAPI
app = FastAPI() # 创建应用实例,所有路由都注册在它身上
@app.get("/")
def read_root():
return {"message": "Hello World"} # 返回 dict 会自动序列化为 JSON类型注解为什么是"核心"
FastAPI 的全部魔法入口就是函数签名的类型注解:参数标了 int 它就帮你从路径/查询串里解析并校验整数;参数是 Pydantic 模型它就从请求体读取;返回值有模型注解它就过滤并序列化输出。注解写得越准,框架替你做的事越多——这也是本教程反复强调 Annotated 写法的原因。
1.2 安装
推荐安装带标准依赖的完整包:
python -m venv .venv && source .venv/bin/activate
pip install "fastapi[standard]"fastapi[standard] 额外包含:
- uvicorn:高性能 ASGI 服务器(真正运行你的应用的就是它);
- fastapi-cli:提供
fastapi dev/fastapi run命令行工具; - 常用可选依赖(
email-validator、httpx、jinja2等),后面章节会用到。
验证安装:
$ fastapi --version
# FastAPI 0.141.x1.3 启动与热重载
把 1.1 的代码保存为 main.py,然后:
$ fastapi dev main.py
INFO Will watch for changes in these directories: [...]
INFO Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO Started reloader process [383138] using WatchFiles
INFO Application startup complete.打开 http://127.0.0.1:8000 就能看到 {"message":"Hello World"}。
关于这几个命令的关系,初学者最容易混:
| 命令 | 用途 | 特点 |
|---|---|---|
fastapi dev main.py | 开发模式 | 自动发现 app、文件改动自动重启 |
fastapi run main.py | 生产模式 | 不监视文件变化,按生产配置启动 |
uvicorn main:app --reload | 手动开发 | fastapi dev 内部就是包装了 uvicorn |
开发/生产要用不同命令
fastapi dev 的重载进程会监视整个目录,在生产环境既浪费资源又有安全风险。部署时请使用 fastapi run 或直接用 uvicorn/gunicorn(第 22 章详讲)。
如果不用 CLI,也可以完全手动启动:
# run_dev.py —— 等价于 fastapi dev 的编程式写法
import uvicorn
if __name__ == "__main__":
uvicorn.run("main:app", host="127.0.0.1", port=8000, reload=True)
# 注意第一个参数是字符串 "main:app" 而不是 app 对象
# 因为热重载需要通过 import string 在子进程里重新导入应用1.4 ASGI 与同步/异步的第一眼
FastAPI 是 ASGI 框架。ASGI(Asynchronous Server Gateway Interface)是 WSGI 的异步继任者:服务器与应用之间以异步消息通信,天然支持 WebSocket 和长连接。
你现在只需要建立一个直觉(第 16 章深入展开):
async def路径函数在事件循环里执行,适合内部用await做异步 IO;- 普通
def路径函数会被丢到线程池里执行,不会阻塞其他请求。
from fastapi import FastAPI
import time
app = FastAPI()
@app.get("/sync-slow")
def sync_slow():
# 普通 def:在线程池中运行,time.sleep 不会卡住事件循环
time.sleep(1)
return {"mode": "sync"}
@app.get("/async-fast")
async def async_fast():
# async def:在事件循环中运行,必须配合异步 IO 才有意义
import asyncio
await asyncio.sleep(1)
return {"mode": "async"}❌ 最常见的坑是在 async def 里写阻塞调用(如 time.sleep、同步 requests.get):这会卡死整个事件循环,让所有并发请求排队。
再补一个多路由的例子,感受一下"只写函数签名,其余交给框架"的风格:
# main.py 追加两个路由
from fastapi import FastAPI
app = FastAPI()
@app.get("/ping")
def ping():
return {"pong": True} # 健康检查:最简单的接口形态
@app.get("/greet/{name}")
def greet(name: str):
# name 从路径中取出并注入函数,无需手动解析 URL
return {"message": f"你好, {name}"}用 fastapi dev 跑起来后访问 /greet/GX,你会看到 {"message":"你好, GX"}——路径参数解析、JSON 序列化、文档生成全部自动完成。
1.5 项目布局建议
本章先建立最简单的单文件结构,后续章节会逐步演进:
myapi/
├── .venv/
├── main.py # 应用入口
└── requirements.txt # pip freeze > requirements.txt 锁定版本两个好习惯现在就养成:
- 应用对象统一命名为
app(工具链默认寻找main:app这样的导入路径); - 用虚拟环境隔离依赖,并把锁定版本写入
requirements.txt,保证"在哪都能跑"。
1.6 本章小结
- FastAPI = Starlette(ASGI 底座)+ Pydantic(校验/序列化)+ 类型驱动的胶水层;
- 安装推荐
pip install "fastapi[standard]",自带 uvicorn 与 fastapi-cli; - 开发用
fastapi dev(热重载),生产用fastapi run/ uvicorn; async def里严禁阻塞调用;普通def由线程池托管;- 返回
dict/list会被自动 JSON 序列化。
🧪 随堂测验
点击你认为正确的选项。答错时会展示正确答案与原因解析。
1. FastAPI 与 Starlette、Pydantic 的关系是?
2. 以下哪条命令适合在日常开发中启动应用并获得热重载?
3. 在一个 async def 路径函数里调用 time.sleep(10) 会发生什么?
4. 为什么 uvicorn.run() 使用热重载时第一个参数要写 "main:app" 字符串?
🛠️ 动手实践
- 把本章最小应用的返回值改成包含你名字和当前时间的字典,用
curl http://127.0.0.1:8000/验证 JSON 输出。 - 实现
/sync-block(普通def+time.sleep(3))、/async-ok(async def+await asyncio.sleep(3)),再故意写一个async def+time.sleep(3)的错误版本,开两个终端同时发请求对比并发行为差异。 - 运行
pip freeze > requirements.txt,新建一个干净虚拟环境并用pip install -r requirements.txt复原环境。
环境跑通后,进入第 2 章认识自动文档。