3. FastAPI 基础:快速搭建 Hello World API

本章是后端部署运维实战的起点。我们将从零搭建一个 FastAPI 应用,通过最简的 Hello World 接口,理解路由、请求方法、路径参数与查询参数这四个核心概念。掌握这些基础后,后续的鉴权拦截中间件才能有正确的挂载位置。

3.1 环境准备与项目初始化

确保 Python 版本 ≥ 3.8,使用 pip 安装 FastAPI 和 ASGI 服务器 Uvicorn:

pip install fastapi uvicorn

创建项目文件 main.py,写入以下代码:

from fastapi import FastAPI

app = FastAPI(title="Hello World API")

@app.get("/")
async def root():
    return {"message": "Hello World"}

启动服务:

uvicorn main:app --reload --host 0.0.0.0 --port 8000

访问 http://localhost:8000,浏览器或 curl 应返回 JSON:{"message":"Hello World"}。

提示: --reload 会在代码变更时自动重启,适合开发阶段;生产环境应去掉此参数。

3.2 路由与请求方法

路由(Route)是 URL 路径与处理函数的映射。FastAPI 通过装饰器 @app.<method>() 注册路由,<method> 对应 HTTP 方法:

装饰器 HTTP 方法 典型用途
@app.get() GET 查询资源
@app.post() POST 创建资源
@app.put() PUT 全量更新资源
@app.patch() PATCH 部分更新资源
@app.delete() DELETE 删除资源

下面扩展 main.py,增加 POST 和 DELETE 示例:

@app.post("/items")
async def create_item():
    return {"status": "created"}

@app.delete("/items/{item_id}")
async def delete_item(item_id: int):
    return {"deleted": item_id}
关键理解: 路由装饰器决定了该接口的 HTTP 方法。同一个路径可以注册多个方法,FastAPI 会自动根据请求方法分发。

3.3 路径参数

路径参数是 URL 路径中的动态片段,用花括号 {param} 声明。FastAPI 会自动提取并做类型转换:

@app.get("/users/{user_id}")
async def get_user(user_id: int):
    return {"user_id": user_id, "name": f"User_{user_id}"}

访问 /users/42 返回 {"user_id":42,"name":"User_42"}。若传入非数字(如 /users/abc),FastAPI 自动返回 422 校验错误。

路径参数 类型声明 示例 URL 提取值
{item_id} int /items/5 5
{username} str /users/alice "alice"
{file_path:path} str + :path /files/home/docs/readme.txt "home/docs/readme.txt"
注意: 路径参数的顺序很重要。FastAPI 按路由定义顺序匹配,若 /users/{user_id} 和 /users/me 同时存在,必须将 /users/me 定义在前面,否则 me 会被当作 user_id 捕获。

3.4 查询参数

查询参数是 URL 中 ? 后的键值对,如 ?skip=0&limit=10。FastAPI 将函数参数中未声明为路径参数的参数自动识别为查询参数:

@app.get("/items")
async def list_items(skip: int = 0, limit: int = 10):
    return {"skip": skip, "limit": limit}

访问 /items?skip=5&limit=20 返回 {"skip":5,"limit":20}。查询参数支持默认值、可选参数和类型校验:

from typing import Optional

@app.get("/search")
async def search(q: Optional[str] = None, page: int = 1):
    return {"query": q, "page": page}

不传 q 时值为 None,page 默认为 1。

3.5 路由、路径参数与查询参数的关系

下面这张 SVG 图清晰展示了三者在一个完整请求中的协作流程:

FastAPI 请求路由解析流程 客户端 GET /users/42?skip=0&limit=10 HTTP方法 + 路径 + 路径参数 + 查询参数 路由匹配 @app.get("/users/{user_id}") 参数提取 user_id=42, skip=0, limit=10 async def get_user(user_id: int, skip: int, limit: int) 路径参数 → 函数位置参数 | 查询参数 → 函数关键字参数 JSON 响应 关键规则 路径参数必填 查询参数可选+默认值

3.6 综合示例:完整的 CRUD 骨架

将上述概念整合为一个简单的物品管理接口:

from fastapi import FastAPI, Query
from typing import Optional

app = FastAPI()

# 模拟数据库
items_db = {}

@app.get("/items")
async def list_items(skip: int = 0, limit: int = 10):
    all_items = list(items_db.values())
    return all_items[skip: skip + limit]

@app.get("/items/{item_id}")
async def get_item(item_id: int):
    return items_db.get(item_id, {"error": "not found"})

@app.post("/items/{item_id}")
async def create_item(item_id: int, name: str = Query(..., min_length=1)):
    items_db[item_id] = {"id": item_id, "name": name}
    return items_db[item_id]

@app.delete("/items/{item_id}")
async def delete_item(item_id: int):
    items_db.pop(item_id, None)
    return {"deleted": item_id}
实战要点:
  • 路径参数 item_id 用于定位单个资源。
  • 查询参数 skip、limit 控制分页。
  • Query(...) 表示该查询参数为必填,且最小长度 1。
  • 所有接口返回 JSON,FastAPI 自动序列化字典。

3.7 自动交互文档

FastAPI 内置 Swagger UI 和 ReDoc。启动服务后访问:

  • Swagger UI: http://localhost:8000/docs
  • ReDoc: http://localhost:8000/redoc

这两个页面会自动列出所有注册的路由、请求方法、参数类型和示例值,是调试和测试接口的利器。后续章节的鉴权拦截器也会在文档中自动体现。

建议: 开发阶段始终开启 /docs,可以快速验证路径参数和查询参数的正确性,减少手动 curl 测试。