Litestar vs FastAPI:一場被低估的 Python Web 框架之爭


如果你在 2024 年問一個 Python 開發者「要寫 API 該用什麼框架」,十個有九個會回答 FastAPI。這個答案在多數場景下沒錯——FastAPI 的生態系、文件品質、社群規模都是壓倒性的優勢。

但如果你再問一個問題:「你有看過 Litestar 嗎?」

多數人會搖頭。少數聽過的人可能知道它「以前叫 Starlite」,然後就沒了。這篇文章要做的,就是把 Litestar 攤開來,從原始碼層級告訴你它和 FastAPI 的差異在哪裡,以及為什麼它值得你花時間認真評估。

為什麼現在寫這篇

市面上已經有不少 Litestar vs FastAPI 的比較文章。但絕大多數都停留在「列功能表」的層次——誰有 CSRF middleware、誰有 rate limiting,然後得出一個安全的結論:「FastAPI 適合快速開發,Litestar 適合追求性能」。

這種結論幾乎沒有資訊量。

我花了時間把 Litestar 的原始碼(v3.0.0b0,約 46,000 行 Python)完整讀過一遍,也對照了 FastAPI 的架構。這篇文章會從以下幾個角度切入:

  • 路由引擎的資料結構差異(radix trie vs 線性掃描)
  • 依賴注入的拓撲排序與平行解析
  • 驗證層的根本性架構差異(msgspec vs Pydantic)
  • DTO 系統——Litestar 最被低估的生產力工具
  • Controller 模式——Django 開發者會覺得回家的設計
  • 測試——沒有任何一篇比較文章認真討論過的主題
  • 社群真實聲音——來自 Hacker News 和 Reddit 的討論

歷史脈絡:從 Starlite 到 Litestar

這段歷史對理解兩個框架的設計哲學至關重要。

Litestar 的前身叫 Starlite,最初就是一個「更好的 FastAPI」計畫。創始團隊認為 FastAPI 的某些設計決策——特別是對 Starlette 的深度耦合和 Pydantic 的綁定——限制了框架的天花板。

2023 年,專案更名為 Litestar,不只是換名字,而是宣示要走出 FastAPI 的影子,成為獨立的框架。到了 2026 年的 v3.0.0 beta,你可以看到這個野心的成果:它不再只是「FastAPI 的替代方案」,而是一個有自己完整設計語言的框架。


路由引擎:Radix Trie vs 線性匹配

這是第一個值得深入的技術差異。

FastAPI 的路由:Starlette 的線性掃描

FastAPI 的路由完全委託給 Starlette。Starlette 的 Router 維護一個路由列表,每次請求進來時,從頭到尾逐一比對,直到找到匹配的路由。

# Starlette 內部邏輯(簡化)
for route in self.routes:
    match, child_scope = route.matches(scope)
    if match == Match.FULL:
        return child_scope

這意味著路由查找的時間複雜度是 O(n),其中 n 是註冊的路由數量。對於 10-20 條路由的小專案,這完全不是問題。但當你的 API 成長到 200、500 條路由時,每個請求都要做線性掃描就開始成為可量測的開銷。

Litestar 的路由:Radix Trie(基數字典樹)

Litestar 在 litestar/_asgi/routing_trie/ 實作了完整的 radix trie。讓我們看看它是怎麼運作的:

# litestar/_asgi/routing_trie/types.py
@dataclass
class RouteTrieNode:
    children: dict[str | PathParameterSentinel, RouteTrieNode]
    path_parameters: set[PathParameterDefinition]
    asgi_handlers: dict[str, ASGIHandlerTuple]  # method -> handler
    is_mount: bool
    is_static: bool

路由在啟動時透過 add_route_to_trie() 一次性建構成樹狀結構。請求進來時,traverse_route_map() 將路徑按 / 分割,沿著樹的分支往下走:

# 簡化的遍歷邏輯
def traverse_route_map(path: str, trie: RouteTrieNode):
    current = trie
    for segment in path.split("/"):
        if segment in current.children:
            current = current.children[segment]
        elif PathParameterSentinel in current.children:
            current = current.children[PathParameterSentinel]
            # 提取路徑參數

時間複雜度是 O(k),其中 k 是路徑的段數(通常 2-5),和總路由數完全無關。

這在實務上有差嗎?

對小專案:幾乎沒差。路由查找在整個請求生命週期中佔的比例微乎其微。

