FastAPI 入门,先搞懂一个请求是怎么跑起来的

学 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 方法,比如 GETPOSTPUTDELETE
  • 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
客户端

当然,后面我们还会讲 HTMLResponseFileResponseresponse_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 到底怎么区分。

参考资料