青戈AI小栈
会员限时8折
FastAPI 开发基础

跑起第一个接口:安装、运行与自动文档

4,615 字约 12 分钟读完138 次阅读更新于 2026/10/21

登录后收藏

阅读设置

字号
行距
代码

前面的 Python、网络与 HTTP、项目工程教程已经完成了任务客户端:发请求、收响应、跑测试。本篇开始写服务端:接收请求,返回响应,把网络与 HTTP 篇的 task_server.py 改写为 FastAPI 应用。

本节结束时,你能启动一个 FastAPI 服务,用三种方式调通它的第一个接口。

本篇新建 task-api/ 目录,沿用项目工程篇的独立虚拟环境。需要已安装 Python 3.12+;Windows 示例使用 PowerShell 7.3+,命令中的 py 在 macOS / Linux 上换成 python3。

装三件套

powershell
mkdir task-api
cd task-api
py -m venv .venv
.\.venv\Scripts\Activate.ps1

fastapi 用来写接口,uvicorn 用来运行服务,httpx2 用于后续接口测试。在 task-api/ 目录新建 requirements.txt,写入这三个直接依赖:

文件
fastapi==0.143.0
uvicorn==0.54.0
httpx2==2.13.1

保存后,在 task-api/ 目录的终端执行:

powershell
.\.venv\Scripts\python.exe -m pip install -r requirements.txt

先写版本清单,再按清单安装,才能让实际安装的直接依赖与正文一致。pydantic、starlette 等传递依赖会自动安装,不必手工逐个安装。

macOS / Linux 的虚拟环境激活命令是 source .venv/bin/activate,安装命令是 .venv/bin/python -m pip install -r requirements.txt。后续 Windows 命令中的 curl.exe 换成 curl。

官方文档也提供 pip install "fastapi[standard]",会安装一组可选工具。本篇只安装当前示例需要的依赖。

本篇固定使用清单中的版本,不混用其他版本教程的依赖。httpx2 到接口测试一节再使用。

第一个接口

在 task-api/ 目录中新建 app/ 文件夹,再在其中新建空文件 __init__.py,使它成为 Python 包。接着新建 app/main.py,手写下面的核心代码:

python
from fastapi import FastAPI

app = FastAPI()


@app.get("/ping")  # 注册路由:收到 GET /ping 时调用下面的函数。
def ping():
    """不接收业务参数,返回用于确认服务启动的 JSON 数据。"""
    return {"ping": "pong"}

三行各做一件事:FastAPI() 造一个应用对象;@app.get("/ping") 声明"GET 请求打到 /ping 就调下面这个函数";函数返回一个字典,FastAPI 自动转成 JSON。

@app.get(...) 这种写在函数头上的叫装饰器——第一篇第 23 节见过,作用一样:给函数贴一张说明,框架读到说明就知道该做什么。

跑起来

虚拟环境已激活的前提下,直接敲 uvicorn(它装在 .venv\Scripts\ 里):

powershell
uvicorn app.main:app --reload --port 8000

app.main:app 是"包.文件:对象"——app 包里 main.py 的 app。--port 8000 指定端口(这里先用默认的 8000;下一节搬任务接口时统一换到 9000,和旧 CLI 的默认地址一致)。--reload 让改代码即时生效,不用手动重启——开发时一直带着它(本篇的命令默认都带)。

启动成功的输出:

输出
INFO:     Will watch for changes in these directories: ['D:\Code\...\task-api']
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [51500] using StatReload
INFO:     Started server process [56864]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

前两行是监视器(--reload 带来的):盯着目录里的文件,一改就自动重载。方括号里的进程号、监视的目录路径每个人不一样。看到最后一行,服务就在 8000 端口等着了。这个窗口现在是服务视角,不要关。

三边确认它在工作

浏览器地址栏输入 http://127.0.0.1:8000/ping,页面显示:

输出
{"ping":"pong"}

另开一个终端,用 curl 看同样的东西:

powershell
curl.exe -s http://127.0.0.1:8000/ping
输出
{"ping":"pong"}

回到服务窗口,多了一行请求日志:

输出
INFO:     127.0.0.1:2112 - "GET /ping HTTP/1.1" 200 OK

冒号后的数字是浏览器那边的临时端口,每次不一样。从左到右:谁来的、发了什么(方法 + 路径 + 协议)、回了什么(200 OK)。第二篇读 http.server 日志的本事,这里照样用得上。

没定义的路径

访问一个没写过的地址:

powershell
curl.exe -s http://127.0.0.1:8000/nope
输出
{"detail":"Not Found"}

这个 404 响应使用 detail 键。后面会遇到的参数校验错误也使用该键,但值是错误列表,不是字符串;未处理的服务器异常则可能返回纯文本,不能一概按这个形状解析。

自动文档

浏览器打开 http://127.0.0.1:8000/docs,能看到一个接口列表页:/ping 已经列在上面,点开展开,点击 Try it out → Execute,不用写任何客户端代码就能调一次,返回 200 和 {"ping": "pong"}。

