替代方案、灵感和比较¶
是什么启发了 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 的替代 UI(您可以与 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(另一种语法)的问题。
Flask、Flask-apispec 与 Marshmallow 和 Webargs 的这种组合是我在构建 FastAPI 之前最喜欢的后端堆栈。
使用它导致创建了几个 Flask 全栈生成器。这些是我(以及几个外部团队)迄今为止使用的主要堆栈。
- https://github.com/tiangolo/full-stack
- https://github.com/tiangolo/full-stack-flask-couchbase
- https://github.com/tiangolo/full-stack-flask-couchdb
而这些相同的全栈生成器构成了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 的最早的极 fast 的 Python 框架之一。它的设计与 Flask 非常相似。
技术细节
它使用了uvloop而不是默认的 Python asyncio 循环。这使得它如此 fast。
它明显启发了 Uvicorn 和 Starlette,它们在开放基准测试中目前比 Sanic 更 fast。
启发了FastAPI 去
找到一种获得极速性能的方法。
这就是为什么 FastAPI 基于 Starlette,因为它是目前最 fast 的框架(经第三方基准测试)。
Falcon¶
Falcon 是另一个高性能的 Python 框架,它的设计极简,并作为 Hug 等框架的基础。
它的设计是接收两个参数的函数,一个“request”和一个“response”。然后您从 request 中“读取”部分内容,并向 response 中“写入”部分内容。由于这种设计,无法使用标准的 Python 类型提示作为函数参数来声明请求参数和请求体。
因此,数据验证、序列化和文档必须在代码中完成,而不是自动完成。或者它们必须作为 Falcon 之上的框架来实现,例如 Hug。这种区别也存在于受 Falcon 设计启发(拥有一个 request 对象和一个 response 对象作为参数)的其他框架中。
启发了FastAPI 去
寻找方法以获得出色的性能。
与 Hug 一起(因为 Hug 基于 Falcon),它启发了 FastAPI 在函数中声明一个 response 参数。
尽管在 FastAPI 中它是可选的,并且主要用于设置标头、cookie 和替代状态码。
Molten¶
在构建 FastAPI 的早期阶段,我发现了 Molten。它有许多相似的想法。
- 基于 Python 类型提示。
- 基于这些类型的验证和文档。
- 依赖注入系统。
它不使用像 Pydantic 这样的第三方数据验证、序列化和文档库,它有自己的库。因此,这些数据类型定义不容易重用。
它需要更多的配置。并且由于它基于 WSGI(而不是 ASGI),它 ikke 针对利用 Uvicorn、Starlette 和 Sanic 等工具提供的极高性能而设计。
依赖注入系统需要预先注册依赖项,并且依赖项是根据声明的类型解决的。因此,不可能声明提供某种类型的多个“组件”。
路由在单个位置声明,使用在其他位置声明的函数(而不是使用可以放在处理端点的函数顶部的装饰器)。这比 Flask(和 Starlette)的实现方式更接近 Django 的方式。它在代码中分离了相对紧密耦合的东西。
启发了FastAPI 去
使用模型属性的“默认”值定义数据类型的额外验证。这提高了编辑器支持,并且以前在 Pydantic 中不可用。
这实际上启发了更新 Pydantic 的部分内容,以支持相同的验证声明样式(现在所有这些功能在 Pydantic 中都已可用)。
Hug¶
Hug 是最早实现使用 Python 类型提示声明 API 参数类型的框架之一。这是一个很棒的想法,启发了其他工具也这样做。
它在声明中使用了自定义类型而不是标准 Python 类型,但仍然是一大进步。
它也是最早生成自定义模式来声明整个 API(以 JSON 格式)的框架之一。
它 ikke 基于 OpenAPI 和 JSON Schema 等标准。因此,与 Swagger UI 等其他工具集成并不直接。但同样,这是一个非常有创意的想法。
它有一个有趣且不常见的特性:使用相同的框架,可以创建 API 和 CLI。
由于它基于同步 Python Web 框架的先前标准(WSGI),因此它无法处理 Websocket 和其他内容,尽管它仍然具有很高的性能。
信息
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 模式生成。
主体模式定义 ikke 使用与 Pydantic 相同的 Python 类型提示,它更类似于 Marshmallow,因此编辑器支持 ikke 那么好,但 APIStar 仍然是可用的最佳选项。
它拥有当时最佳的性能基准(仅次于 Starlette)。
起初,它没有自动 API 文档 Web UI,但我知道我可以添加 Swagger UI 到其中。
它有一个依赖注入系统。它需要预先注册组件,如上面讨论的其他工具。但它仍然是一项很棒的功能。
我从未能在完整的项目中实际使用它,因为它没有安全集成,所以我无法替换基于 Flask-apispec 的全栈生成器所提供的所有功能。我有一个待办项目,要创建一个 pull request 来添加该功能。
但后来,项目的重点转移了。
它不再是一个 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、静态文件、流式响应。
- Session 和 Cookie 支持。
- 100% 测试覆盖率。
- 100% 类型注解的代码库。
- 少数硬性依赖。
Starlette 目前是测试过的最 fast 的 Python 框架。仅次于 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 是一个闪电般 fast 的 ASGI 服务器,基于 uvloop 和 httptools 构建。
它不是一个 Web 框架,而是一个服务器。例如,它不提供按路径路由的工具。这是一个像 Starlette(或 FastAPI)这样的框架会在其基础上提供的功能。
它是 Starlette 和 FastAPI 推荐的服务器。
基准测试和速度¶
要理解、比较和查看 Uvicorn、Starlette 和 FastAPI 之间的区别,请参阅基准测试部分。