写点什么

FastAPI 快速开发 Web API 项目: 响应模型与错误处理

作者:宇宙之一粟
  • 2023-04-16
    广东
  • 本文字数:3799 字

    阅读完需:约 12 分钟

FastAPI 快速开发 Web API 项目: 响应模型与错误处理

FastAPI 快速开发 Web API 项目学习笔记:


介绍

在前面的文章中,我们可以通过注释路径操作函数返回类型来声明用于响应的类型。


因此,我们可以像在函数参数中输入数据一样使用类型注释,使用 Pydantic 模型、列表、字典、标量值(如整数、布尔值等)。

响应模型

响应模型作为模板,用于从 API 路由的路径返回数据。它们建立在 Pydantic 上,以正确解析从客户端到服务器的请求响应。


Responses 是 API 生命周期的一个组成部分。响应是通过任何标准的 HTTP 方法与 API 路由交互而收到的反馈。一个 API 响应通常是 JSON 或 XML 格式,但它也可以是文档形式。响应一般由一个头和一个响应体组成。


响应头


响应头由请求的状态和附加信息组成,以指导响应体的交付。响应头中包含的信息的一个例子是 头中包含的信息的一个例子是 Content-Type,它告诉客户端返回的内容类型。


响应体


另一方面,响应体是客户端向服务器请求的数据。


响应体是由 Content-Type 头变量决定的,最常用的是 application/json 。

建立 FastAPI 响应模型

FastAPI 可以为 response_model 定义 API 输出的数据格式:


  1. 对 API 响应返回的数据进行验证

  2. 转化输出数据对应 response_model 所定义的数据模型,它将限制和过滤输出数据,使之符合返回类型中的定义。这对于 API 安全性尤为重要

  3. 可以根据 response_model 指定的数据格式,限制可以输出的数据:如果数据是无效的(例如,你缺少一个字段),这意味着你的应用程序代码被破坏了,没有返回它应该返回的东西,它将返回一个服务器错误,而不是返回错误的数据

  4. 为响应添加一个 JSON schema,在 OpenAPI 的路由操作中上体现,方便开发者可以直接从文件上看到 API 需要的文件格式,它也将被自动客户端代码生成工具所使用


之前的文章中学习了如何使用 Pydantic 来构建模型。在 FastAPI 中,响应模型也是建立在 Pydantic 上的,但其目的不同。例如,在路由路径的定义中,我们有以下内容:


@todo_router.get("/todo")async def retrieve_todos() -> dict:    return {        "todos": todo_list    }
复制代码


该路由返回数据库中存在的待办事项的列表。下面是一些输出的例子:


{  "todos": [    {      "id": 1,      "name": "write a todo",      "item": "write a todo project"    },    {      "id": 2,      "name": "learning path",      "item": "learning path parameters"    },    {      "id": 3,      "name": "learning query",      "item": "learning query parameters"    }  ]}
复制代码


该路由返回存储在 todos 数组中的所有内容。为了指定要返回的信息,我们必须把要显示的数据分开,或者引入额外的逻辑。幸运的是,我们可以创建一个包含我们想要返回的字段的模型,并使用 response_model 参数将其添加到我们的路由定义中。


先定义一个新的模型类来返回待办事项的列表,在 model.py 中进行代码变更:


from pydantic import BaseModel, StrictIntfrom typing import List

class Todo(BaseModel): id: StrictInt name: str item: str

class TodoItem(BaseModel): item: str class Config: schema_extra = { "example": { "item": "test" } }
class TodoItems(BaseModel): todos: List[TodoItem] class Config: schema_extra = { "example": { "todos": [ { "item": "Example schema 1!" }, { "item": "Example schema 2!" } ] } }
复制代码


$ curl -X 'POST' 'http://127.0.0.1:8888/todo' -H 'accept: application/json' -H 'Content-Type: application/json' -d '{"id": 1,"name": "test", "item": "This todo will be retrieved without exposing my ID!"}'{"message":"Todo added successfully"}
复制代码


$ curl -X 'GET' 'http://127.0.0.1:8888/todo' -H 'accept: applicatiion/json'{"todos":[{"item":"This todo will be retrieved without exposing my ID!"}]}
复制代码

状态码

状态码是服务器为响应客户的请求而发出的独特的短代码。 在 HTTP 中,您发送一个 3 位数的数字状态代码作为响应的一部分。这些状态代码有一个关联的名称来识别它们,但重要的部分是数字。响应状态代码被分为五类,每一类表示不同的响应:


  • 100 及以上为“信息”。你很少直接使用它们。具有这些状态代码的响应不能有正文。

  • 200 及以上表示“成功”响应。这些是您最常使用的。

  • 200 是默认状态代码,表示一切正常。

  • 另一个例子是 201,“已创建”。它通常在数据库中创建新记录后使用。

  • 一个特例是 204,“无内容”。当没有内容返回给客户端时使用此响应,因此响应不能有正文。

  • 300 及以上用于“重定向”。具有这些状态代码的响应可能有也可能没有正文,但 304“未修改”除外,它不能有正文。

  • 400 及以上用于“客户端错误”响应。这些是您可能最常使用的第二种类型。

  • 一个示例是 404,表示“未找到”响应。

  • 对于来自客户端的一般错误,您可以只使用 400。

  • 500 及以上是服务器错误。你几乎从不直接使用它们。当您的应用程序代码或服务器的某个部分出现问题时,它会自动返回这些状态代码之一。


