3. FastAPI 基础入门:创建第一个 FastAPI 应用、路由与路径参数、查询参数与请求体、使用 Pydantic 进行数据校验
FastAPI 是一个现代、高性能的 Python Web 框架,专为构建 API 而设计。它基于 Starlette(网络层)和 Pydantic(数据层),天然支持异步、自动生成 OpenAPI 文档,并且性能接近 Node.js 和 Go。本章将从零搭建第一个 FastAPI 应用,并系统讲解路由、参数传递与数据校验的核心机制。
3.1 创建第一个 FastAPI 应用
安装 FastAPI 和 ASGI 服务器(推荐 Uvicorn):
pip install fastapi uvicorn
创建一个 main.py 文件,写入以下代码:
from fastapi import FastAPI
app = FastAPI(title="低延迟评分接口", version="1.0.0")
@app.get("/")
def read_root():
return {"message": "评分服务已启动"}
启动服务:
uvicorn main:app --host 0.0.0.0 --port 8000 --reload
访问 http://localhost:8000 即可看到 JSON 响应。同时,FastAPI 自动生成交互式文档:http://localhost:8000/docs(Swagger UI)和 http://localhost:8000/redoc(ReDoc)。
--reload 可在代码变更时自动重启,适合开发阶段。
3.2 路由与路径参数
路由(Route)将 HTTP 方法与 URL 路径绑定到处理函数。路径参数(Path Parameter)是从 URL 路径中提取的动态片段。
| 装饰器 | HTTP 方法 | 典型用途 |
|---|---|---|
@app.get() |
GET | 查询资源 |
@app.post() |
POST | 创建资源 |
@app.put() |
PUT | 全量更新资源 |
@app.patch() |
PATCH | 部分更新资源 |
@app.delete() |
DELETE | 删除资源 |
路径参数示例:
@app.get("/users/{user_id}")
def get_user(user_id: int):
return {"user_id": user_id, "name": f"User_{user_id}"}
@app.get("/items/{item_id}/reviews/{review_id}")
def get_review(item_id: int, review_id: int):
return {"item_id": item_id, "review_id": review_id}
路径参数使用花括号 {param} 声明,函数参数名必须与路径中的名称一致。FastAPI 会自动进行类型转换和校验——如果传入非整数值,将返回 422 校验错误。
3.3 查询参数与请求体
查询参数(Query Parameter)是 URL 中 ? 后的键值对,用于过滤、排序或分页。请求体(Request Body)则通过 POST/PUT/PATCH 方法发送,通常承载 JSON 数据。
查询参数
@app.get("/scores/")
def list_scores(
min_score: float = 0.0,
max_score: float = 100.0,
category: str | None = None,
page: int = 1,
size: int = 20
):
return {
"filters": {
"min_score": min_score,
"max_score": max_score,
"category": category
},
"pagination": {"page": page, "size": size}
}
查询参数是函数参数中未在路径中出现的参数。默认值表示该参数可选;无默认值的查询参数为必填。
请求体
请求体数据通过 Pydantic 模型定义,FastAPI 自动解析 JSON 并校验:
from pydantic import BaseModel
class ScoreInput(BaseModel):
user_id: int
item_id: int
score: float
comment: str | None = None
@app.post("/scores/")
def create_score(input_data: ScoreInput):
return {
"received": input_data.model_dump(),
"message": "评分已记录"
}
FastAPI 根据类型注解自动区分:路径参数 → 路径中提取;查询参数 → URL 查询字符串;Pydantic 模型 → 请求体 JSON。
3.4 使用 Pydantic 进行数据校验
Pydantic 是 FastAPI 的数据校验核心。它通过 Python 类型注解定义数据模型,自动完成类型转换、值校验和错误报告。
基础模型与字段校验
from pydantic import BaseModel, Field, field_validator
from typing import Literal
class RatingRequest(BaseModel):
user_id: int = Field(..., gt=0, description="用户ID,必须大于0")
item_id: int = Field(..., gt=0, description="物品ID,必须大于0")
score: float = Field(..., ge=0.0, le=5.0, description="评分,0.0~5.0")
category: Literal["movie", "book", "music"] = "movie"
tags: list[str] = Field(default_factory=list, max_length=10)
@field_validator("score")
@classmethod
def check_score_precision(cls, v: float) -> float:
if round(v, 1) != v:
raise ValueError("评分最多保留一位小数")
return v
| Pydantic 特性 | 说明 | 示例 |
|---|---|---|
Field() |
定义字段约束、默认值、描述 | Field(gt=0, le=100) |
Literal |
限定字段只能取指定值 | Literal["movie", "book"] |
field_validator |
自定义字段级校验逻辑 | 校验精度、格式、业务规则 |
model_dump() |
将模型实例转为字典 | input_data.model_dump() |
model_validate() |
从字典或 JSON 创建模型 | RatingRequest.model_validate(data) |
嵌套模型与复杂结构
class Address(BaseModel):
city: str
district: str
detail: str
class UserProfile(BaseModel):
name: str = Field(..., min_length=1, max_length=50)
age: int = Field(..., ge=0, le=150)
email: str | None = None
address: Address | None = None
@app.post("/users/")
def create_user(profile: UserProfile):
return {"status": "ok", "data": profile.model_dump()}
嵌套模型自动递归校验,任何层级的数据不合法都会返回清晰的 422 错误,包含具体字段路径和错误原因。
3.5 FastAPI 请求处理流程总览
下图展示了 FastAPI 从接收 HTTP 请求到返回响应的完整链路:
3.6 完整示例:评分提交接口
综合本章知识点,实现一个完整的评分提交端点:
from fastapi import FastAPI, Query, Path
from pydantic import BaseModel, Field, field_validator
from typing import Literal
app = FastAPI(title="评分服务", version="1.0.0")
class RatingCreate(BaseModel):
user_id: int = Field(..., gt=0, description="用户ID")
item_id: int = Field(..., gt=0, description="物品ID")
score: float = Field(..., ge=0.0, le=5.0, description="评分值")
category: Literal["movie", "book", "music"] = "movie"
comment: str | None = Field(None, max_length=500)
@field_validator("score")
@classmethod
def one_decimal(cls, v: float) -> float:
if round(v, 1) != v:
raise ValueError("评分最多保留一位小数")
return v
@app.post("/ratings/")
def create_rating(
rating: RatingCreate,
source: str = Query("api", description="请求来源"),
trace_id: str | None = Query(None, description="追踪ID")
):
return {
"status": "success",
"data": rating.model_dump(),
"meta": {"source": source, "trace_id": trace_id}
}
@app.get("/ratings/{rating_id}")
def get_rating(
rating_id: int = Path(..., gt=0, description="评分记录ID"),
include_comment: bool = Query(False, description="是否包含评论")
):
return {
"rating_id": rating_id,
"include_comment": include_comment,
"message": "评分详情查询成功"
}
- 使用
Literal类型限制枚举值,避免运行时字符串比对。 - 字段校验器使用
@classmethod并保持轻量,避免在热路径中执行重计算。 - 查询参数中
trace_id设为可选,不强制客户端传递,减少请求失败率。 - 路径参数
rating_id使用gt=0校验,防止 SQL 注入或无效查询。
3.7 本章小结
通过本章学习,你已经掌握了 FastAPI 的核心基础:
- 应用创建: 使用
FastAPI()实例化,搭配 Uvicorn 启动。 - 路由与路径参数: 通过装饰器绑定 HTTP 方法与路径,使用类型注解自动提取和校验路径参数。
- 查询参数与请求体: 函数参数中未出现在路径中的参数自动成为查询参数;Pydantic 模型参数自动解析请求体 JSON。
- Pydantic 数据校验: 利用
Field、Literal、field_validator实现声明式校验,确保数据质量。