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}
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" |
/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 图清晰展示了三者在一个完整请求中的协作流程:
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 测试。