Categories
程式開發

Airbnb 遷移到 GraphQL


Airbnb 已經成功地將其大部分 API 遷移到了 GraphQL,從而縮短了頁面加載時間並提供了更直觀的用戶體驗。在 GraphQL Summit 上的演講中,Brie Bunge 描述了 Airbnb 多個團隊都有使用過的多階段遷移過程。

在每個階段完成之後,Airbnb 最終推出了一款基於Apollo 和GraphQL 應用程序,該應用程序是100% 類型安全的,沒有過度抓取的問題,並且在整個遷移過程的每個階段,都能保持著網站的正常運行。因為採用了 Apollo 和 GraphQL 來奠定基礎,使 Airbnb 可以嘗試新的性能改進,而傳統的基於 REST 的架構則無法實現。

在遷移過程開始之前,必須滿足兩個先決條件。首先,必須在後端設置 GraphQL。 Adam Neary 曾寫過關於 Airbnb 是如何與 GraphQL 合作的文章

第二個先決條件是在前端採用 TypeScript。在 Airbnb 中,TypeScript 和類型安全促進了更快的開發,並且團隊對他們自己所構建的東西更有信心。 TypeScript 類型可以直接從 schema 中生成(使用 apollo client:codegen –target=typescript),這些類型在後端和前端之間創建一個單一數據源(single source-of-truth,SSOT)。

TypeScript 現在是 Airbnb 前端開發的官方語言,在他們 300 萬行的代碼庫中,有一半已經遷移到了 TypeScript。 Bunge 之前曾在 JSConf 上發表過關於 Airbnb 採用 TypeScript 的演講

Bunge說,轉換為 GraphQL 有三個主要選項可選。首先,也是最誘人的,是完全從零開始重寫。雖然在某些情況下,這作為其他重大項目的一部分經常發生,但這通常不是一個可行的選項。第二個選項是停機並重構,這在小型或單獨的團隊中可以很好地運行,但在有許多開發人員一起工作的情況下就很困難了。

Airbnb 推薦的遷移選項是漸進式採用,這是最安全且最可行的方法,特別是在擁有大型團隊和龐大的已有代碼庫的情況下。 Bunge 所描述的遷移過程包括五個階段,每個階段的目標是發布一個可交付的、功能齊全的、無回歸的應用程序版本。

第一階段是改變數據的來源,而不是數據的使用方式。使用 GraphQL 後端和 TypeScript 後, REST請求就可以與 GraphQL 請求交換。第一個階段的目標是驗證前端到後端的集成是否能正常工作以及 TypeScript 類型生成是否能正常工作。無需變更 React 組件或 API 響應的模型。這需要與 REST 端點匹配的 GraphQL 查詢和變異。

Airbnb 早期依賴的兩個 GraphQL 特性是別名和適配器。別名實現了 GraphQL 返回的駝峰式屬性和舊 REST 端點的蛇形屬性之間的映射。適配器用於轉換 GraphQL 響應,這樣就可以遞歸地將它與 REST 響應區分開來,並確保 GraphQL 返回與之前相同的數據。這些適配器在後面會被刪除,但是它們對於實現第一階段的對等目標是至關重要的。

第二階段的重點是整個代碼中的傳播類型,這將增加後面階段的可信度。此時,不應影響任何運行時行為。

第三階段是改進 Apollo 的使用。早期階段直接使用了Apollo Client,通過Apollo Client觸發Redux 操作,使組件能夠使用了 Redux 存儲。使用 React Hooks(@apollo/react-hooks)重構應用程序可以使用 Apollo 緩存代替 Redux 存儲。

GraphQL 的一個主要優點是減少過度抓取。使用大型查詢的第一個階段保留了舊 REST 端點的所有過度抓取行為,但是第四個階段可以通過引入更細粒度的查詢片段來解決這個問題。

首先,只有應用程序的根組件才能感知到 GraphQL ,並且它必須獲取樹中任何組件可能需要的所有數據。改進過程從組件樹的最低葉節點開始,方法是僅為該子組件所需的數據創建一個GraphQL 查詢。 TypeScript 很有用,因為如果所需的字段不存在,它將拋出編譯器警告。然後修改父組件以根據其子組件的片段來獲取數據。一個“清洗並重複”的過程會遍歷所有的葉子節點,然後沿樹向上到達應用程序的根組件,在那裡舊的大型查詢已經被所有組合的片段所替換。因為所有片段都隻請求它們所需要的數據,所以消除了過度抓取。

第五階段,也是最後一個階段,是階段管理。一旦將所有組件都遷移到 Apollo,Airbnb 就可以利用 Apollo 來獲取 API 數據、React 本地狀態或客戶端上下文數據。這為處理客戶端數據提供了一個一致的心智模型,並對組合了 React 、Apollo 和 Redux 元素的碎片模型進行了改進。它還消除了 Redux 所需的大量樣板代碼,並且它處理緩存的方式比手動滾動的解決方案更有效。

有了 GraphQL,Airbnb 現在可以嘗試新的技術。 Bunge 描述的第一種情況是 service worker 查詢預取,它是為了儘早啟動 GraphQL 查詢,以便用戶能更快地看到使用數據呈現的頁面。

如果沒有 service worker,頁面在服務端渲染完畢後,用戶還需要等待較長時間間隔才能最終看見最終完整的頁面。 service worker 允許應用程序外殼立即出現,並提供一個加載階段,在該加載階段中,頁面將從返回數據時開始填充。由於緩存了許多的 JavaScript,頁面加載速度也更快。然後,service worker 可以通過從組件級查詢切換到路由級查詢來實現進一步的改進。基於設備的限制,在頁面完全交互之前,這可能還會導致總時間另外再減少23-50%。

以數據為中心的統一模式是目前正在進行的另一個項目。現有的模式與 Airbnb 面向服務的架構保持一致。由於服務可以通過不同的方式來組合相同的底層數據,因此數據通常是重複的。通過切換到以數據為中心的模式,並在架構中添加數據水化層,可以避免重複的數據請求、刪除重複的代碼、提高響應效率、並改進緩存。這項工作目前正處於測試階段,但看起來很有希望,更多的信息將會在明年宣布。

原文鏈接:

Migrating to GraphQL at Airbnb