第 4 章:FastAPI 框架详解 FastAPI 是 Python 生态中最现代的 Web 框架,以高性能、自动文档和类型安全著称。特别适合 AI/ML 模型服务。
4.1 FastAPI 是什么? FastAPI 是一个 基于 Python 类型提示的现代化 Web 框架 ,由 Sebastián Ramírez 于 2018 年创建。
核心依赖 ┌─────────────────────────────────────────┐
│ FastAPI │
│ │
│ ┌─────────────┐ ┌──────────────────┐ │
│ │ Starlette │ │ Pydantic │ │
│ │ (Web 层) │ │ (数据验证层) │ │
│ │ 异步路由 │ │ 类型验证 │ │
│ │ WebSocket │ │ 序列化 │ │
│ └─────────────┘ └──────────────────┘ │
│ │
│ ┌──────────────────────────────────┐ │
│ │ OpenAPI (Swagger) 自动生成 │ │
│ └──────────────────────────────────┘ │
└─────────────────────────────────────────┘
Starlette :高性能异步 Web 框架(路由、中间件、WebSocket) Pydantic :基于 Python 类型提示的数据验证库 Uvicorn :ASGI 服务器,运行 FastAPI 应用 为什么选择 FastAPI? 特性 Express FastAPI 语言 JavaScript Python 类型安全 需 TypeScript 原生类型提示 自动文档 需 swagger-ui-express 内置 /docs 异步 Callback/Promise 原生 async/await 数据验证 需 express-validator 内置 Pydantic AI/ML 生态 ❌ ✅(无缝对接)
4.2 快速开始 安装 pip install fastapi uvicorn
第一个应用 from fastapi import FastAPI
app = FastAPI (
title = "我的 API" ,
description = "这是一个示例 API" ,
version = "1.0.0"
)
@app . get ( "/" )
async def root ():
return { "message" : "Hello World" }
@app . get ( "/users/ {user_id} " )
def get_user ( user_id : int , name : str = "Anonymous" ):
return { "user_id" : user_id , "name" : name }
运行 uvicorn main:app --reload
# main:app → 文件名:应用实例名
# --reload → 开发模式,代码修改自动重启
访问 http://localhost:8000/docs 可以看到自动生成的 Swagger UI!
4.3 路径参数与查询参数 路径参数 from fastapi import FastAPI , Path
from typing import Annotated
app = FastAPI ()
# 基本路径参数
@app . get ( "/users/ {user_id} " )
def get_user ( user_id : int ):
# user_id 自动转换为 int,如果不是整数会返回 422
return { "user_id" : user_id , "type" : type ( user_id ) . __name__ }
# 带验证的路径参数
@app . get ( "/items/ {item_id} " )
def get_item (
item_id : Annotated [ int , Path ( title = "物品 ID" , ge = 1 , le = 1000 )]
):
return { "item_id" : item_id }
# 多个路径参数
@app . get ( "/users/ {user_id} /posts/ {post_id} " )
def get_user_post ( user_id : int , post_id : int ):
return { "user_id" : user_id , "post_id" : post_id }
查询参数 # 查询参数自动识别(不是路径参数的都是查询参数)
@app . get ( "/items" )
def list_items (
skip : int = 0 , # 默认值
limit : int = 100 ,
q : str | None = None # 可选参数
):
results = [{ "id" : i } for i in range ( skip , skip + limit )]
if q :
results = [ r for r in results if q in str ( r )]
return { "items" : results , "query" : q }
# 访问:GET /items?skip=0&limit=10&q=test
必需的查询参数 # 没有默认值的参数 = 必需参数
@app . get ( "/search" )
def search ( q : str , page : int = 1 ):
# q 是必需的,page 是可选的(有默认值)
return { "q" : q , "page" : page }
# 访问:GET /search?q=python ✅
# 访问:GET /search ❌ 422 Unprocessable Entity
4.4 请求体与 Pydantic 模型 基本请求体 from pydantic import BaseModel , EmailStr , Field
from typing import Optional
class UserCreate ( BaseModel ):
name : str
email : str
age : int
bio : Optional [ str ] = None # 可选字段
@app . post ( "/users" )
def create_user ( user : UserCreate ):
# FastAPI 自动:
# 1. 解析 JSON 请求体
# 2. 验证类型(name 必须是字符串,age 必须是整数)
# 3. 返回 Pydantic 模型实例
return { "message" : "用户创建成功" , "user" : user . model_dump ()}
Pydantic 验证示例 from pydantic import BaseModel , Field , field_validator
from datetime import date
class UserUpdate ( BaseModel ):
name : str = Field ( min_length = 1 , max_length = 50 , description = "用户名" )
email : str = Field ( pattern = r '^[\w\.-]+@[\w\.-]+\.\w+$' )
age : int = Field ( ge = 0 , le = 150 , description = "年龄" )
birth_date : date | None = None
@field_validator ( 'name' )
@classmethod def name_must_not_be_empty ( cls , v ):
if not v . strip ():
raise ValueError ( '用户名不能为空' )
return v . strip ()
@field_validator ( 'age' )
@classmethod def age_must_be_positive ( cls , v ):
if v < 0 :
raise ValueError ( '年龄不能为负数' )
return v
嵌套模型 class Address ( BaseModel ):
street : str
city : str
country : str
zipcode : str
class UserDetail ( BaseModel ):
name : str
email : str
address : Address # 嵌套模型
tags : list [ str ] = []
@app . post ( "/users/detailed" )
def create_detailed_user ( user : UserDetail ):
return user . model_dump ()
# 请求体示例:
# {
# "name": "Alice",
# "email": "alice@example.com",
# "address": {
# "street": "123 Main St",
# "city": "Beijing",
# "country": "China",
# "zipcode": "100000"
# },
# "tags": ["developer", "python"]
# }
4.5 响应模型 控制响应数据 from pydantic import BaseModel , Field
class UserInDB ( BaseModel ):
id : int
name : str
email : str
hashed_password : str # 数据库中有密码
created_at : str
class UserPublic ( BaseModel ):
"""对外暴露的模型(不包含密码)"""
id : int
name : str
email : str
# 没有 hashed_password!
@app . post ( "/users" , response_model = UserPublic )
def create_user ( user : UserCreate ):
# 即使返回完整数据,响应也会只包含 UserPublic 的字段
db_user = save_to_db ( user ) # 包含 hashed_password
return db_user # 自动过滤掉 hashed_password
多个响应模型 from fastapi.responses import JSONResponse
@app . get ( "/users/ {user_id} " ,
response_model = UserPublic ,
responses = {
404 : { "model" : { "detail" : str }},
422 : { "description" : "验证错误" }
}
)
def get_user ( user_id : int ):
user = find_user ( user_id )
if not user :
return JSONResponse ( status_code = 404 , content = { "detail" : "用户不存在" })
return user
4.6 异步编程 sync vs async # 同步路由(在线程池中运行,不阻塞 Event Loop)
@app . get ( "/sync" )
def sync_endpoint ():
# 适合 CPU 密集型操作
result = heavy_computation ()
return { "result" : result }
# 异步路由(直接在 Event Loop 中运行)
@app . get ( "/async" )
async def async_endpoint ():
# 适合 I/O 密集型操作
result = await fetch_from_database ()
result2 = await call_external_api ()
return { "result" : result , "result2" : result2 }
并发异步请求 import httpx
@app . get ( "/aggregate" )
async def aggregate_data ():
async with httpx . AsyncClient () as client :
# 并发请求,不是串行!
user_resp , post_resp , comment_resp = await asyncio . gather (
client . get ( "http://users-api/users/1" ),
client . get ( "http://posts-api/posts?user_id=1" ),
client . get ( "http://comments-api/comments?user_id=1" ),
)
return {
"user" : user_resp . json (),
"posts" : post_resp . json (),
"comments" : comment_resp . json (),
}
4.7 依赖注入(Dependency Injection) FastAPI 最强大的特性之一。
基本依赖 from fastapi import Depends , Query
# 定义依赖
async def common_params (
skip : int = Query ( 0 , ge = 0 ),
limit : int = Query ( 100 , ge = 1 , le = 100 ),
):
return { "skip" : skip , "limit" : limit }
# 使用依赖
@app . get ( "/items" )
async def list_items ( params : dict = Depends ( common_params )):
return { "params" : params }
@app . get ( "/users" )
async def list_users ( params : dict = Depends ( common_params )):
return { "params" : params }
认证依赖 from fastapi import Depends , HTTPException , status
from fastapi.security import HTTPBearer , HTTPAuthorizationCredentials
security = HTTPBearer ()
async def get_current_user (
credentials : HTTPAuthorizationCredentials = Depends ( security )
):
token = credentials . credentials
user = decode_token ( token )
if not user :
raise HTTPException (
status_code = status . HTTP_401_UNAUTHORIZED ,
detail = "无效的认证令牌"
)
return user
@app . get ( "/users/me" )
async def get_me ( current_user : dict = Depends ( get_current_user )):
return current_user
数据库会话依赖 from sqlalchemy.orm import Session
def get_db ():
db = SessionLocal ()
try :
yield db # 生成器依赖:yield 之前的代码在请求前执行,yield 之后的代码在请求后执行
finally :
db . close ()
@app . get ( "/items/ {item_id} " )
def get_item ( item_id : int , db : Session = Depends ( get_db )):
item = db . query ( Item ) . filter ( Item . id == item_id ) . first ()
if not item :
raise HTTPException ( status_code = 404 , detail = "物品不存在" )
return item
依赖链 async def verify_token ( token : str = Depends ( security )):
return decode_token ( token . credentials )
async def get_user_from_token (
token_data : dict = Depends ( verify_token )
):
user = find_user ( token_data [ "user_id" ])
if not user :
raise HTTPException ( status_code = 401 , detail = "用户不存在" )
return user
async def require_admin (
current_user : dict = Depends ( get_user_from_token )
):
if not current_user . get ( "is_admin" ):
raise HTTPException ( status_code = 403 , detail = "需要管理员权限" )
return current_user
@app . delete ( "/users/ {user_id} " )
async def delete_user (
user_id : int ,
admin : dict = Depends ( require_admin )
):
# 只有管理员能访问
...
4.8 中间件 from starlette.middleware.base import BaseHTTPMiddleware
import time
# 请求耗时中间件
@app . middleware ( "http" )
async def process_request ( request , call_next ):
start_time = time . time ()
response = await call_next ( request )
process_time = time . time () - start_time
response . headers [ "X-Process-Time" ] = str ( process_time )
return response
# CORS 中间件
from starlette.middleware.cors import CORSMiddleware
app . add_middleware (
CORSMiddleware ,
allow_origins = [ "https://example.com" ],
allow_credentials = True ,
allow_methods = [ "*" ],
allow_headers = [ "*" ],
)
4.9 WebSocket 支持 from fastapi import WebSocket
@app . websocket ( "/ws/chat" )
async def websocket_endpoint ( websocket : WebSocket ):
await websocket . accept ()
try :
while True :
data = await websocket . receive_text ()
# 广播给所有连接
await websocket . send_text ( f "Echo: { data } " )
except WebSocketDisconnect :
pass
4.10 完整项目结构 my-fastapi-app/
├── app/
│ ├── __init__.py
│ ├── main.py # FastAPI 应用入口
│ ├── config.py # 配置
│ ├── models/
│ │ ├── __init__.py
│ │ ├── user.py # Pydantic 模型
│ │ └── post.py
│ ├── schemas/
│ │ ├── __init__.py
│ │ ├── user.py # 请求/响应 Schema
│ │ └── post.py
│ ├── api/
│ │ ├── __init__.py
│ │ ├── deps.py # 依赖注入
│ │ ├── users.py # 用户路由
│ │ └── posts.py # 文章路由
│ ├── services/
│ │ ├── user_service.py # 业务逻辑
│ │ └── email_service.py
│ ├── database.py # 数据库连接
│ └── middleware.py # 中间件
├── tests/
│ ├── test_users.py
│ └── test_posts.py
├── requirements.txt
├── Dockerfile
└── README.md
4.11 AI/ML 模型服务案例 from fastapi import FastAPI , File , UploadFile
from pydantic import BaseModel
import numpy as np
app = FastAPI ( title = "AI 图像分类服务" )
# 加载模型(启动时加载一次)
model = load_model ( "resnet50.pth" )
classes = [ "cat" , "dog" , "bird" , "fish" ]
class PredictionResult ( BaseModel ):
class_name : str
confidence : float
all_probs : dict
@app . post ( "/predict" , response_model = PredictionResult )
async def predict ( file : UploadFile = File ( ... )):
# 读取上传的图片
contents = await file . read ()
image = preprocess_image ( contents )
# 模型推理
with torch . no_grad ():
output = model ( image )
probs = torch . softmax ( output , dim = 1 )[ 0 ]
# 返回结果
top_idx = probs . argmax () . item ()
return PredictionResult (
class_name = classes [ top_idx ],
confidence = probs [ top_idx ] . item (),
all_probs = { classes [ i ]: probs [ i ] . item () for i in range ( len ( classes ))}
)
@app . get ( "/health" )
async def health ():
return { "status" : "healthy" , "model_loaded" : model is not None }
4.12 总结 核心概念 一句话 类型提示 原生 Python 类型 = 自动验证 + 自动文档 Pydantic 数据验证和序列化的标准库 async/await 原生异步,I/O 密集型场景性能优异 依赖注入 可复用、可测试、可组合的依赖系统 自动文档 /docs(Swagger)和 /redoc 开箱即用 AI/ML 集成 Python 生态无缝对接
FastAPI 的优势: 类型安全、自动文档、高性能、Python 生态 FastAPI 的不足: 相对年轻(2018 年),社区生态不如 Express 成熟
上一章:Express.js 框架 | 下一章:Nginx 原理与配置