對大型 API(數百條路由):有可量測的差異。更重要的是,radix trie 的查找時間是恆定的——不管你的 API 從 50 條路由成長到 500 條,路由查找的延遲不會增加。這對可預測性很重要。

James Bennett 在他的文章中提出了一個精闢的觀點:框架的擴展有兩個維度——scale up(處理更多流量)和 scale out(處理更大的程式碼庫)。Radix trie 同時改善了這兩個維度。


依賴注入:設計哲學的分歧點

這是兩個框架最根本的設計差異之一,也是最常被膚淺比較的主題。

FastAPI:Depends() 行內宣告

from fastapi import Depends

async def get_db():
    db = Database()
    try:
        yield db
    finally:
        await db.close()

@app.get("/users")
async def get_users(db: Database = Depends(get_db)):
    return await db.fetch_users()

FastAPI 的 DI 是行內宣告的——你在函式簽名裡用 Depends() 指定依賴。這很直覺,但有幾個根本性的限制:

  1. 沒有真正的 DI 容器:每個依賴都是獨立解析的,沒有全域的依賴圖概念
  2. 循環引用問題:當你的 Depends(get_db) 散佈在幾十個檔案中,Python 的 import 機制會開始出問題。James Bennett 和多位社群開發者都報告過這個痛點
  3. 解析是順序的:FastAPI 的依賴解析本質上是順序執行的

Litestar:Provide() 階層式宣告

from litestar import Litestar, get, Controller
from litestar.di import Provide

async def get_db() -> AsyncGenerator[Database, None]:
    db = Database()
    try:
        yield db
    finally:
        await db.close()

async def get_cache() -> Cache:
    return Cache()

class UserController(Controller):
    path = "/users"
    dependencies = {"repo": Provide(get_user_repo)}

    @get()
    async def list_users(self, db: Database, repo: UserRepo) -> list[User]:
        return await repo.list(db)

app = Litestar(
    route_handlers=[UserController],
    dependencies={
        "db": Provide(get_db),
        "cache": Provide(get_cache),
    }
)

這裡的核心差異不只是語法,而是設計模型

  1. 階層繼承:依賴可以在 App → Router → Controller → Handler 任何一層宣告,子層自動繼承父層的依賴
  2. 名稱綁定:依賴透過名稱(字典的 key)綁定到參數,不是透過型別或行內標注
  3. 解耦宣告與使用:你在 handler 裡只寫 db: Database,不需要知道它是怎麼來的

平行依賴解析:拓撲排序

這是最值得深入的技術細節。在 litestar/_kwargs/dependencies.py 中,Litestar 實作了一個真正的拓撲排序演算法來建立依賴解析批次:

def create_dependency_batches(dependencies: dict) -> list[set[str]]:
    """將依賴圖排序為可平行解析的批次"""
    # 1. 遞迴建立依賴圖
    # 2. 找出所有沒有子依賴的節點 → 第一批
    # 3. 移除已解析的批次,重複
    # 結果:每個 set 裡的依賴可以同時解析

接著在 KwargsModel 中,每個批次使用 anyio.create_task_group 同時解析:

async with create_task_group() as task_group:
    for dependency in batch:
        task_group.start_soon(resolve_dependency, dependency)

這意味著如果你有三個互不依賴的資料來源(資料庫、快取、外部 API),Litestar 會同時發起這三個請求,而不是一個接一個。

在實際生產環境中,假設每個依賴的 I/O 延遲是 5ms,三個依賴:

  • FastAPI:15ms(順序)
  • Litestar:5ms(平行)

這個差異在高併發場景下會被放大。


驗證層:msgspec vs Pydantic

這是 Litestar 最具爭議性、也最具技術深度的選擇。

FastAPI:Pydantic 是唯一選項

FastAPI 和 Pydantic 是深度耦合的。你的請求驗證、回應序列化、OpenAPI schema 生成全部依賴 Pydantic。這不是可以輕易替換的——它是 FastAPI 的核心假設。

Pydantic v2 確實比 v1 快了很多(底層用 Rust 重寫),但它仍然是一個通用型的資料驗證庫,不是專門為 web 框架的請求/回應週期優化的。

Litestar:msgspec 為核心,Pydantic 為選項

Litestar 做了一個大膽的選擇:用 msgspec 作為核心驗證和序列化引擎。

