使用 Flask、Connexion 和 SQLAlchemy 构建 Python REST API

2025年3月17日 | 阅读 15 分钟

创建虚拟环境

在本教程中,您将构建您的项目结构。您可以随意命名项目的根文件夹。例如,您可以将其命名为 rp_flask_api/。创建该文件夹并进入其中

在 Shell 中创建文件夹的语法

这里,mkdir 代表命令行中的 make directory 语法

在这种情况下,您将项目的根文件夹命名为 rp_flask_api/。您在本系列中创建的文件和文件夹将位于此文件夹或其子文件夹中。

进入项目文件夹后,最好创建并激活一个虚拟环境。这样,您所安装的任何项目依赖项都不是系统范围的,而只是在您的项目虚拟环境中。

选择您下面的操作系统,并使用您特定于平台的命令来设置虚拟环境

Power shell

使用上面显示的命令,您通过使用 Python 内置的 venv 模块来创建和激活一个名为 venv 的虚拟环境。提示符前的括号 (venv) 表示您已成功激活虚拟环境。

添加依赖项

创建并激活虚拟环境后,现在是时候用 pip 安装 Flask 了

Shell

Flask 微型 Web 框架是您的项目所需的主要依赖项。除了 Flask,还要安装 Connexion 来处理 HTTP 请求

Shell

为了同样使用自动生成的 API 文档,您安装了带有 Swagger UI 额外支持的 Connexion。在本教程的后面,您将了解您最近安装的 Python 包。

启动您的 Flask 项目

您的 Flask 项目的主文件将是 app.py。在 rp_flask_api/ 中创建 app.py 并添加以下内容

说明

您导入 Flask 模块,使应用程序能够访问 Flask 功能。然后您创建一个名为 app 的 Flask 应用程序实例。接下来,您通过使用 @app.route("/") 装饰器将 URL 路由 "/" 连接到 home() 函数。此函数调用 Flask 的 rend_template() 函数从 templates 目录获取 home.html 文件并将其返回给浏览器。

简而言之,此代码会启动一个基本的 Web 服务器,并使其响应 home.html 模板,该模板将在导航到 URL "/" 时提供给浏览器。

注意:Flask 的开发服务器默认端口为 5000。在较新的 macOS 版本上,此端口已被 macOS AirPlay 接收器占用。上面,您已将 Flask 应用程序的端口更改为 port=8000。如果您愿意,可以更改 Mac 上的 AirPlay 接收器偏好设置。

Flask 期望 home.html 位于名为 templates/ 的模板目录中。创建 templates/ 目录并添加 home.html

Flask 附带 Jinja 模板引擎,它使您能够增强您的模板。但是,您的 home.html 模板是一个基本的 HTML 文件,没有 Jinja 功能。现在这样很好,因为 home.html 的目的是检查您的 Flask 项目是否按预期响应。

在 Python 虚拟环境处于活动状态的情况下,您可以在包含 app.py 文件的目录中使用此命令行运行您的应用程序

Shell

当您运行 app.py 时,Web 服务器将在端口 8000 上启动。如果您打开浏览器并导航到 https://:8000,您应该会看到 Hello, World!

Python REST APIs with Flask, Connexion, and SQLAlchemy

添加您的第一个 REST API 端点

现在您有一个正在运行的 Web 服务器,您可以添加您的第一个 REST API 端点。为此,您将使用 Connexion,您在上一节中已经安装了它。

Connexion 模块允许 Python 程序使用带有 Swagger 的 OpenAPI 规范。OpenAPI 规范是一种用于 REST API 的 API 描述格式,并提供了许多功能,包括:

  • 验证进出 API 的输入和输出数据
  • 配置 API URL 端点和预期参数

当您将 OpenAPI 与 Swagger 结合使用时,您可以创建一个用户界面 (UI) 来调试 API。所有这些都可以在您创建一个 Flask 应用程序可以访问的配置文件时发生。

创建 API 配置文件

Swagger 配置文件是一个 YAML 或 JSON 文件,其中包含您的 OpenAPI 定义。此文件包含配置服务器以提供输入参数验证、输出响应数据验证和 URL 端点定义所需的所有信息。

创建一个名为 swagger.yml 的文件并开始向其中添加元数据

当您定义 API 时,您必须包含您的 OpenAPI 定义的版本。您为此使用 openapi 关键字。版本字符串很重要,因为 OpenAPI 结构的一些部分可能会随时间变化。

此外,就像每个新的 Python 版本都包含新功能一样,OpenAPI 规范中也可能会添加或弃用关键字。

信息关键字开始 API 信息块的范围

  • Title:Connexion 生成的 UI 框架中包含的标题
  • Description:API 提供或关于什么的描述
  • Version:API 的版本值

接下来,添加 servers 和 url,它们定义了 API 的根路径