这是 FastAPI 附赠的:代码即文档。以后每加一个接口,这个页面自动多一行;第 9 节回头看它时,会发现它连数据模型都列得清清楚楚。

停服务按 Ctrl + C(在跑服务的那个窗口按)。

完整示例

  1. 新建 task-api/ 目录和虚拟环境,创建上面的 requirements.txt,执行 pip install -r requirements.txt。
  2. 建 app/ 包(空 __init__.py),写 app/main.py(上面三段式代码)。
  3. uvicorn app.main:app --reload --port 8000 启动。
  4. 浏览器打开 http://127.0.0.1:8000/ping,确认看到 {"ping":"pong"}。
  5. 另开终端 curl.exe -s http://127.0.0.1:8000/ping,确认输出一致。
  6. 浏览器打开 http://127.0.0.1:8000/docs,展开 /ping,Try it out → Execute,确认返回 200。
  7. 服务窗口 Ctrl + C 停止。

预期结果

启动输出六行(进程号、监视目录每个人不一样):

输出
INFO:     Will watch for changes in these directories: ['D:\Code\...\task-api']
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [51500] using StatReload
INFO:     Started server process [56864]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

一次访问后多一行(客户端端口每次不同):

输出
INFO:     127.0.0.1:2112 - "GET /ping HTTP/1.1" 200 OK

常见错误

浏览器打开根路径 http://127.0.0.1:8000/ 显示 {"detail":"Not Found"}:只定义了 /ping,根路径没人管。框架对"没定义的路径"统一回这个形状,不是服务没起来。

第二个终端启动报 ERROR: [Errno 10048] error while attempting to bind on address ('127.0.0.1', 8000):端口被占了——多半是之前那个服务窗口还在跑。后半句中文大意是"每个地址只允许用一次"。关掉旧窗口(Ctrl + C),或换个端口(访问地址里也要跟着改)。

**'uvicorn' 不是内部或外部命令**:这个终端没激活虚拟环境,找不到 .venv\Scripts` 里的 uvicorn。看提示符前有没有 (.venv),没有就先执行 .\.venv\Scripts\Activate.ps1。

改了 app/main.py,刷新没变化:启动命令漏了 --reload。开发时一直带着它;不带就要手动停掉重跑。

小结

  • 三个包一次装齐:fastapi 写接口、uvicorn 跑服务、httpx2 留到测接口时用;requirements.txt 只写直接依赖。
  • app.main:app 是"包.文件:对象";@app.get("/ping") 把函数挂到路径上;返回字典自动转 JSON。
  • 跑服务用 uvicorn app.main:app --reload --port 8000,三边确认:浏览器、curl、服务日志。
  • 没定义的路径统一回 {"detail": "Not Found"};/docs 是自动生成的接口文档。
  • 下一节搬真正的任务接口,端口统一换到 9000。

练习

  1. 操作:给 app/main.py 加一个 /hello 接口,返回 {"hello": "fastapi"},用 curl 调通,并在 /docs 里看到两个路径。

  2. 排查:新开一个终端启动服务,报 Errno 10048。判断问题出在哪,下一步敲什么?

  3. 先预测、再验证:先写下访问 http://127.0.0.1:8000/ 会看到什么,再用浏览器验证。说出原因。

验收:第 1 题两个 curl 输出分别是 {"ping":"pong"} 与 {"hello":"fastapi"},/docs 里有两个路径;第 2 题能说出「旧的服务没关,端口被占」,解法是旧窗口 Ctrl + C 或换端口;第 3 题预测与实际一致({"detail":"Not Found"}),原因是「只定义了 /ping(与 /hello),根路径没人管」。

查看提示

第 1 题:照抄 /ping 的三行结构,只换路径、函数名和返回内容;改完不用重启(--reload 开着)。第 2 题:10048 的后半句中文说得很直白——想想"只允许用一次"指的是什么。第 3 题:先想想服务里一共定义了哪几个路径。

查看参考答案

第 1 题:app/main.py 追加:

python
@app.get("/hello")
def hello():
    """不接收业务参数,返回问候数据。"""
    return {"hello": "fastapi"}
powershell
curl.exe -s http://127.0.0.1:8000/hello
输出
{"hello":"fastapi"}

刷新 /docs,路径列表里出现 /ping 与 /hello 两条。--reload 开着,改完保存即生效,不用重启;如果没生效,回头检查启动命令里有没有 --reload。

第 2 题:旧的服务进程还在 8000 端口上,新起的绑不上去。回到旧的服务窗口按 Ctrl + C 停掉,再启动;旧窗口找不到了,就换个端口(--port 8001,访问地址同步改成 :8001)。

第 3 题:看到 {"detail":"Not Found"}。服务里只定义了 /ping(加上第 1 题的 /hello),根路径 / 从没定义过——框架对没定义的路径统一回这个形状,和服务是否正常无关。

有帮助
登录后提问 / 纠错

提问与反馈

仅你和管理员可见。我的反馈

设置你的昵称

在英雄榜和讨论中,使用你自己的名字。

2–12 个字符0 / 12