替代方案、灵感与比较¶
是什么启发了 FastAPI,它与替代方案的比较,以及从中学到了什么。
简介¶
如果没有前人的工作,FastAPI 就不会存在。
在 FastAPI 之前,已经有很多工具帮助启发了它的创建。
多年来,我一直避免创建一个新的框架。首先,我尝试使用许多不同的框架、插件和工具来解决 FastAPI 所涵盖的所有功能。
但在某个时刻,除了创建一个提供所有这些功能的框架之外,别无选择,从之前的工具中汲取最佳想法,并以最佳方式将它们结合起来,利用以前不可用的语言特性(Python 3.6+ 类型提示)。
之前的工具¶
Django¶
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 的搜索的第一个想法。
Note
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 创建的网页用户界面。因此,能够为 API 生成 Swagger 文档将允许自动使用这个网页用户界面。
在某个时候,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 之前我也使用过很多次。
Info
Webargs 是由相同的 Marshmallow 开发者创建的。
"启发了 FastAPI 去"
自动验证传入请求数据。
APISpec¶
Marshmallow 和 Webargs 提供了验证、解析和序列化作为插件。
但文档仍然缺失。然后 APISpec 被创建了。
它是一个适用于许多框架的插件(也有一个适用于 Starlette 的插件)。
它的工作方式是,你使用 YAML 格式在处理路由的每个函数的 docstring 中编写模式的定义。
并且它生成 OpenAPI 模式。
这就是它在 Flask、Starlette、Responder 等中的工作方式。
但随后,我们再次面临在 Python 字符串(一个大的 YAML)中使用微语法的问题。
编辑器对此帮助不大。如果我们修改参数或 Marshmallow 模式,但忘记也修改那个 YAML docstring,生成的模式将会过时。
Info
APISpec 是由相同的 Marshmallow 开发者创建的。
"启发了 FastAPI 去"
支持 API 的开放标准,OpenAPI。
Flask-apispec¶
它是一个 Flask 插件,将 Webargs、Marshmallow 和 APISpec 结合在一起。
它使用 Webargs 和 Marshmallow 的信息,使用 APISpec 自动生成 OpenAPI 模式。
这是一个很棒的工具,非常被低估。它应该比许多 Flask 插件更受欢迎。可能是因为它的文档过于简洁和抽象。
这解决了在 Python docstrings 中编写 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 项目生成器 的基础。
Info
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 这样的第三方数据验证、序列化和文档库,而是有自己的实现。因此,这些数据类型定义不会像使用 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和其他内容,尽管它仍然具有高性能。
Info
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框架。
Info
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 是一个基于 uvloop 和 httptools 构建的闪电般快速的 ASGI 服务器。
它不是一个 Web 框架,而是一个服务器。例如,它不提供路径路由工具。这是像 Starlette(或 FastAPI)这样的框架会提供的功能。
它是 Starlette 和 FastAPI 推荐的默认服务器。
基准测试和速度¶
要了解、比较和查看 Uvicorn、Starlette 和 FastAPI 之间的差异,请查看 基准测试 部分。