msgspec 是什麼?它是一個用 C 實作的高性能序列化/驗證庫,支援 JSON、MessagePack、TOML、YAML。在基準測試中:

  • JSON 序列化比 Pydantic v2 快 3-6 倍
  • JSON 反序列化比 Pydantic v2 快 2-4 倍
  • 記憶體使用量更低

但真正有趣的是 Litestar 怎麼用它。在 litestar/_signature/model.py 中:

class SignatureModel:
    """在啟動時動態建立 msgspec.Struct 子類別"""
    
    @classmethod
    def create(cls, fn, ...) -> type[SignatureModel]:
        # 解析函式簽名
        # 為每個參數建立 msgspec 欄位定義
        # 用 defstruct() 動態生成 Struct 子類別
        struct_type = defstruct(
            name=f"SignatureModel_{fn.__name__}",
            fields=fields,
        )
        return struct_type

這段程式碼在應用啟動時就為每個 handler 預先編譯好了驗證邏輯。請求進來時,驗證的開銷趨近於零——因為所有的型別檢查邏輯在啟動階段就已經被編譯成了最佳化的 C 程式碼。

多後端支援:真正的選擇自由

但 Litestar 的野心不止於此。它支援四種驗證後端

後端使用方式適用場景
msgspec預設,零設定追求性能
Pydantic v2PydanticPlugin現有 Pydantic 模型遷移
attrsAttrsSchemaPlugin已有 attrs 程式碼
dataclasses內建支援標準庫優先

你可以在同一個應用中混用不同的驗證後端。你的 domain model 用 dataclasses,API 層用 msgspec,歷史遺留的模組用 Pydantic——Litestar 都能處理。

FastAPI 做不到這一點。如果你的 domain model 不是 Pydantic BaseModel,你必須手動轉換。


DTO 系統:Litestar 最被低估的功能

如果你只記住這篇文章的一個重點,應該是這個。

FastAPI 的痛點:Model 爆炸

用 FastAPI 做 CRUD API 時,你需要為每個實體手動建立多個 Pydantic model:

# FastAPI 的常見模式
class UserBase(BaseModel):
    name: str
    email: str

class UserCreate(UserBase):
    password: str

class UserRead(UserBase):
    id: int
    created_at: datetime

class UserUpdate(BaseModel):
    name: str | None = None
    email: str | None = None

一個實體,四個 model。十個實體,四十個 model。而且它們之間的同步是手動的——當你在 User ORM model 加了一個欄位,你需要記得更新所有相關的 Pydantic model。

Litestar 的 DTO:從 ORM 自動生成

from litestar.dto import DTOConfig, DataclassDTO
from litestar.contrib.sqlalchemy.dto import SQLAlchemyDTO

class UserDTO(SQLAlchemyDTO[User]):
    config = DTOConfig(
        exclude={"password", "internal_notes"},
        rename_strategy="camel",
        max_nested_depth=2,
    )

class UserCreateDTO(SQLAlchemyDTO[User]):
    config = DTOConfig(
        include={"name", "email", "password"},
    )

class UserUpdateDTO(SQLAlchemyDTO[User]):
    config = DTOConfig(
        include={"name", "email"},
        partial=True,  # 所有欄位自動變為 Optional
    )

@post("/users", dto=UserCreateDTO, return_dto=UserDTO)
async def create_user(data: User) -> User:
    # data 已經是驗證過的 User 實例
    # 回傳時自動套用 UserDTO 的過濾和重命名
    return await repo.create(data)

注意幾個關鍵差異:

  1. 單一真相來源:所有 DTO 都從同一個 User model 生成,不需要手動同步
  2. 宣告式設定excludeincludepartialrename_strategy 都是設定,不是程式碼
  3. 輸入/輸出分離dto 控制輸入驗證,return_dto 控制輸出格式
  4. 自動 partialpartial=True 讓所有欄位變成 Optional,不需要手動寫 UserUpdate
  5. Code generation 後端:實驗性的 experimental_codegen_backend=True 用程式碼生成進一步加速

James Bennett 在他的文章中稱 DTO 系統是他最想看到其他框架採用的功能。我完全同意。這是真正的生產力提升,不是語法糖。


Controller 模式:給 Django 開發者的回家之路

FastAPI 的理念是函式優先——每個 handler 是一個獨立的函式,用 APIRouter 分組。這對小專案很好,但當 API 成長時,你會遇到一些問題:

  1. 共享狀態難以管理:同一組 handler 需要共享的依賴、guard、middleware 只能透過重複宣告或全域變數
  2. 組織困難:200 個函式散落在各處,沒有自然的分組機制
  3. 重構成本高:想把一組 handler 從一個 router 移到另一個,需要逐一修改

