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)。

关键概念: FastAPI 应用是一个 ASGI 应用实例。Uvicorn 作为 ASGI 服务器,负责接收 HTTP 请求并调用 FastAPI 的路由处理函数。使用 --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 校验错误。

注意: 路径参数的顺序很重要。FastAPI 按定义顺序匹配路由,因此静态路径应放在动态路径之前,避免被动态路由捕获。

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。

性能要点: 查询参数和请求体的解析在 FastAPI 内部是异步且零拷贝的。对于高并发场景,建议将非敏感过滤条件放在查询参数中,将复杂结构化数据放在请求体中,以利用 HTTP 缓存和 CDN 加速。

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 错误,包含具体字段路径和错误原因。

低延迟实践: Pydantic v2 基于 Rust 核心(pydantic-core)重写,校验速度比 v1 快 5~50 倍。在评分接口中,建议将请求体模型设计得尽量扁平,减少嵌套深度,以降低序列化/反序列化开销。

3.5 FastAPI 请求处理流程总览

下图展示了 FastAPI 从接收 HTTP 请求到返回响应的完整链路:

FastAPI 请求处理流程 HTTP 请求 路由匹配 参数解析 路径参数 查询参数 请求体 (Pydantic) 业务处理函数 自动文档 /docs (Swagger) /redoc (ReDoc) OpenAPI 规范

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 实现声明式校验,确保数据质量。