一、基本介绍

基础定义
业界常用开发模型
/src目录 :存放核心应用代码。其下可细分多个子模块:models子目录:存放数据库模型定义routes子目录:管理FastAPI路由配置services子目录:封装业务逻辑层
/tests目录:将测试代码与主应用隔离,便于测试管理并确保生产构建不包含测试代码/docs目录:集中存放API文档、安装指南及使用说明等关键文档资源
异步兼容
py
# 异步函数应仅用于I/O密集型操作(数据库查询、HTTP请求等)
@app.get("/")
async def read_root():
return {"Hello": "World"}
端点
端点是API交互的接入点。在FastAPI中,通过HTTP方法装饰器(如@app.get("/"))创建端点,表示应用根路径的GET请求处理器:
py
from fastapi import FastAPI
app = FastAPI()
# 当向根URL("/")发起GET请求时,read_root函数被调用并返回JSON响应
@app.get("/")
async def read_root():
return {"Hello": "World"}
路由
当需要管理跨文件的多个端点时,路由 机制尤为重要。路由将端点分组到不同模块,大幅提升代码可维护性与可读性(例如:用户操作路由与产品操作路由分离)。
py
# 创建路由 router_example.py
from fastapi import APIRouter
router = APIRouter()
@router.get("/items/{item_id}")
async def read_item(item_id: int):
return {"item_id": item_id}
py
# 挂载路由 main.py
# 路由模块应遵循单一职责原则,按业务域垂直拆分
import router_example
from fastapi import FastAPI
app = FastAPI()
app.include_router(router_example.router)
@app.get("/")
async def read_root():
return {"Hello": "World"}
bash
uvicorn main:app --reload #--reload参数使服务器在代码变更后自动重启,是开发环境的理想选择
# 生产环境则应使用--workers参数配置多进程
uvicorn main:app --reload --host 192.168.31.158
# 限制运行在特定的IP
http://127.0.0.1:8000
http://127.0.0.1:8000/docs
http://127.0.0.1:8000/redoc
书店系统案例
后端雏形
python
# 书店系统后端雏形
from fastapi import FastAPI
app = FastAPI()
# {book_id}是路径参数 用来动态传递值
@app.get("/books/{book_id}")
# book_id: int 执行了数据验证 防御常见注入攻击
async def read_book(book_id: int ):
return {
"book_id": book_id,
"title": "The Great Gatsby",
"author": "F. Scott Fitzgerald"
}
!NOTE
RESTful API 资源标识规范
- REST 是面向资源的,路径应表示资源,而不是操作。
- 不推荐:
/getBook/{id}、/deleteUser/{userId}- 推荐:
/books/{book_id}、/users/{user_id}路径本身表示资源集合(
/books)或具体资源(/books/123),操作由 HTTP 方法(GET/POST/PUT/DELETE)表达。
- 使用小写、下划线或短横线分隔(推荐短横线
-)推荐:
/books/{book-id}或直接/books/{id}
- 路径参数名应简洁,避免冗余
既然路径已经是
/books/...,那么参数名无需重复 "book":
- 冗余:
/books/{book_id}- 简洁:
/books/{id}这是 RESTful 设计中的通用惯例 。例如 GitHub API 使用:
/repos/{owner}/{repo},而不是/repo/{repo_owner}/{repo_name}。
- 使用复数形式表示资源集合
/books(资源集合)/books/123(具体资源实例)
- 标识符应为不透明的(opaque)且稳定
- 使用数据库主键(如整数
123)或全局唯一 ID(如 UUIDa1b2c3d4)。- 不应暴露内部结构(如
/books/user123_book456)。- 一旦分配,不应改变(避免破坏链接)。
参数处理
python
# 路径参数适用于资源标识(如/users/{user_id})
# 新增路径参数端点 用于检索作者信息
@app.get("/authors/{author_id}")
# 通过Python类型提示(author_id: int)自动执行参数验证与转换
async def read_author(author_id: int):
return {
"author_id": author_id,
"name": "Ernest Hemingway"
}
- 查询参数 用于细化或定制API端点的响应,以问号(?)后追加的形式出现在URL中。例如,
/books?genre=fiction&year=2010可能仅返回2010年出版的虚构类书籍。
为现有端点添加查询参数。假设我们需要允许用户按出版年份过滤书籍:
python
# 查询参数适用于资源过滤(如?status=active`)和分页控制(如?page=2&size=10),以问号(?)后追加的形式出现在URL中
# 例如 /books?genre=fiction&year=2010
# 添加查询参数
@app.get("/books")
# 此时year可选,None明确表示参数可缺失
async def read_books(year: int = None):
if year:
return {
"year": year,
"books": ["Book 1", "Book 2"]
}
return {"books": ["All Books"]}
模型定义
基础模型
python
from pydantic import BaseModel
class Book(BaseModel):
# 每个字段都有类型声明
title: str
author: str
year: int
请求体
python
# 定义请求体
from models import Book
# Pydantic模型也用于请求体的结构定义
# 当用户向 /book 发送包含JSON数据的POST请求时,FastAPI会自动解析并验证数据是否符合Book模型。若数据无效,将返回自动化的错误响应
@app.post("/book")
async def create_book(book: Book):
return book
python
# 高级验证功能
from pydantic import BaseModel, Field
class Book(BaseModel):
# 最小长度1个字符 最大长度100 个字符
title: str = Field(..., min_length=1, max_length=100)
author: str = Field(..., min_length=1, max_length=50)
# 大于1900 小于2100
year: int = Field(..., gt=1900, lt=2100)
响应模型
python
from pydantic import BaseModel
# 定义响应模型
# 响应模型分离设计遵循最小权限原则,避免意外泄露敏感字段
class BookResponse(BaseModel):
title: str
author: str
# /allbooks GET端点需要返回图书列表,但仅包含书名和作者
@app.get("/allbooks")
# list[BookResponse] 表示使用BookResponse模型处理响应 保证响应只有两个属性
async def read_all_books() -> list[BookResponse]:
return [
{
"title": "1984",
"author": "George Orwell"
},
{
"title": "The Great Gatsby",
"author": "F. Scott Fitzgerald"
},
]
python
# 在端点装饰器参数中指定响应类型
# response_model参数具有更高优先级
@app.get("/allbooks", response_model=list[BookResponse])
async def read_all_books():
# 端点实现内容
异常处理
Http错误处理
python
from fastapi import FastAPI, HTTPException
from starlette.responses import JSONResponse
# http_exception_handler函数将处理所有`HTTPException`错误。
@app.exception_handler(HTTPException)
async def http_exception_handler(request, exc):
return JSONResponse(
status_code=exc.status_code,
content={
"message": "Oops! Something went wrong"
},
)
python
# 测试用端点 显式抛出HTTP错误响应
@app.get("/error_endpoint")
async def raise_exception():
raise HTTPException(status_code=400)
验证错误处理
python
import json
from fastapi import Request, status
from fastapi.exceptions import RequestValidationError
from fastapi.responses import PlainTextResponse
# 捕获所有RequestValidationError错误 并返回包含错误详情的纯文本响应
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(
request: Request,
exc: RequestValidationError
):
return PlainTextResponse(
"This is a plain text response:"
f" \n{json.dumps(exc.errors(), indent=2)}",
status_code=status.HTTP_400_BAD_REQUEST,
)