跳到内容

替代方案、灵感与对比

FastAPI 的灵感来源、它与替代方案的比较以及从中吸取了哪些经验。

简介

如果没有其他人的前期工作,FastAPI 将不复存在。

在其创建之前,已经有许多工具对其产生了启发。

我多年来一直避免创建一个新的框架。起初,我尝试使用许多不同的框架、插件和工具来解决 FastAPI 所涵盖的所有功能。

但到了一定阶段,别无选择,只能创建一个能提供所有这些功能的工具,它吸取了现有工具的最佳创意,并以最佳方式将它们结合起来,利用了以前甚至不可用的语言特性(Python 3.6+ 类型提示)。

现有工具

Django

它是最受欢迎的 Python 框架,广受信任。它被用于构建像 Instagram 这样的系统。

它与关系型数据库(如 MySQL 或 PostgreSQL)耦合度较高,因此,将 NoSQL 数据库(如 Couchbase、MongoDB、Cassandra 等)作为主要存储引擎并非易事。

它最初是为了在后端生成 HTML 而创建的,而不是为了创建供现代前端(如 React、Vue.js 和 Angular)或其他与之通信的系统(如 IoT 设备)使用的 API。

Django REST Framework

Django REST framework 的创建旨在成为一个灵活的工具包,用于在 Django 基础上构建 Web API,以增强其 API 能力。

它被许多公司使用,包括 Mozilla、Red Hat 和 Eventbrite。

它是**自动 API 文档**的首批范例之一,这正是启发“寻找” FastAPI 的最初想法之一。

注意

Django REST Framework 由 Tom Christie 创建。他也是 Starlette 和 Uvicorn 的创建者,而 FastAPI 正是基于它们。

启发了 FastAPI

拥有一个自动的 API 文档 Web 用户界面。

Flask

Flask 是一个“微框架”,它不包含数据库集成以及 Django 中默认提供的许多功能。

这种简单性和灵活性允许将 NoSQL 数据库用作主要数据存储系统。

因为它非常简单,学习起来相对直观,尽管文档在某些方面会变得有些技术化。

它也常用于不需要数据库、用户管理或 Django 中预置的许多其他功能的应用程序。尽管其中许多功能可以通过插件添加。

这种组件解耦以及作为可以扩展以准确覆盖所需功能的“微框架”是我希望保留的一个关键特性。

鉴于 Flask 的简单性,它似乎很适合构建 API。接下来要找到的是一个 Flask 版的“Django REST Framework”。

启发了 FastAPI

成为一个微框架。使其易于混合和匹配所需的工具和组件。

拥有一个简单易用的路由系统。

Requests

FastAPI 实际上并非 Requests 的替代品。它们的应用范围大相径庭。

实际上,在 FastAPI 应用程序内部使用 Requests 是很常见的。

但即便如此,FastAPI 还是从 Requests 中获得了不少灵感。

Requests 是一个用于 API 交互(作为客户端)的库,而 FastAPI 是一个用于构建 API(作为服务器)的库。

它们或多或少处于对立的两端,相互补充。

Requests 具有非常简单直观的设计,易于使用,并带有合理的默认值。但与此同时,它又非常强大且可定制。

这就是为什么,正如官方网站所说

Requests 是有史以来下载量最大的 Python 包之一

它的使用方法非常简单。例如,要执行 GET 请求,你会这样写

response = requests.get("http://example.com/some/url")

FastAPI 对应的 API 路径操作 可能看起来像

@app.get("/some/url")
def read_url():
    return {"message": "Hello World"}

请注意 requests.get(...)@app.get(...) 之间的相似之处。

启发了 FastAPI

  • 拥有简单直观的 API。
  • 直接使用 HTTP 方法名(操作),以一种直接而直观的方式。
  • 拥有合理的默认值,但支持强大的自定义功能。

Swagger / OpenAPI

我希望从 Django REST Framework 中获得的主要功能是自动 API 文档。

后来我发现有一个使用 JSON(或 YAML,JSON 的扩展)来文档化 API 的标准,称为 Swagger。

并且已经有了一个用于 Swagger API 的 Web 用户界面。因此,能够为 API 生成 Swagger 文档将允许自动使用此 Web 用户界面。

在某个时候,Swagger 被移交给 Linux 基金会,并更名为 OpenAPI。

这就是为什么谈论 2.0 版本时常说“Swagger”,而 3+ 版本时说“OpenAPI”的原因。

启发了 FastAPI

采用并使用 API 规范的开放标准,而不是自定义模式。

并集成基于标准的 UI 工具

选择这两款工具是因为它们相当流行且稳定,但快速搜索一下,你会发现几十种用于 OpenAPI 的替代用户界面(你可以与 FastAPI 一起使用)。

