FastAPI 学习总结 – 第一部分:基础入门
一、FastAPI 简介
什么是 FastAPI?
FastAPI 是一个用于快速构建 API 的现代、快速(高性能)的 Python Web 框架,基于标准 Python 类型提示。它是由 Sebastián Ramírez 创建的,首次发布于 2019 年。
核心依赖
FastAPI 建立在两个强大的库之上:
主要特点
| 快速 | 性能极高,可与 Node.js 和 Go 媲美,基于 Starlette |
| 自动文档 | 自动生成交互式 API 文档(Swagger UI 和 ReDoc) |
| 类型提示 | 基于 Python 类型提示进行数据验证 |
| 异步支持 | 原生支持异步操作 |
| 依赖注入 | 内置依赖注入系统 |
| 安全性 | 内置 OAuth2、JWT 等安全功能 |
为什么选择 FastAPI?
- 开发效率高: 自动数据验证、自动文档生成
- 性能优秀: 异步支持,处理大量并发请求
- 易于学习: 基于 Python 类型提示,语法简洁
- 生态完善: 支持 SQLAlchemy、Pydantic、OAuth2 等
二、HTTP 协议基础
请求结构
一个 HTTP 请求由三部分组成:
POST /api/v1/users HTTP/1.1
Host: example.com
Content-Type: application/json
Authorization: Bearer token123
{"username": "john", "password": "123456"}
-
请求首行: POST /api/v1/users HTTP/1.1
- 请求方法:POST
- 请求路径:/api/v1/users
- 协议版本:HTTP/1.1
-
请求头: 附加信息
- Host: 目标主机
- Content-Type: 请求体格式
- Authorization: 认证信息
-
请求体: 传输的数据(主要用于 POST、PUT 请求)
请求方法
HTTP 定义了多种请求方法,每种方法对应不同的操作:
| GET | 获取资源 | 获取用户列表 |
| POST | 创建资源 | 新建用户 |
| PUT | 更新资源 | 更新用户信息 |
| DELETE | 删除资源 | 删除用户 |
| PATCH | 部分更新 | 更新用户密码 |
状态码
HTTP 状态码用于表示请求的结果:
| 200 | 成功 | 请求成功 |
| 201 | 成功 | 创建成功 |
| 400 | 客户端错误 | 请求参数错误 |
| 401 | 客户端错误 | 未认证 |
| 403 | 客户端错误 | 无权限 |
| 404 | 客户端错误 | 资源不存在 |
| 500 | 服务器错误 | 服务器内部错误 |
RESTful 规范
REST(Representational State Transfer)是一种软件架构风格:
核心原则:
示例:
| 获取所有用户 | /users | GET |
| 获取单个用户 | /users/{id} | GET |
| 创建用户 | /users | POST |
| 更新用户 | /users/{id} | PUT |
| 删除用户 | /users/{id} | DELETE |
三、FastAPI 基础
安装
首先安装 FastAPI 和 ASGI 服务器:
# 安装 FastAPI 及所有可选依赖
pip install "fastapi[standard]"
# 安装 ASGI 服务器(Uvicorn)
pip install uvicorn
基本结构
创建一个简单的 FastAPI 应用:
# main.py
from fastapi import FastAPI
import uvicorn
# 创建 FastAPI 实例
app = FastAPI(
title="我的第一个 FastAPI 应用",
description="这是一个简单的示例应用",
version="1.0.0"
)
# 定义路由
@app.get("/")
def read_root():
"""根路径,返回欢迎信息"""
return {"message": "Hello, FastAPI!"}
# 带参数的路由
@app.get("/hello/{name}")
def say_hello(name: str):
"""根据名字返回问候"""
return {"message": f"Hello, {name}!"}
# 运行服务器
if __name__ == "__main__":
uvicorn.run(
"main:app", # 模块名:应用实例
host="localhost", # 主机地址
port=8000, # 端口号
reload=True # 开发模式自动重载
)
运行应用
python main.py
访问以下地址:
- API 文档:http://localhost:8000/docs(Swagger UI)
- ReDoc 文档:http://localhost:8000/redoc
自动文档
FastAPI 会根据你的代码自动生成交互式文档:
Swagger UI: http://localhost:8000/docs
- 可以直接在浏览器中测试 API
- 显示请求参数、响应格式
- 支持身份认证
ReDoc: http://localhost:8000/redoc
- 更简洁的文档风格
- 适合作为最终文档展示
四、路由管理
路由装饰器
FastAPI 使用装饰器定义路由:
@app.get("/items") # GET 请求
@app.post("/items") # POST 请求
@app.put("/items/{id}") # PUT 请求
@app.delete("/items/{id}")# DELETE 请求
@app.patch("/items/{id}") # PATCH 请求
路由分发(APIRouter)
当应用变得复杂时,可以使用 APIRouter 组织路由:
步骤 1:创建路由文件
# app/api/users.py
from fastapi import APIRouter
# 创建路由实例
router = APIRouter(
prefix="/users", # 路径前缀
tags=["用户管理"], # 文档标签
responses={404: {"description": "用户不存在"}}
)
# 定义路由
@router.get("/")
def get_users():
"""获取所有用户"""
return [{"id": 1, "name": "张三"}, {"id": 2, "name": "李四"}]
@router.get("/{user_id}")
def get_user(user_id: int):
"""根据ID获取用户"""
return {"id": user_id, "name": "张三"}
@router.post("/")
def create_user(name: str):
"""创建用户"""
return {"id": 3, "name": name}
步骤 2:在主应用中注册
# main.py
from fastapi import FastAPI
from app.api.users import router as users_router
app = FastAPI()
# 注册路由
app.include_router(users_router)
路由参数说明
@router.get(
"/{user_id}",
summary="获取用户详情", # 简短描述
description="根据用户ID获取用户详细信息", # 详细描述
tags=["用户管理"], # 标签
deprecated=False # 是否废弃
)
def get_user(user_id: int):
return {"id": user_id}
五、参数类型
路径参数
路径参数是 URL 路径的一部分:
@app.get("/items/{item_id}")
def read_item(item_id: int):
"""
获取商品详情
:param item_id: 商品ID(整数)
:return: 商品信息
"""
return {"item_id": item_id}
类型转换: FastAPI 会自动将路径参数转换为声明的类型。
访问示例:
- GET /items/5 → {"item_id": 5}
- GET /items/abc → 422 错误(类型不匹配)
查询参数
查询参数是 URL 中 ? 后面的部分:
@app.get("/items")
def read_items(skip: int = 0, limit: int = 10):
"""
获取商品列表(分页)
:param skip: 跳过的数量(默认0)
:param limit: 返回的数量(默认10)
:return: 商品列表
"""
# 模拟数据
items = [{"id": i, "name": f"Item {i}"} for i in range(100)]
return items[skip : skip + limit]
访问示例:
- GET /items → 返回前10个商品
- GET /items?skip=10&limit=5 → 返回第11-15个商品
请求体参数
使用 Pydantic 模型定义请求体:
from pydantic import BaseModel
class User(BaseModel):
"""用户模型"""
username: str
email: str
password: str
age: int = 18 # 默认值
@app.post("/users")
def create_user(user: User):
"""
创建用户
:param user: 用户信息
:return: 创建的用户(隐藏密码)
"""
return {
"username": user.username,
"email": user.email,
"age": user.age
}
请求示例:
curl -X POST "http://localhost:8000/users" \\
-H "Content-Type: application/json" \\
-d '{"username": "john", "email": "john@example.com", "password": "123456"}'
响应示例:
{"username": "john", "email": "john@example.com", "age": 18}
表单参数
使用 Form 接收表单数据:
from fastapi import Form
@app.post("/login")
def login(username: str = Form(...), password: str = Form(...)):
"""
用户登录
:param username: 用户名
:param password: 密码
:return: 登录状态
"""
if username == "admin" and password == "123456":
return {"message": "登录成功"}
return {"message": "登录失败"}
注意: 需要安装 python-multipart:
pip install python-multipart
请求示例:
curl -X POST "http://localhost:8000/login" \\
-H "Content-Type: application/x-www-form-urlencoded" \\
-d "username=admin&password=123456"
文件上传
使用 File 和 UploadFile 处理文件上传:
from fastapi import File, UploadFile
@app.post("/upload")
def upload_file(file: UploadFile = File(...)):
"""
上传文件
:param file: 上传的文件
:return: 文件信息
"""
return {
"filename": file.filename,
"content_type": file.content_type,
"size": len(file.file.read())
}
多文件上传:
@app.post("/upload-multiple")
def upload_files(files: list[UploadFile] = File(...)):
"""
上传多个文件
:param files: 文件列表
:return: 所有文件信息
"""
return [
{"filename": file.filename, "content_type": file.content_type}
for file in files
]
请求示例:
curl -X POST "http://localhost:8000/upload" \\
-H "Content-Type: multipart/form-data" \\
-F "file=@test.txt"
混合参数
可以在一个接口中使用多种参数类型:
from fastapi import Path, Query
@app.put("/users/{user_id}")
def update_user(
user_id: int = Path(..., gt=0), # 路径参数
name: str = Query(None), # 查询参数
user: User = None # 请求体参数
):
"""
更新用户信息
:param user_id: 用户ID(必须大于0)
:param name: 用户名(可选)
:param user: 用户对象(可选)
:return: 更新后的用户
"""
result = {"id": user_id}
if name:
result["name"] = name
if user:
result.update(user.dict())
return result