通过将 "/api" 作为 url 的值,您将能够访问相对于 https://:8000/api 的所有 API 路径。

您在 paths 块中定义您的 API 端点

paths 块开始 API URL 端点路径的配置

  • /people:API 端点的通用 URL
  • get:此 URL 端点将响应的 HTTP 方法

连同 servers 中的 url 定义,这会创建 GET /api/people URL 端点,您可以通过 https://:8000/api/people 访问它。

get 块开始配置单个 /api/people URL 端点

  • operationId:将响应请求的 Python 函数
  • tags:分配给此端点的标签,允许您在 UI 中对操作进行分组
  • summary:此端点的 UI 显示文本
  • responses:端点响应的状态码

operationId 应该包含一个字符串。Connexion 将使用 "people.read_all" 在您项目的 people 模块中查找名为 read_all() 的 Python 函数。您将在本教程的后面创建相应的 Python 代码。

responses 块定义了可能的状态码的配置。在这里,您定义了一个状态码 "200" 的成功响应,其中包含一些描述文本。

您可以在下面的折叠部分找到 swagger.yml 文件的完整内容

swagger.yml 文件就像您 API 的蓝图。通过您在 swagger.yml 中包含的细节,您可以定义您的 Web 服务器可以预期的数据以及您的服务器应该如何响应请求。但是,到目前为止,您的 Flask 项目对您的 swagger.yml 文件知之甚少。继续阅读以使用 Connexion 将您的 OpenAPI 规范与您的 Flask 应用程序连接起来。

将 Connexion 添加到应用程序

使用 Connexion 将 REST API URL 端点添加到您的 Flask 应用程序有两个步骤

  • 向您的项目添加 API 配置文件。
  • 将您的 Flask 应用程序与配置文件连接。

您之前在上一节中添加了一个名为 swagger.yml 的配置文件。要将 API 配置文件与您的 Flask 应用程序连接,您必须在 app.py 文件中引用 swagger.yml

import connexion 语句将模块添加到程序中。下一步是使用 Connexion 而不是 Flask 创建应用程序实例。在内部,Flask 应用程序仍然被创建,但它现在已添加了额外的功能。

应用程序实例创建的一部分包括第 6 行中的参数 specification_dir。这告诉 Connexion 在哪个目录中查找其配置文件。在这种情况下,它与您运行 app.py 的目录相同。

在第 7 行,您告诉应用程序实例从规范目录中读取 swagger.yml 文件并配置框架以提供 Connexion 功能。

从您的 People 端点返回数据

在 swagger.yml 文件中,您使用 operationId 值 "people.read_all" 配置了 Connexion。因此,当 API 收到 GET /api/people 的 HTTP 请求时,您的 Flask 应用程序会调用 people 模块中的 read_all() 函数。

为了实现这一点,创建一个包含 read_all() 函数的 people.py 文件

在第 5 行,您创建一个名为 get_timestamp() 的辅助函数,它生成当前时间戳的字符串表示。

然后,您在第 8 行定义 People 字典数据结构,这是您将在本教程系列这一部分中处理的数据。

People 字典代替了一个合法的数据库。由于 People 是一个模块变量,它的状态在 REST API 调用之间保持不变。但是,您更改的任何数据都将在您重新启动 Web 应用程序时丢失。这不好,但目前没问题。

然后,您在第 26 行创建 read_all() 函数。当您的服务器收到对 GET /api/people 的 HTTP 请求时,它将运行 read_all()。read_all() 的返回值是一个包含个人信息的字典列表。

运行您的服务器代码并将您的浏览器导航到 https://:8000/api/people 将在屏幕上显示人员列表

Python REST APIs with Flask, Connexion, and SQLAlchemy

探索您的 API 文档

目前,您有一个运行着单个 URL 端点的 REST API。您的 Flask 应用程序知道根据 swagger.yml 中的 API 规范提供什么。此外,Connexion 使用 swagger.yml 为您创建 API 文档。

导航到 localhost:8000/api/ui 以查看您的 API 文档

Python REST APIs with Flask, Connexion, and SQLAlchemy

这显示了预期响应的结构、该响应的内容类型以及您在 swagger.yml 文件中输入的关于该端点的描述文本。每当配置文件更改时,Swagger UI 也会随之更改。

您可以通过点击“试一试”按钮来试用该端点。当您的 API 发展时,此功能非常有用。Swagger UI API 文档为您提供了一种无需编写任何代码即可调试和分析 API 的方法。

将 OpenAPI 与 Swagger UI 结合使用提供了一种良好、干净的方法来创建 API URL 端点。到目前为止,您只创建了一个端点来服务所有人员。在下一节中,您将添加额外的端点来创建、更新和删除您的集合中的人员。

构建完整的 API