Flask REST 框架

有几个 Flask REST 框架,但在投入时间和精力进行调查后,我发现许多已经停止维护或被弃用,并且存在一些使其不适用的问题。

Marshmallow

API 系统所需的主要功能之一是数据“序列化”,它将代码(Python)中的数据转换为可以通过网络发送的格式。例如,将包含数据库数据的对象转换为 JSON 对象。将 datetime 对象转换为字符串等。

API 所需的另一个重要功能是数据验证,确保数据在给定某些参数的情况下是有效的。例如,某个字段是 int 类型,而不是随机字符串。这对于接收到的数据特别有用。

如果没有数据验证系统,你将不得不手动在代码中进行所有检查。

Marshmallow 就是为提供这些功能而构建的。它是一个很棒的库,我之前使用过很多次。

但它是在 Python 类型提示出现之前创建的。因此,要定义每个模式,你需要使用 Marshmallow 提供的特定工具和类。

启发了 FastAPI

使用代码自动定义提供数据类型和验证的“模式”。

Webargs

API 所需的另一个重要功能是解析来自传入请求的数据。

Webargs 是一个工具,旨在为包括 Flask 在内的多个框架提供此功能。

它在底层使用 Marshmallow 进行数据验证。它由同一批开发人员创建。

它是一个很棒的工具,在拥有 FastAPI 之前,我也大量使用过它。

信息

Webargs 由 Marshmallow 的同一批开发人员创建。

启发了 FastAPI

拥有对传入请求数据的自动验证功能。

APISpec

Marshmallow 和 Webargs 以插件形式提供验证、解析和序列化功能。

但文档仍然缺失。于是 APISpec 应运而生。

它是许多框架的插件(也有一个 Starlette 的插件)。

它的工作方式是,你在处理路由的每个函数的文档字符串中,使用 YAML 格式编写模式的定义。

然后它生成 OpenAPI 模式。

这就是它在 Flask、Starlette、Responder 等框架中的工作方式。

但这样一来,我们又遇到了在一个 Python 字符串(一个大 YAML)中包含微语法的问题。

编辑器对此帮助不大。而且,如果我们修改参数或 Marshmallow 模式,却忘记同时修改该 YAML 文档字符串,生成的模式就会过时。

信息

APISpec 由 Marshmallow 的同一批开发人员创建。

启发了 FastAPI

支持 API 的开放标准 OpenAPI。

Flask-apispec

它是一个 Flask 插件,将 Webargs、Marshmallow 和 APISpec 结合在一起。

它利用 Webargs 和 Marshmallow 的信息,使用 APISpec 自动生成 OpenAPI 模式。

它是一个很棒的工具,但被严重低估了。它应该比市面上许多 Flask 插件更受欢迎。这可能归因于其文档过于简洁和抽象。

这解决了在 Python 文档字符串中编写 YAML(另一种语法)的问题。

在构建 FastAPI 之前,Flask、Flask-apispec 与 Marshmallow 和 Webargs 的这种组合是我最喜欢的后端技术栈。

使用它促成了几个 Flask 全栈生成器的创建。这些是我(和几个外部团队)迄今为止一直在使用的主要技术栈

而这些全栈生成器正是 FastAPI 项目生成器 的基础。

信息

Flask-apispec 由 Marshmallow 的同一批开发人员创建。

启发了 FastAPI

从定义序列化和验证的同一代码中,自动生成 OpenAPI 模式。

