跳到内容

替代品、灵感和比较

是什么启发了 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.0 以上版本则说“OpenAPI”。

启发 FastAPI 去:

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

并集成基于标准的用户界面工具:

之所以选择这两个,是因为它们相当流行和稳定,但快速搜索一下,你可以找到几十个 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 的插件)。

它的工作方式是,你在处理路由的每个函数的文档字符串(docstring)中,使用 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 服务器。它几乎拥有我想要的一切,并且设计得很好。

它是我见过的最早使用 Python 类型提示来声明参数和请求的框架实现之一(在 NestJS 和 Molten 之前)。我几乎是和 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 框架/工具包,是构建高性能 asyncio 服务的理想选择。

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

它拥有:

  • 令人印象深刻的性能。
  • 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 是一个快如闪电的 ASGI 服务器,构建在 uvloop 和 httptools 之上。

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

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

FastAPI 推荐它作为:

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

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

部署部分查看更多细节。

基准测试和速度

要理解、比较并查看 Uvicorn、Starlette 和 FastAPI 之间的区别,请查看关于基准测试的部分。