第一个 FastAPI 应用:从零到运行
实验目标
创建并运行一个完整的 FastAPI 应用,理解启动流程、路径操作、自动文档。
环境准备
bash
# 创建虚拟环境
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# 安装依赖
pip install fastapi uvicorn[standard]实验 1:Hello World
创建 main.py:
python
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
@app.get("/items/{item_id}")
async def read_item(item_id: int, q: str = None):
return {"item_id": item_id, "q": q}运行:
bash
uvicorn main:app --reload测试:
bash
# 根路径
curl http://localhost:8000/
# 输出: {"message":"Hello World"}
# 路径参数
curl http://localhost:8000/items/42
# 输出: {"item_id":42,"q":null}
# 查询参数
curl http://localhost:8000/items/42?q=test
# 输出: {"item_id":42,"q":"test"}
# 类型错误
curl http://localhost:8000/items/foo
# 输出: 422 错误实验 2:请求体与验证
python
from pydantic import BaseModel, Field
class Item(BaseModel):
name: str = Field(..., min_length=1, max_length=50)
description: str = None
price: float = Field(..., gt=0)
tax: float = None
@app.post("/items/")
async def create_item(item: Item):
item_dict = item.dict()
if item.tax:
price_with_tax = item.price + item.tax
item_dict.update({"price_with_tax": price_with_tax})
return item_dict测试:
bash
# 正确请求
curl -X POST http://localhost:8000/items/ \
-H "Content-Type: application/json" \
-d '{"name":"Laptop","price":1200.00,"tax":120.00}'
# 输出: {"name":"Laptop","description":null,"price":1200.0,"tax":120.0,"price_with_tax":1320.0}
# 验证错误:price 为负数
curl -X POST http://localhost:8000/items/ \
-H "Content-Type: application/json" \
-d '{"name":"Laptop","price":-100}'
# 输出: 422 错误,说明 price 必须大于 0实验 3:查看自动文档
Swagger UI:访问 http://localhost:8000/docs
- 交互式测试界面
- 自动生成的 API 文档
- 可以直接在浏览器测试 API
ReDoc:访问 http://localhost:8000/redoc
- 更清晰的文档视图
- 适合分享给前端团队
OpenAPI JSON:访问 http://localhost:8000/openapi.json
- 原始 OpenAPI 规范
- 可用于生成客户端代码
实验 4:响应模型
python
from typing import Optional
class ItemResponse(BaseModel):
name: str
price: float
price_with_tax: Optional[float] = None
@app.post("/items/", response_model=ItemResponse)
async def create_item(item: Item):
# 即使返回额外字段,也只序列化 response_model 定义的字段
return {
"name": item.name,
"price": item.price,
"price_with_tax": item.price + (item.tax or 0),
"internal_field": "这个不会出现在响应中"
}实验 5:状态码
python
from fastapi import status, HTTPException
@app.post("/items/", status_code=status.HTTP_201_CREATED)
async def create_item(item: Item):
return item
@app.get("/items/{item_id}")
async def read_item(item_id: int):
if item_id not in items:
raise HTTPException(status_code=404, detail="Item not found")
return items[item_id]验收标准
✅ 应用成功启动,访问 http://localhost:8000 返回 Hello World
✅ 路径参数和查询参数正确工作
✅ 请求体验证失败返回 422 错误
✅ /docs 和 /redoc 可访问且显示完整文档
✅ 响应模型过滤了多余字段
✅ 状态码和异常处理正确
常见问题
Q: uvicorn 找不到 app
bash
# 确保文件名是 main.py,且代码中有 app = FastAPI()
# 或明确指定:uvicorn filename:appQ: 自动重载不工作
bash
# 确保使用 --reload 标志
uvicorn main:app --reloadQ: 端口已被占用
bash
# 更改端口
uvicorn main:app --port 8001下一步:进入调试与边界学习错误处理。