学 FastAPI 最容易卡住的地方,不是语法。
真正容易卡住的是,你明明只写了一个 Python 函数,为什么浏览器一访问 URL,它就能跑起来;为什么函数返回一个字典,浏览器收到的却是 JSON;为什么 /docs 页面还能自动生成接口文档。
如果这个链路没想清楚,后面学 Path、Query、Pydantic、依赖注入、ORM,都会像在背零散知识点。
所以这一篇先不急着堆功能,我们先把 FastAPI 的第一条主线讲清楚。
一个 HTTP 请求,到底是怎么进入 FastAPI,又怎么变成响应返回给客户端的。
本篇准备
如果你想跟着跑代码,先安装 FastAPI 和 Uvicorn:
bash
pip install fastapi uvicorn
本文示例默认你把代码写在 main.py 里,然后用下面的命令启动:
bash
uvicorn main:app --reload
启动成功后,浏览器访问 http://127.0.0.1:8000/ 就能看到接口返回。
1. 最小 FastAPI 应用
一个最小 FastAPI 应用大概长这样:
python
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
运行它:
bash
uvicorn main:app --reload
这里有三个关键点:
| 写法 | 含义 |
|---|---|
main |
Python 文件名,也就是 main.py |
app |
文件里的 FastAPI 应用实例 |
--reload |
开发模式下代码变化自动重启 |
启动后访问:
text
http://127.0.0.1:8000/
你会看到:
json
{
"message": "Hello World"
}
这个例子看着简单,但它已经包含了 FastAPI 最核心的工作方式。
2. FastAPI 做的第一件事,建立 URL 和函数的映射
这行代码:
python
@app.get("/")
不是普通装饰器那么简单。它告诉 FastAPI:
如果客户端用 GET 方法访问 /,就执行下面这个函数。
也就是说,FastAPI 的路由关系由两部分决定:
- HTTP 方法,比如
GET、POST、PUT、DELETE - URL 路径,比如
/、/hello、/news/list
可以把它想成一张路由表:
| 请求方法 | 请求路径 | 处理函数 |
|---|---|---|
GET |
/ |
root() |
GET |
/hello |
get_hello() |
POST |
/register |
register() |
用 Mermaid 画出来就是这样:
Handler FastAPI Router Client Handler FastAPI Router Client #mermaid-svg-My3N3cKdakZNTnhU{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-My3N3cKdakZNTnhU .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-My3N3cKdakZNTnhU .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-My3N3cKdakZNTnhU .error-icon{fill:#552222;}#mermaid-svg-My3N3cKdakZNTnhU .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-My3N3cKdakZNTnhU .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-My3N3cKdakZNTnhU .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-My3N3cKdakZNTnhU .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-My3N3cKdakZNTnhU .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-My3N3cKdakZNTnhU .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-My3N3cKdakZNTnhU .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-My3N3cKdakZNTnhU .marker{fill:#333333;stroke:#333333;}#mermaid-svg-My3N3cKdakZNTnhU .marker.cross{stroke:#333333;}#mermaid-svg-My3N3cKdakZNTnhU svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-My3N3cKdakZNTnhU p{margin:0;}#mermaid-svg-My3N3cKdakZNTnhU .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-My3N3cKdakZNTnhU text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-My3N3cKdakZNTnhU .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-My3N3cKdakZNTnhU .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-My3N3cKdakZNTnhU .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-My3N3cKdakZNTnhU .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-My3N3cKdakZNTnhU #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-My3N3cKdakZNTnhU .sequenceNumber{fill:white;}#mermaid-svg-My3N3cKdakZNTnhU #sequencenumber{fill:#333;}#mermaid-svg-My3N3cKdakZNTnhU #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-My3N3cKdakZNTnhU .messageText{fill:#333;stroke:none;}#mermaid-svg-My3N3cKdakZNTnhU .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-My3N3cKdakZNTnhU .labelText,#mermaid-svg-My3N3cKdakZNTnhU .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-My3N3cKdakZNTnhU .loopText,#mermaid-svg-My3N3cKdakZNTnhU .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-My3N3cKdakZNTnhU .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-My3N3cKdakZNTnhU .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-My3N3cKdakZNTnhU .noteText,#mermaid-svg-My3N3cKdakZNTnhU .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-My3N3cKdakZNTnhU .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-My3N3cKdakZNTnhU .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-My3N3cKdakZNTnhU .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-My3N3cKdakZNTnhU .actorPopupMenu{position:absolute;}#mermaid-svg-My3N3cKdakZNTnhU .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-My3N3cKdakZNTnhU .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-My3N3cKdakZNTnhU .actor-man circle,#mermaid-svg-My3N3cKdakZNTnhU line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-My3N3cKdakZNTnhU :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} GET / 匹配 root() return {"message": "Hello World"} JSON Response
读 FastAPI 代码时,先看装饰器,再看函数名和参数。
装饰器决定这个函数负责哪个接口。
3. 为什么返回 dict 会变成 JSON
在 Flask 或 Django 里,你可能经常需要显式返回响应对象。
但 FastAPI 里,很多时候你只需要返回 Python 对象:
python
@app.get("/user")
async def get_user():
return {
"id": 1,
"name": "Tom"
}
FastAPI 会自动把字典、列表、Pydantic 模型等对象转换成 JSON 响应。
也就是说,你写的是 Python 数据结构,客户端收到的是 HTTP 响应。
这件事对新手很重要,因为它把 API 开发里最常见的工作简化了:
#mermaid-svg-6ldgituYB3FiCjT5{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-6ldgituYB3FiCjT5 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-6ldgituYB3FiCjT5 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-6ldgituYB3FiCjT5 .error-icon{fill:#552222;}#mermaid-svg-6ldgituYB3FiCjT5 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-6ldgituYB3FiCjT5 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-6ldgituYB3FiCjT5 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-6ldgituYB3FiCjT5 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-6ldgituYB3FiCjT5 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-6ldgituYB3FiCjT5 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-6ldgituYB3FiCjT5 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-6ldgituYB3FiCjT5 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-6ldgituYB3FiCjT5 .marker.cross{stroke:#333333;}#mermaid-svg-6ldgituYB3FiCjT5 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-6ldgituYB3FiCjT5 p{margin:0;}#mermaid-svg-6ldgituYB3FiCjT5 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-6ldgituYB3FiCjT5 .cluster-label text{fill:#333;}#mermaid-svg-6ldgituYB3FiCjT5 .cluster-label span{color:#333;}#mermaid-svg-6ldgituYB3FiCjT5 .cluster-label span p{background-color:transparent;}#mermaid-svg-6ldgituYB3FiCjT5 .label text,#mermaid-svg-6ldgituYB3FiCjT5 span{fill:#333;color:#333;}#mermaid-svg-6ldgituYB3FiCjT5 .node rect,#mermaid-svg-6ldgituYB3FiCjT5 .node circle,#mermaid-svg-6ldgituYB3FiCjT5 .node ellipse,#mermaid-svg-6ldgituYB3FiCjT5 .node polygon,#mermaid-svg-6ldgituYB3FiCjT5 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-6ldgituYB3FiCjT5 .rough-node .label text,#mermaid-svg-6ldgituYB3FiCjT5 .node .label text,#mermaid-svg-6ldgituYB3FiCjT5 .image-shape .label,#mermaid-svg-6ldgituYB3FiCjT5 .icon-shape .label{text-anchor:middle;}#mermaid-svg-6ldgituYB3FiCjT5 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-6ldgituYB3FiCjT5 .rough-node .label,#mermaid-svg-6ldgituYB3FiCjT5 .node .label,#mermaid-svg-6ldgituYB3FiCjT5 .image-shape .label,#mermaid-svg-6ldgituYB3FiCjT5 .icon-shape .label{text-align:center;}#mermaid-svg-6ldgituYB3FiCjT5 .node.clickable{cursor:pointer;}#mermaid-svg-6ldgituYB3FiCjT5 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-6ldgituYB3FiCjT5 .arrowheadPath{fill:#333333;}#mermaid-svg-6ldgituYB3FiCjT5 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-6ldgituYB3FiCjT5 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-6ldgituYB3FiCjT5 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6ldgituYB3FiCjT5 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-6ldgituYB3FiCjT5 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6ldgituYB3FiCjT5 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-6ldgituYB3FiCjT5 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-6ldgituYB3FiCjT5 .cluster text{fill:#333;}#mermaid-svg-6ldgituYB3FiCjT5 .cluster span{color:#333;}#mermaid-svg-6ldgituYB3FiCjT5 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-6ldgituYB3FiCjT5 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-6ldgituYB3FiCjT5 rect.text{fill:none;stroke-width:0;}#mermaid-svg-6ldgituYB3FiCjT5 .icon-shape,#mermaid-svg-6ldgituYB3FiCjT5 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6ldgituYB3FiCjT5 .icon-shape p,#mermaid-svg-6ldgituYB3FiCjT5 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-6ldgituYB3FiCjT5 .icon-shape .label rect,#mermaid-svg-6ldgituYB3FiCjT5 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6ldgituYB3FiCjT5 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-6ldgituYB3FiCjT5 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-6ldgituYB3FiCjT5 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Python dict/list/model
FastAPI 序列化
JSON Response
客户端
当然,后面我们还会讲 HTMLResponse、FileResponse、response_model,那是响应系统的进阶部分。
这一篇先记住一件事:
普通 API 接口里,返回 dict/list/model,FastAPI 默认会帮你转成 JSON。
4. /docs 为什么能自动生成
FastAPI 很大的一个优势,是自动生成交互式 API 文档。
启动服务后访问:
text
http://127.0.0.1:8000/docs
会看到 Swagger UI。
访问:
text
http://127.0.0.1:8000/redoc
会看到 ReDoc。
这个能力不是魔法,来源主要有三块:
- 路由装饰器,比如
@app.get("/book/{id}") - Python 类型注解,比如
id: int - Pydantic 模型,比如请求体和响应模型
FastAPI 会根据这些信息生成 OpenAPI schema,再由 Swagger UI 或 ReDoc 渲染成页面。
所以你写类型注解,不只是给 Python 或编辑器看的,也是给 API 文档和参数校验看的。
5. 同步函数和异步函数
FastAPI 同时支持普通函数和异步函数:
python
@app.get("/sync")
def sync_api():
return {"mode": "sync"}
@app.get("/async")
async def async_api():
return {"mode": "async"}
很多人一开始会把 async 理解成更快。
这个理解不准确。
更准确的说法是,async 适合处理 I/O 等待。
比如数据库查询、网络请求、Redis 读取,这些操作经常不是 CPU 在算,而是在等外部系统返回。异步函数可以在等待期间把执行权让出来,让服务继续处理别的请求。
Request B Database FastAPI Request A Request B Database FastAPI Request A #mermaid-svg-cn8lBjyd5HocE4uu{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-cn8lBjyd5HocE4uu .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-cn8lBjyd5HocE4uu .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-cn8lBjyd5HocE4uu .error-icon{fill:#552222;}#mermaid-svg-cn8lBjyd5HocE4uu .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-cn8lBjyd5HocE4uu .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-cn8lBjyd5HocE4uu .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-cn8lBjyd5HocE4uu .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-cn8lBjyd5HocE4uu .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-cn8lBjyd5HocE4uu .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-cn8lBjyd5HocE4uu .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-cn8lBjyd5HocE4uu .marker{fill:#333333;stroke:#333333;}#mermaid-svg-cn8lBjyd5HocE4uu .marker.cross{stroke:#333333;}#mermaid-svg-cn8lBjyd5HocE4uu svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-cn8lBjyd5HocE4uu p{margin:0;}#mermaid-svg-cn8lBjyd5HocE4uu .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-cn8lBjyd5HocE4uu text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-cn8lBjyd5HocE4uu .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-cn8lBjyd5HocE4uu .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-cn8lBjyd5HocE4uu .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-cn8lBjyd5HocE4uu .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-cn8lBjyd5HocE4uu #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-cn8lBjyd5HocE4uu .sequenceNumber{fill:white;}#mermaid-svg-cn8lBjyd5HocE4uu #sequencenumber{fill:#333;}#mermaid-svg-cn8lBjyd5HocE4uu #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-cn8lBjyd5HocE4uu .messageText{fill:#333;stroke:none;}#mermaid-svg-cn8lBjyd5HocE4uu .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-cn8lBjyd5HocE4uu .labelText,#mermaid-svg-cn8lBjyd5HocE4uu .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-cn8lBjyd5HocE4uu .loopText,#mermaid-svg-cn8lBjyd5HocE4uu .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-cn8lBjyd5HocE4uu .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-cn8lBjyd5HocE4uu .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-cn8lBjyd5HocE4uu .noteText,#mermaid-svg-cn8lBjyd5HocE4uu .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-cn8lBjyd5HocE4uu .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-cn8lBjyd5HocE4uu .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-cn8lBjyd5HocE4uu .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-cn8lBjyd5HocE4uu .actorPopupMenu{position:absolute;}#mermaid-svg-cn8lBjyd5HocE4uu .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-cn8lBjyd5HocE4uu .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-cn8lBjyd5HocE4uu .actor-man circle,#mermaid-svg-cn8lBjyd5HocE4uu line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-cn8lBjyd5HocE4uu :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 等 DB 时不必卡住整个事件循环 请求 A await 查询数据库 请求 B 可以继续被处理 查询结果 返回响应 A
但如果你在 async def 里写阻塞代码,比如:
python
import time
@app.get("/bad")
async def bad_api():
time.sleep(3)
return {"ok": True}
这就会卡住事件循环。
正确的方向是,要么使用真正的异步库,要么把阻塞任务放到合适的位置处理。
课程里后面使用 SQLAlchemy Async、aiomysql、redis.asyncio,原因就在这里。
6. 从请求到响应的完整链路
把前面的内容合起来,一次请求大概会经历这些步骤:
#mermaid-svg-p7kLNX2OGeCt2IMP{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-p7kLNX2OGeCt2IMP .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-p7kLNX2OGeCt2IMP .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-p7kLNX2OGeCt2IMP .error-icon{fill:#552222;}#mermaid-svg-p7kLNX2OGeCt2IMP .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-p7kLNX2OGeCt2IMP .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-p7kLNX2OGeCt2IMP .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-p7kLNX2OGeCt2IMP .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-p7kLNX2OGeCt2IMP .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-p7kLNX2OGeCt2IMP .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-p7kLNX2OGeCt2IMP .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-p7kLNX2OGeCt2IMP .marker{fill:#333333;stroke:#333333;}#mermaid-svg-p7kLNX2OGeCt2IMP .marker.cross{stroke:#333333;}#mermaid-svg-p7kLNX2OGeCt2IMP svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-p7kLNX2OGeCt2IMP p{margin:0;}#mermaid-svg-p7kLNX2OGeCt2IMP .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-p7kLNX2OGeCt2IMP .cluster-label text{fill:#333;}#mermaid-svg-p7kLNX2OGeCt2IMP .cluster-label span{color:#333;}#mermaid-svg-p7kLNX2OGeCt2IMP .cluster-label span p{background-color:transparent;}#mermaid-svg-p7kLNX2OGeCt2IMP .label text,#mermaid-svg-p7kLNX2OGeCt2IMP span{fill:#333;color:#333;}#mermaid-svg-p7kLNX2OGeCt2IMP .node rect,#mermaid-svg-p7kLNX2OGeCt2IMP .node circle,#mermaid-svg-p7kLNX2OGeCt2IMP .node ellipse,#mermaid-svg-p7kLNX2OGeCt2IMP .node polygon,#mermaid-svg-p7kLNX2OGeCt2IMP .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-p7kLNX2OGeCt2IMP .rough-node .label text,#mermaid-svg-p7kLNX2OGeCt2IMP .node .label text,#mermaid-svg-p7kLNX2OGeCt2IMP .image-shape .label,#mermaid-svg-p7kLNX2OGeCt2IMP .icon-shape .label{text-anchor:middle;}#mermaid-svg-p7kLNX2OGeCt2IMP .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-p7kLNX2OGeCt2IMP .rough-node .label,#mermaid-svg-p7kLNX2OGeCt2IMP .node .label,#mermaid-svg-p7kLNX2OGeCt2IMP .image-shape .label,#mermaid-svg-p7kLNX2OGeCt2IMP .icon-shape .label{text-align:center;}#mermaid-svg-p7kLNX2OGeCt2IMP .node.clickable{cursor:pointer;}#mermaid-svg-p7kLNX2OGeCt2IMP .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-p7kLNX2OGeCt2IMP .arrowheadPath{fill:#333333;}#mermaid-svg-p7kLNX2OGeCt2IMP .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-p7kLNX2OGeCt2IMP .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-p7kLNX2OGeCt2IMP .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-p7kLNX2OGeCt2IMP .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-p7kLNX2OGeCt2IMP .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-p7kLNX2OGeCt2IMP .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-p7kLNX2OGeCt2IMP .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-p7kLNX2OGeCt2IMP .cluster text{fill:#333;}#mermaid-svg-p7kLNX2OGeCt2IMP .cluster span{color:#333;}#mermaid-svg-p7kLNX2OGeCt2IMP div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-p7kLNX2OGeCt2IMP .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-p7kLNX2OGeCt2IMP rect.text{fill:none;stroke-width:0;}#mermaid-svg-p7kLNX2OGeCt2IMP .icon-shape,#mermaid-svg-p7kLNX2OGeCt2IMP .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-p7kLNX2OGeCt2IMP .icon-shape p,#mermaid-svg-p7kLNX2OGeCt2IMP .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-p7kLNX2OGeCt2IMP .icon-shape .label rect,#mermaid-svg-p7kLNX2OGeCt2IMP .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-p7kLNX2OGeCt2IMP .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-p7kLNX2OGeCt2IMP .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-p7kLNX2OGeCt2IMP :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 客户端发起 HTTP 请求
Uvicorn 接收请求
FastAPI 匹配路由
解析参数和类型校验
执行路径操作函数
返回 Python 对象
序列化为 HTTP 响应
客户端收到结果
这里先认识几个名字:
| 名称 | 作用 |
|---|---|
| Uvicorn | ASGI 服务器,负责运行 FastAPI 应用 |
| FastAPI app | 应用对象,管理路由、中间件、异常处理 |
| Router | 路由匹配,把 URL 分发给函数 |
| Handler | 具体路径操作函数,也就是你写的业务函数 |
| Response | 最终返回给客户端的 HTTP 响应 |
后面所有知识点,几乎都能塞进这条链路里。
Path、Query、Body 属于参数解析。
Pydantic 属于数据校验和序列化。
Middleware 属于请求进入和响应返回时的外层处理。
Depends 属于执行函数前准备资源。
ORM 属于函数内部访问数据库。
7. 小结
FastAPI 入门不要先背 API。
先记住这条线:
text
客户端请求 -> Uvicorn -> FastAPI 路由 -> 参数解析 -> 函数执行 -> JSON 响应
只要这条线清楚,后面的知识点就不散。
你看到 @app.get(),就知道这是在登记路由。
你看到 id: int,就知道 FastAPI 会做类型转换和校验。
你看到 return {"ok": True},就知道它会被转成 JSON 响应。
这就是 FastAPI 最核心的入门心智模型。
下一篇,我们顺着参数解析继续往下讲,Path、Query、Body 到底怎么区分。