Skip to content

回复客户端: 响应模型与错误处理

API 是一种双向对话。我们已经掌握了“倾听”(输入),现在必须掌握“说话”(响应)。在本章中,我们将学习如何严格定义 API 返回给客户端的内容,以及如何优雅地处理错误。

默认情况下,FastAPI 允许您返回几乎任何内容——字典、列表或数据库对象——它都会将它们转换为 JSON。然而,明确定义**响应模型(Response Model)**提供了以下关键优势:

  • 数据过滤:它将输出数据限制为模型中精确定义的内容。
  • 安全性:它防止敏感字段(如密码)的意外泄露。
  • 文档:它在 API 文档中为响应生成 JSON Schema。

假设我们有一个用于输入的 User 模型,其中包含密码,但我们想要一个单独的用于输出的模型,该模型排除密码。

from pydantic import BaseModel
class UserIn(BaseModel):
username: str
password: str
email: str
class UserOut(BaseModel):
username: str
email: str
# 密码被有意省略
@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn):
return user

即使我们返回了 user 对象(其中包含密码),FastAPI 也会检测到 response_model=UserOut 并自动过滤数据。客户端将只接收到 username 和 email。

在 HTTP 中,状态码告诉客户端操作的结果。虽然 200 OK 是默认值,但使用特定的状态码通常更合适。例如,当创建一个新资源时,201 Created 是标准状态码。

FastAPI 通过 status 模块提供了一个快捷方式,以避免记住数字。

from fastapi import status
@app.post("/items/", status_code=status.HTTP_201_CREATED)
async def create_item(name: str):
return {"name": name}

有时,事情会出错。用户请求了一个不存在的 ID,或者他们缺乏权限。您不应该只返回一个字典,例如 {"error": "not found"},因为那仍然会导致 200 OK 状态码,从而混淆前端逻辑。

相反,请使用 HTTPException。

from fastapi import HTTPException
items = {"foo": "The Foo Wrestler"}
@app.get("/items/{item_id}")
async def read_item(item_id: str):
if item_id not in items:
raise HTTPException(status_code=404, detail="Item not found")
return {"item": items[item_id]}

当您 raise 一个 HTTPException 时,FastAPI 会立即停止路径操作的执行,并向客户端发送一个正确的 JSON 错误响应:

{
"detail": "Item not found"
}

如果需要,您还可以向错误响应添加自定义头(headers),使您的错误处理更健壮并符合 HTTP 标准。