到目前为止,您的 Flask REST API 只有一个端点。现在是时候构建一个 API,为您的人员结构提供完整的 CRUD 访问权限。正如您所回顾的,您的 API 定义如下所示

操作 HTTP 动词 URL 路径 描述

读取 GET /api/people 读取用于人员集合。

创建 POST /api/people 创建用于新增人员。

读取 GET /api/people/<lname> 读取用于特定人员。

更新 PUT /api/people/<lname> 更新用于现有人员。

删除 DELETE /api/people/<lname> 删除现有人员。

使用组件

在 swagger.yml 中定义新的 API 路径之前,您将添加一个新的组件块。组件是您的 OpenAPI 规范中的构建块,您可以从规范的其他部分引用它们。

添加一个包含单个人员的模式的组件块

为了避免代码重复,您创建了一个 components 块。目前,您只将 Person 数据模型保存在 schemas 块中

type: 模式的数据类型

required: 必需的属性

- (破折号)在 - lname 之前 表示 required 可以包含属性列表。您定义为 required 的任何属性也必须存在于 properties 中,其中包括以下内容

fname: 一个人的名字

lname: 一个人的姓氏

type 键定义与其父键相关联的值。对于 Person,所有属性都是字符串。您将在本教程的后面将此模式作为字典在您的 Python 代码中表示。

创建新人

通过在 /people 块中为 post 请求添加新块来扩展您的 API 端点

post 的结构与现有 get 结构相似。一个区别是您还向服务器发送 requestBody。毕竟,您需要告诉 Flask 它需要哪些数据来创建新人员。另一个区别是 operationId,您将其设置为 people.create。

在 content 中,您将 application/json 定义为 API 的数据交换格式。

您可以在 API 请求和 API 响应中提供各种媒体类型。如今,API 通常使用 JSON 作为数据交换格式。这对于您作为 Python 开发人员来说是个好消息,因为 JSON 对象看起来像 Python 字典。例如

JSON

此 JSON 对象类似于您之前在 swagger.yml 中定义并使用 $ref 引用在 schema 中的 Person 组件。

您还使用 201 HTTP 状态码,这是一个成功响应,表示新资源的创建。

注意:如果您想了解有关 HTTP 状态码的更多信息,可以查阅 Mozilla 关于 HTTP 响应状态码的文档。

使用 people.create,您告诉您的服务器在 people 模块中查找 create() 函数。打开 people.py 并将 create() 添加到文件中

在第 4 行,您正在导入 Flask 的 abort() 函数。使用 abort() 帮助您在第 20 行发送错误消息。当请求正文不包含姓氏或已存在具有此姓氏的人时,您会引发错误响应。

注意:一个人的姓氏必须是唯一的,因为您将 lname 用作 People 的字典键。这意味着您目前的项目中不能有两个同姓的人。

如果请求正文中的数据有效,您将在第 13 行更新 People,并在第 18 行用新对象和 201 HTTP 代码响应。

处理一个人

到目前为止,您已能够创建新人员并获取所有人员的列表。在本节中,您将更新 swagger.yml 和 people.py 以处理处理单个现有人员的新路径。

打开 swagger.yml 并添加以下代码

与您的 /people 路径一样,您从 /people/{lname} 路径的 get 操作开始。{lname} 子字符串是姓氏的占位符,您需要将其作为 URL 参数传入。因此,例如,URL 路径 api/people/Ruprecht 包含 Ruprecht 作为 lname。

注意:URL 参数区分大小写。这意味着您必须输入像 Ruprecht 这样的姓氏,R 大写。

您也将在其他任务中使用 lname 参数。因此,为它创建一个组件并在需要时引用它是有意义的。

在这里,operationId 指向 people.py 中的 read_one() 函数,因此再次转到该文件并创建缺失的函数

当您的 Flask 应用程序在 People 中找到提供的姓氏时,它将返回此特定人员的数据。否则,服务器将返回 404 HTTP 错误。

要更新现有人员,请使用此代码更新 swagger.yml

通过此 put 操作的定义,您的服务器期望 people.py 中的 update()

update() 函数需要参数 lname 和 person。当存在具有给定姓氏的人时,您将更新 People 中与个人数据对应的匹配值。

要删除数据集中的一个人,您需要使用 delete 操作

将相应的 delete() 函数添加到 person.py

如果要删除数据集中的现有项,则将其从 People 中删除。在所有管理人员的端点都设置好后,现在是时候测试您的 API 了。由于您使用 Connexion 将您的 Flask 项目与 Swagger 连接起来,因此当您重新启动服务器时,您的 API 文档已为您准备就绪。

每当您更新 swagger.yml 和 people.py 文件以完成人员 API 功能时,Swagger UI 框架将相应更新。此 UI 允许您查看您在 swagger.yml 文件中包含的所有文档,并与构成人员接口的 CRUD 功能的所有 URL 端点进行交互。