NestJS(和 Angular

这甚至不是 Python,NestJS 是一个受 Angular 启发的 JavaScript (TypeScript) NodeJS 框架。

它实现了与 Flask-apispec 类似的功能。

它拥有一个集成的依赖注入系统,灵感来源于 Angular 2。它需要预先注册“可注入项”(和我所知的其他所有依赖注入系统一样),因此增加了冗余和代码重复。

由于参数是用 TypeScript 类型(类似于 Python 类型提示)描述的,编辑器支持相当不错。

但由于 TypeScript 数据在编译到 JavaScript 后不保留,因此它不能同时依赖类型来定义验证、序列化和文档。由于这一点和一些设计决策,为了实现验证、序列化和自动模式生成,需要在许多地方添加装饰器。因此,代码会变得相当冗长。

它对嵌套模型的处理不是很好。因此,如果请求中的 JSON 主体是一个包含内部字段的 JSON 对象,而这些内部字段又嵌套了 JSON 对象,则无法正确地进行文档化和验证。

启发了 FastAPI

使用 Python 类型以获得出色的编辑器支持。

拥有强大的依赖注入系统。找到一种方法来最小化代码重复。

Sanic

它是首批基于 asyncio 的极速 Python 框架之一。它的设计与 Flask 非常相似。

技术细节

它使用 uvloop 而不是默认的 Python asyncio 循环。这就是它如此之快的原因。

它显然启发了 Uvicorn 和 Starlette,它们在公开基准测试中目前比 Sanic 更快。

启发了 FastAPI

找到一种方法来实现超高性能。

这就是为什么 FastAPI 基于 Starlette 的原因,因为它是目前最快的可用框架(经第三方基准测试)。

Falcon

Falcon 是另一个高性能 Python 框架,它被设计为极简,并作为 Hug 等其他框架的基础。

它的设计理念是让函数接收两个参数,一个“请求”和一个“响应”。然后你从请求中“读取”部分内容,并向响应中“写入”部分内容。由于这种设计,无法使用标准的 Python 类型提示作为函数参数来声明请求参数和主体。

因此,数据验证、序列化和文档必须在代码中手动完成,而不是自动完成。或者它们必须作为 Falcon 之上的一个框架实现,就像 Hug 那样。这种相同的区别也发生在其他受 Falcon 设计启发,将一个请求对象和一个响应对象作为参数的框架中。

启发了 FastAPI

寻找获得出色性能的方法。

与 Hug(因为 Hug 基于 Falcon)一起,启发了 FastAPI 在函数中声明 response 参数。

尽管在 FastAPI 中它是可选的,并且主要用于设置请求头、Cookie 和替代状态码。

Molten

我在构建 FastAPI 的早期阶段发现了 Molten。它有着非常相似的理念

  • 基于 Python 类型提示。
  • 基于这些类型进行验证和文档生成。
  • 依赖注入系统。

它不使用像 Pydantic 这样的第三方数据验证、序列化和文档库,它有自己的实现。因此,这些数据类型定义不容易被重用。

它需要稍微更冗长的配置。而且由于它基于 WSGI(而不是 ASGI),它没有被设计来利用 Uvicorn、Starlette 和 Sanic 等工具提供的高性能。

依赖注入系统需要预先注册依赖项,并且依赖项是根据声明的类型解析的。因此,不可能声明多个提供特定类型的“组件”。

路由在一个地方声明,使用在其他地方声明的函数(而不是使用可以放在处理端点的函数之上的装饰器)。这更接近 Django 的做法,而不是 Flask(和 Starlette)的做法。它在代码中分离了那些相对紧密耦合的东西。

启发了 FastAPI

使用模型属性的“默认”值定义数据类型的额外验证。这改进了编辑器支持,并且以前在 Pydantic 中是不可用的。

这实际上启发了 Pydantic 部分功能的更新,以支持相同的验证声明风格(所有这些功能现在已在 Pydantic 中可用)。

Hug

Hug 是首批使用 Python 类型提示实现 API 参数类型声明的框架之一。这是一个很棒的想法,启发了其他工具效仿。

它在声明中使用了自定义类型而不是标准的 Python 类型,但这仍然是一个巨大的进步。

它也是首批生成自定义模式以 JSON 格式声明整个 API 的框架之一。

它不是基于 OpenAPI 和 JSON Schema 等标准。因此,将其与其他工具(如 Swagger UI)集成并不直接。但再次强调,这是一个非常创新的想法。

它有一个有趣且不常见的功能:使用同一个框架,可以创建 API,也可以创建 CLI。

因为它基于同步 Python Web 框架的旧标准(WSGI),所以它无法处理 Websockets 和其他东西,尽管它仍然具有高性能。

信息

Hug 由 Timothy Crosley 创建,他也是 isort 的创建者,这是一个用于自动排序 Python 文件中导入语句的优秀工具。

启发 FastAPI 的思想

Hug 启发了 APIStar 的部分内容,并且是与 APIStar 一起,我发现最有前途的工具之一。

Hug 启发了 FastAPI 使用 Python 类型提示来声明参数,并自动生成定义 API 的模式。

Hug 启发了 FastAPI 在函数中声明 response 参数来设置请求头和 Cookie。

APIStar (<= 0.5)

就在决定构建 FastAPI 之前,我发现了 APIStar 服务器。它几乎具备了我所寻找的一切,并且设计非常出色。

它是我见过的(在 NestJS 和 Molten 之前)首批使用 Python 类型提示声明参数和请求的框架实现之一。我大约与 Hug 同时发现了它。但 APIStar 使用了 OpenAPI 标准。

它在多个地方基于相同的类型提示,实现了自动数据验证、数据序列化和 OpenAPI 模式生成。

主体模式定义没有像 Pydantic 那样使用相同的 Python 类型提示,它更类似于 Marshmallow,因此,编辑器支持不会那么好,但即便如此,APIStar 仍然是当时最好的选择。

它在当时拥有最佳的性能基准(仅次于 Starlette)。

最初,它没有自动 API 文档 Web UI,但我知道我可以为其添加 Swagger UI。

它有一个依赖注入系统。它需要预先注册组件,正如上面讨论的其他工具一样。但即便如此,它仍然是一个很棒的功能。

我从未能在完整项目中使用它,因为它没有安全集成功能,所以我无法用基于 Flask-apispec 的全栈生成器替换我已有的所有功能。我曾在我的项目待办事项中计划创建一个拉取请求来添加该功能。

但后来,项目重心发生了转变。

它不再是一个 API Web 框架,因为创建者需要专注于 Starlette。

现在 APIStar 是一套用于验证 OpenAPI 规范的工具,而不是一个 Web 框架。

信息

APIStar 由 Tom Christie 创建。他也是以下项目的创建者:

  • Django REST Framework
  • Starlette(FastAPI 基于此)
  • Uvicorn(由 Starlette 和 FastAPI 使用)

启发了 FastAPI

存在。

使用相同的 Python 类型声明多项内容(数据验证、序列化和文档),同时提供出色的编辑器支持,我认为这是一个绝妙的想法。

在长时间寻找类似的框架并测试了许多不同的替代方案后,APIStar 是当时最好的选择。

随后 APIStar 不再作为服务器存在,Starlette 被创建,并成为此类系统的一个新的更好基础。这是构建 FastAPI 的最终灵感来源。

我将 FastAPI 视为 APIStar 的“精神继承者”,它在所有这些现有工具的经验基础上,改进并增加了功能、类型系统和其他部分。

FastAPI 使用

Pydantic

Pydantic 是一个基于 Python 类型提示,用于定义数据验证、序列化和文档(使用 JSON Schema)的库。

这使得它极其直观。

它与 Marshmallow 相当。尽管在基准测试中它比 Marshmallow 更快。而且由于它基于相同的 Python 类型提示,编辑器支持非常出色。

FastAPI 使用它来

处理所有数据验证、数据序列化和自动模型文档(基于 JSON Schema)。

然后 FastAPI 将这些 JSON Schema 数据放入 OpenAPI 中,此外还执行所有其他操作。

Starlette

Starlette 是一个轻量级的 ASGI 框架/工具包,非常适合构建高性能的异步服务。

它非常简单直观。它被设计为易于扩展,并拥有模块化的组件。

它具有

  • 令人印象深刻的性能。
  • WebSocket 支持。
  • 进程内后台任务。
  • 启动和关闭事件。
  • 基于 HTTPX 构建的测试客户端。
  • CORS、GZip、静态文件、流式响应。
  • 会话和 Cookie 支持。
  • 100% 测试覆盖率。
  • 100% 类型注解代码库。
  • 少量硬依赖。

Starlette 是目前经过测试最快的 Python 框架。仅被 Uvicorn 超越,而 Uvicorn 并非框架,而是一个服务器。

Starlette 提供了所有基本的 Web 微框架功能。

但它不提供自动数据验证、序列化或文档。

这是 FastAPI 在其之上添加的主要功能之一,所有这些都基于 Python 类型提示(使用 Pydantic)。此外,还有依赖注入系统、安全工具、OpenAPI 模式生成等。

技术细节

ASGI 是由 Django 核心团队成员开发的一个新“标准”。尽管他们正在进行这项工作,但它仍不是一个“Python 标准”(PEP)。

尽管如此,它已经被一些工具用作“标准”。这大大提高了互操作性,因为你可以将 Uvicorn 替换为任何其他 ASGI 服务器(如 Daphne 或 Hypercorn),或者添加兼容 ASGI 的工具,如 python-socketio

FastAPI 使用它来

处理所有核心 Web 组件。在此之上添加功能。

FastAPI 类本身直接继承自 Starlette 类。

因此,任何你用 Starlette 能做的事情,都可以直接用 FastAPI 来做,因为它基本上是强化版的 Starlette。

Uvicorn

Uvicorn 是一个基于 uvloop 和 httptools 构建的闪电般快速的 ASGI 服务器。

它不是一个 Web 框架,而是一个服务器。例如,它不提供按路径路由的工具。这是 Starlette(或 FastAPI)这样的框架会在其之上提供的功能。

它是 Starlette 和 FastAPI 推荐的服务器。

FastAPI 推荐它作为

运行 FastAPI 应用程序的主要 Web 服务器。

你也可以使用 --workers 命令行选项来拥有一个异步多进程服务器。

更多详情请查阅部署章节。

基准测试和速度

要理解、比较并查看 Uvicorn、Starlette 和 FastAPI 之间的区别,请查阅基准测试章节。