总结就是:


  • 1XX: 请求被接收

  • 2XX: 请求成功

  • 3XX: 请求重定向

  • 4XX: 客户端错误

  • 5XX: 服务端错误


完整的状态码列表可以点此处



在构建 Web 应用程序时,不管是什么框架,所遵循的标准做法是为各个事件返回适当的状态代码。400 状态码不应该被返回给服务器错误。同样地,200 状态码也不应该在请求操作失败时返回。

定义 HTTP 状态码

除了定义 response_model 之外,也可以在路由操作中确定 API 预期返回的 HTTP 状态码:


@app.post( '/user/login' , response_model=UserBase, status_code= 201 ) def  login ( user_in: UserIn ):返回user_in    
复制代码


如果 HTTP 状态码记不过来,但是知道状态消息类别,也可以使用 FastAPI 提供的状态:


from fastapi import FastAPI, status @app.post( '/user/login' , response_model=UserBase, status_code=status.HTTP_201_CREATED ) def  login ( user_in: UserIn ):返回user_in
复制代码


FastAPI 将使用该时间响应来提取状态代码(还有 cookie 和标头),并将它们放入包含您返回的值的最终响应中,由任何 response_model 过滤。您也可以在依赖项中声明 Response 参数,并在其中设置状态码。但请记住,最后设置的将获胜。

错误处理

错误处理包括在处理应用程序的错误时涉及的实践和活动。这些做法包括返回适当的错误状态代码和错误信息。


请求可能会返回错误的响应,这些响应可能是意料之外的,或者对请求失败原因的信息不足。请求的错误可能是由于试图访问不存在的资源、没有足够权限的受保护页面,甚至是服务器错误。FastAPI 中的错误是通过使用 FastAPI 的 HTTPException 类引发一个异常来处理的:


  • 状态码:返回失败的状态码

  • 描述:将向客户发送的附带信息

  • 头:一个可选的参数,用于需要头信息的响应



在我们的待办事项路由定义中,当一个待办事项找不到时,我们会返回一个消息。我们将更新它以引发 HTTPException 。HTTPException 允许我们返回一个适当的错误响应代码。


如果根据上一节路由中的方法,如果访问一个 id 不存在的待办事项: 1111,我们虽然会返回一个错误信息,但是状态码是返回 200,这与状态码的规则是不相符的,如图所示:


HTTP/1.1 200 OKcontent-length: 50content-type: application/jsondate: Mon, 10 Apr 2023 06:42:15 GMTserver: uvicorn
{"message":"Todo with supplied ID doesn't exist."}
复制代码



因此,我们需要修改一下代码,使用 HTTPException,如下:


@todo_router.get("/todo/{todo_id}")async def get_single_todo(todo_id: int = Path(...,                                              title="The ID of the todo to be retrieved.")) -> dict:    for todo in todo_list:        # if todo["id"] == todo_id:        if todo.id == todo_id:            return {                "todo": todo            }    # return {    #     "message": "Todo with supplied ID doesn't exist."    # }    raise HTTPException(        status_code=status.HTTP_404_NOT_FOUND,        detail= "Todo with supplied ID doesn't exist",    )
复制代码


此时,我们返回的状态码就是 404 Not Found,


总结

本文学习了什么是响应和响应模型,以及错误处理的含义,并了解了 HTTP 状态码以及它的含义。并利用 FastAPI 创建了一个响应模型,只返回待办事项列表中的 item ,而不返回其 id。最后,我们学习了错误和错误处理,让 Todo 应用在发生查不到的情况返回 404 错误,而不是 200 状态码。


希望本文能对你有所帮助,如果喜欢本文,可以点个关注.


下一篇文章见!宇宙古今无有穷期,一生不过须臾,当思奋争。


参考链接:

发布于: 15 小时前阅读数: 4
用户头像

宇宙古今无有穷期,一生不过须臾,当思奋争 2020-05-07 加入

🏆InfoQ写作平台-签约作者 🏆 混迹于江湖,江湖却没有我的影子 热爱技术,专注于后端全栈,轻易不换岗 拒绝内卷,工作于外企开发,弹性不加班 热衷分享,执着于阅读写作,佛系不水文 同名公众号:《宇宙之一粟》

评论

发布
暂无评论
FastAPI 快速开发 Web API 项目: 响应模型与错误处理_Python_宇宙之一粟_InfoQ写作社区