替代方案、啟發和比較¶
啟發 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 文件網頁使用者介面。
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+ 版則稱為「OpenAPI」。
「啟發 FastAPI 去」
採用並使用開放的 API 規範標準,而不是自訂的 schema。
並整合基於標準的使用者介面工具
選擇這兩個是因為它們相當流行且穩定,但只要快速搜尋一下,您就可以找到數十種 OpenAPI 的替代使用者介面(您可以與 FastAPI 一起使用)。
Flask REST 框架¶
有幾個 Flask REST 框架,但在投入時間和精力研究它們之後,我發現許多框架都已停止維護或被放棄,並且存在許多使其不適用的問題。
Marshmallow¶
API 系統所需的主要功能之一是資料「序列化」,即從程式碼(Python)中提取資料並將其轉換為可以透過網路傳送的內容。例如,將包含資料庫資料的物件轉換為 JSON 物件。將 datetime
物件轉換為字串等等。
API 需要的另一個重要功能是資料驗證,確保資料在給定某些參數的情況下是有效的。例如,某個欄位是 int
,而不是隨機字串。這對於傳入資料尤其有用。
如果沒有資料驗證系統,您就必須手動在程式碼中進行所有檢查。
Marshmallow 就是為了提供這些功能而建構的。它是一個很棒的函式庫,我以前經常使用它。
但它是在 Python 类型提示出現之前創建的。因此,要定義每個schema(模式),您需要使用 Marshmallow 提供的特定工具和類別。
「啟發 FastAPI 去」
使用程式碼自動定義提供資料類型和驗證的「模式」。
Webargs¶
API 需要的另一個重要功能是從傳入請求中解析資料。
Webargs 是一個在幾個框架(包括 Flask)之上提供此功能的工具。
它在底層使用 Marshmallow 進行資料驗證。它是由相同的開發者創建的。
這是一個很棒的工具,在使用FastAPI之前,我也經常使用它。
資訊
Webargs 是由與 Marshmallow 相同的開發者創建的。
「啟發 FastAPI 去」
自動驗證傳入的請求資料。
APISpec¶
Marshmallow 和 Webargs 以插件形式提供驗證、解析和序列化功能。
但仍然缺少文件。於是就有了 APISpec。
它是許多框架的插件(Starlette 也有一個插件)。
它的工作方式是,您在每個處理路由的函數的 docstring 中使用 YAML 格式編寫 schema 的定義。
然後它會生成 OpenAPI 模式。
這就是它在 Flask、Starlette、Responder 等框架中的工作方式。
但這樣一來,我們又遇到了在 Python 字串(一個很大的 YAML)中使用微語法帶來的問題。
編輯器對此幫助不大。如果我們修改了參數或 Marshmallow 模式,卻忘記同時修改 YAML docstring,生成的模式就會過時。
資訊
APISpec 是由與 Marshmallow 相同的開發者創建的。
「啟發 FastAPI 去」
支援 API 的開放標準 OpenAPI。
Flask-apispec¶
它是一個 Flask 插件,將 Webargs、Marshmallow 和 APISpec 聯繫在一起。
它使用來自 Webargs 和 Marshmallow 的資訊,使用 APISpec 自動生成 OpenAPI 模式。
這是一個很棒的工具,卻被低估了。它應該比許多 Flask 插件更受歡迎。這可能是因為它的文件過於簡潔和抽象。
這解決了在 Python docstring 中編寫 YAML(另一種語法)的問題。
在構建FastAPI之前,Flask、Flask-apispec、Marshmallow 和 Webargs 的組合是我最喜歡的後端堆疊。
使用它促成了幾個 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 後不會保留,它無法依賴類型同時定義驗證、序列化和文件。由於這個原因以及一些設計決策,為了獲得驗證、序列化和自動 schema 生成,需要在許多地方添加裝飾器。因此,它變得相當冗長。
它不能很好地處理巢狀模型。因此,如果請求中的 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 產生自定義 schema 來宣告整個 API 的框架之一。
它並非基於 OpenAPI 和 JSON Schema 等標準。因此,將其與其他工具(如 Swagger UI)整合並不容易。但同樣地,這是一個非常創新的想法。
它有一個有趣且不常見的功能:使用相同的框架,可以建立 API 和 CLI。
由於它基於先前的同步 Python 網頁框架標準 (WSGI),它無法處理 Websockets 和其他東西,儘管它的效能仍然很高。
資訊
Hug 的創作者是 Timothy Crosley,他也是 isort
的創作者,這是一個在 Python 檔案中自動排序 import 的好工具。
「啟發 FastAPI 的想法」
Hug 啟發了 APIStar 的部分內容,並且是我認為與 APIStar 並列最有前途的工具之一。
Hug 啟發了 FastAPI 使用 Python 類型提示來宣告參數,並自動產生定義 API 的 schema。
Hug 啟發了 FastAPI 在函式中宣告 response
參數來設定標頭和 cookie。
APIStar (<= 0.5)¶
就在我決定建構 FastAPI 之前,我找到了 APIStar 伺服器。它幾乎具備了我想要的一切,並且設計很棒。
這是我見過最早使用 Python 類型提示來宣告參數和請求的框架實現之一(在 NestJS 和 Molten 之前)。我大約與 Hug 同時發現它。但 APIStar 使用了 OpenAPI 標準。
它具有基於多個位置的相同類型提示的自動資料驗證、資料序列化和 OpenAPI schema 產生功能。
Body schema 定義不像 Pydantic 那樣使用相同的 Python 類型提示,它更類似於 Marshmallow,因此,編輯器支援不會那麼好,但 APIStar 仍然是當時最好的選擇。
它在當時擁有最佳的效能基準測試結果(僅次於 Starlette)。
一開始,它沒有自動的 API 文件網頁 UI,但我知道我可以將 Swagger UI 新增到其中。
它有一個依賴注入系統。它需要預先註冊組件,就像上面討論的其他工具一樣。但這仍然是一個很棒的功能。
我從未在完整的專案中使用它,因為它沒有安全性整合,因此,我無法替換我使用基於 Flask-apispec 的全棧產生器所擁有的所有功能。在我的專案待辦事項中,我曾打算建立一個 pull request 來新增該功能。
但後來,專案的重點轉移了。
它不再是一個 API 網頁框架,因為創作者需要專注於 Starlette。
現在 APIStar 是一組用於驗證 OpenAPI 規範的工具,而不是一個網頁框架。
資訊
APIStar 的創作者是 Tom Christie。他也是以下項目的創作者:
- Django REST Framework
- Starlette(FastAPI 基於此)
- Uvicorn(Starlette 和 FastAPI 使用)
「啟發 FastAPI 去」
以及 Exist。
使用相同的 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 是目前測試中最快的 Python 框架。只有 Uvicorn 比它更快,但 Uvicorn 不是框架,而是一個伺服器。
Starlette 提供了所有基本的 Web 微框架功能。
但它不提供自動數據驗證、序列化或文檔。
這是 FastAPI 在其基礎上添加的主要功能之一,所有這些都基於 Python 類型提示(使用 Pydantic)。此外,還包括依賴注入系統、安全工具、OpenAPI schema 生成等。
「技術細節」
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 之間的差異,請查看「基準測試」一節。