Litestar 的 Controller 解決了這些問題:

from litestar import Controller, get, post, put, delete
from litestar.di import Provide

class ArticleController(Controller):
    path = "/articles"
    dependencies = {"repo": Provide(get_article_repo)}
    guards = [require_auth]
    tags = ["articles"]

    @get()
    async def list_articles(self, repo: ArticleRepo) -> list[Article]:
        return await repo.list()

    @get("/{article_id:int}")
    async def get_article(self, repo: ArticleRepo, article_id: int) -> Article:
        return await repo.get(article_id)

    @post()
    async def create_article(self, repo: ArticleRepo, data: Article) -> Article:
        return await repo.create(data)

    @put("/{article_id:int}")
    async def update_article(
        self, repo: ArticleRepo, article_id: int, data: Article
    ) -> Article:
        return await repo.update(article_id, data)

    @delete("/{article_id:int}")
    async def delete_article(self, repo: ArticleRepo, article_id: int) -> None:
        await repo.delete(article_id)

Controller 的設計不是 FastAPI 的 APIRouter 加上 class 包裝而已。它是 Litestar 階層配置模型的一部分:

  • dependencies 在 Controller 層宣告,所有 handler 自動繼承
  • guards 套用到整個 Controller
  • tags 自動套用到 OpenAPI 文件
  • dto / return_dto 可以在 Controller 層設定預設值

如果你從 Django 的 ViewSet 或 Flask 的 MethodView 過來,這個模型會讓你覺得回家了。


測試:被所有比較文章忽略的主題

我檢查了市面上 10 篇 Litestar vs FastAPI 的文章,沒有任何一篇認真討論測試。這讓人不解,因為測試體驗是框架選擇中最重要的因素之一。

FastAPI 的測試

FastAPI 使用 Starlette 的 TestClient(基於 httpx):

from fastapi.testclient import TestClient

def test_read_users():
    client = TestClient(app)
    response = client.get("/users")
    assert response.status_code == 200

# 依賴覆寫
def test_with_mock_db():
    def mock_get_db():
        return FakeDB()

    app.dependency_overrides[get_db] = mock_get_db
    client = TestClient(app)
    response = client.get("/users")
    # 記得清理
    app.dependency_overrides.clear()

dependency_overrides 是一個全域字典,這意味著:

  • 它不是 thread-safe 的(平行跑測試要小心)
  • 你需要手動清理
  • 覆寫粒度只有「這個函式 → 那個函式」

Litestar 的測試

Litestar 提供了專門建構的測試工具:

from litestar.testing import create_test_client

def test_list_users():
    with create_test_client(
        route_handlers=[UserController],
        dependencies={"db": Provide(lambda: FakeDB())},
    ) as client:
        response = client.get("/users")
        assert response.status_code == 200

幾個關鍵差異:

  1. create_test_client 接受所有 Litestar 建構參數:你可以在測試中完整設定 app,包括 dependencies、middleware、guards、plugins。不需要 monkey-patch 全域狀態
  2. 內建 WebSocket 測試WebSocketTestSession 不需要額外安裝
  3. Session 資料輔助工具_get_session_data_set_session_data 用於測試 session 相關邏輯
  4. RequestFactory:建立 mock Request 物件做單元測試
  5. Out-of-process 測試subprocess_async_client 用於端對端測試

最大的差異在於測試隔離。FastAPI 的 dependency_overrides 修改全域狀態,Litestar 的 create_test_client 創建完全獨立的 app 實例。這在 pytest-xdist 等平行測試場景下尤為重要。


內建功能矩陣:一張表說清楚

與其像其他文章一樣逐一列舉,不如看看全貌:

功能LitestarFastAPI
CORS內建Via Starlette
CSRF 保護內建需第三方
Rate Limiting內建(支援 Store 後端)需第三方(slowapi 等)
壓縮(gzip/brotli/zstd)內建Via Starlette(僅 gzip)
Session 管理內建(memory/file/Redis/Valkey)Via Starlette(僅 cookie)
Response 快取內建(支援 Store 後端)需第三方
認證框架內建(JWT/Session/自訂)需第三方
WebSocket Pub/Sub內建 Channels(Redis/Postgres/Memory)需自行實作
CLI內建(litestar runlitestar routes需第三方(uvicorn CLI)
Key-Value Store內建抽象層(Memory/File/Redis/Valkey)
MessagePack原生支援需第三方
SSE內建 Response 型別需 sse-starlette
Repository Pattern內建

這張表帶出一個重要的架構哲學差異:

FastAPI 是「小核心 + 生態系」——框架本身只做路由、DI、驗證,其他都交給第三方。好處是靈活,壞處是你需要自己拼裝,而且每個第三方庫的品質、維護狀態、API 風格都不同。

Litestar 是「batteries included」——像 Django 一樣把常用功能內建。好處是統一的 API 風格和保證的相容性,壞處是框架本身更重、學習曲線更陡。


Guards 系統:宣告式授權

這個功能在現有文章中幾乎沒有被討論過,但它是 Litestar 在實際專案中非常實用的設計。

from litestar import ASGIConnection, BaseRouteHandler
from litestar.exceptions import NotAuthorizedException

async def require_admin(
    connection: ASGIConnection, _: BaseRouteHandler
) -> None:
    if not connection.user or not connection.user.is_admin:
        raise NotAuthorizedException()

async def require_verified_email(
    connection: ASGIConnection, _: BaseRouteHandler
) -> None:
    if not connection.user.email_verified:
        raise NotAuthorizedException(detail="Email not verified")

# 在任何層級套用
app = Litestar(
    route_handlers=[...],
    guards=[require_auth],  # 全域:所有路由都需要認證
)

class AdminController(Controller):
    path = "/admin"
    guards = [require_admin]  # Controller 層:所有 admin 路由需要管理員權限

    @get("/settings")
    async def get_settings(self) -> Settings: ...

    @post("/dangerous-action", guards=[require_verified_email])
    async def dangerous(self) -> None:  # handler 層:額外要求 email 驗證
        ...

Guards 可以疊加——handler 層的 guard 不會覆蓋 controller 或 app 層的 guard,而是全部都要通過。這讓授權邏輯可以用組合的方式建構,而不是在每個 handler 裡寫 if-else。

在 FastAPI 中,你通常用 Depends() 實作類似的功能,但它混淆了「取得資料的依賴」和「檢查權限的守衛」這兩個不同的概念。


Channels:WebSocket Pub/Sub 的內建解答

如果你需要做即時通訊、通知推送、或任何 WebSocket 廣播功能,Litestar 的 Channels 系統是一個殺手級功能。

from litestar.channels import ChannelsPlugin
from litestar.channels.backends.redis import RedisChannelsBackend

channels = ChannelsPlugin(
    backend=RedisChannelsBackend(url="redis://localhost"),
    channels=["notifications", "chat"],
)

@post("/notify")
async def send_notification(
    channels: ChannelsPlugin, data: Notification
) -> None:
    await channels.publish(data.dict(), channels=["notifications"])

app = Litestar(
    route_handlers=[send_notification],
    plugins=[channels],
)

Channels 支援多種後端:

  • MemoryChannelsBackend:單進程,適合開發
  • RedisChannelsBackend:Redis Pub/Sub,適合生產
  • AsyncPgChannelsBackend:PostgreSQL LISTEN/NOTIFY
  • PsycopgChannelsBackend:Psycopg3 後端

FastAPI 沒有任何對應的內建功能。你需要自己實作 WebSocket 管理、channel 訂閱、後端整合。


社群觀點:真實的聲音

Hacker News 的冷靜分析

在 HN 的 Litestar 討論串中,一位開發者提出了一個值得注意的觀點:

「Async Python 框架在高請求率下,會把 I/O-bound 的問題變成 CPU-bound 的問題。」

這不是在說 Litestar(或 FastAPI)的 async 不好,而是在提醒:Python 的 async 不是銀彈。GIL(即使在 Python 3.13 有了 free-threaded 模式)仍然是 CPU 密集型操作的瓶頸。當你的 API 在高併發下需要做大量 JSON 序列化/反序列化時,這就變成了 CPU 問題。

這恰好是 Litestar 選擇 msgspec(C 實作)的原因之一——它把序列化的 CPU 開銷降到最低。

社群常見的遷移動機

從各論壇整理的遷移原因:

從 FastAPI 遷移到 Litestar 的原因:

  1. 專案變大後,Depends() 的循環引用問題變得難以管理
  2. 需要 class-based views 來組織程式碼
  3. 想擺脫 Pydantic 的效能開銷(特別是高流量場景)
  4. 需要內建的 rate limiting 和 CSRF 保護
  5. FastAPI 的維護速度受質疑——核心開發者基本只有 Tiangolo 一人

留在 FastAPI 的原因:

  1. 生態系壓倒性優勢——幾乎所有的教程、範例、第三方整合都是 FastAPI
  2. 文件品質極高
  3. 招聘市場上「會 FastAPI」是常見需求,「會 Litestar」幾乎不存在
  4. Litestar 的文件和錯誤訊息仍有改善空間
  5. 不想冒險在小眾框架上——畢竟 FastAPI 背後有大量生產驗證

Litestar 團隊自己也在 HN 討論中承認文件是他們的「痛點」,正在積極改善。


Litestar v3:下一步往哪走

Litestar 3.0.0 目前是 beta 階段,帶來了幾個重要的方向性決策:

  1. 放棄 Python 3.9 和 3.10——最低要求 Python 3.11。這讓框架能用 ExceptionGroupTaskGroup、更好的 typing 等現代 Python 功能
  2. 放棄 Pydantic v1 支援——全面轉向 Pydantic v2(如果你還在用 v1,這是個強訊號)
  3. 全新日誌系統——完整重寫,更符合結構化日誌的最佳實踐
  4. 新的 ASGIMiddleware 基礎類別——用 handle() 方法取代舊的 AbstractMiddleware,支援靜態路徑排除模式
  5. Python 3.14 官方支援

v3 的方向很明確:加碼 msgspec、擁抱現代 Python、簡化遺留相容層。如果你現在要開始一個新專案,選 Litestar 意味著你在押注一個正在往正確方向走的框架。


什麼時候選哪個

讓我給出一個比「FastAPI 適合快速開發」更有用的建議:

選 FastAPI,如果你:

  • 團隊的 Python 經驗參差不齊——FastAPI 的學習曲線確實更平緩,文件也更好
  • 需要大量第三方整合——OAuth providers、AI/ML 框架(LangChain、LlamaIndex 等)幾乎都優先支援 FastAPI
  • 已經有大量 Pydantic models——遷移成本不值得
  • 專案不大(< 50 條路由)——FastAPI 和 Litestar 在這個規模下的差異微乎其微
  • 需要招人——「FastAPI experience」是可搜尋的關鍵字,「Litestar experience」不是

選 Litestar,如果你:

  • 在建構一個會持續成長的 API——Controller、階層式 DI、Guard 這些設計在 200+ 路由的專案中會明顯感受到價值
  • 對性能有硬指標——msgspec + radix trie + 平行依賴解析的組合在高併發場景下有實質的優勢
  • 需要 WebSocket 即時功能——Channels 系統省去大量自建成本
  • 從 Django 過來——Controller 模式、batteries included 的哲學會讓你覺得更熟悉
  • 想要更好的測試體驗——create_test_client 的隔離性設計在大型專案中是真正的生產力提升
  • 願意投資在一個較小的生態系——用更少的第三方依賴,換取更統一的框架體驗

不要選 Litestar,如果你:

  • 只是因為它「更快」——沒有經過你自己業務場景的 benchmark,「3-6x」只是一個數字
  • 覺得 FastAPI 不好——FastAPI 是一個傑出的框架,Litestar 是一個不同的傑出框架
  • 團隊沒有餘裕學新工具——Litestar 的概念(DTO、Guard、Controller、Store)比 FastAPI 多,學習成本是真實的

結語

Python web 框架的格局正在改變。FastAPI 在 2020 年之後幾乎是唯一被認真討論的 async 選擇,但 Litestar 正在證明還有另一種路可以走。

這兩個框架之間的選擇不是「好 vs 壞」,而是設計哲學的分歧

  • FastAPI 選擇了簡約和生態系——核心小而精,讓社群填補其餘部分
  • Litestar 選擇了完備和一致性——把 web 應用需要的功能內建,確保它們能無縫配合

對我來說,Litestar 最讓人印象深刻的不是任何單一功能,而是它在原始碼層級的設計品質。Radix trie 路由、拓撲排序的依賴解析、SignatureModel 的啟動時編譯——這些都不是「夠用就好」的實作,而是經過深思熟慮的工程決策。

如果你正在選框架,花一個下午的時間讀讀 Litestar 的原始碼。不是文件,是原始碼。你可能會對一個「小眾框架」的工程品質感到驚訝。