GraphQL技術棧概覽:如何將所有的功能組合起來

caobiao 6年前發布 | 15K 次閱讀 GraphQL

非死book將GraphQL作為開源項目發布已經有兩年的時間了。從那時算起,社區就以指數級的速度在增長,現在成千上萬的公司在生產環境中使用GraphQL。在2017年10月舉行的GraphQL峰會上,我非常榮幸地受邀在第二天演講。讀者可以在油Tube上觀看 完整的視頻 ,也可以通過閱讀本文對演講有一個大致的了解(演講的演示文稿可以在SlideShare 站點 下載 ——譯者注)。

首先,我會簡要介紹一下GraphQL的現狀,然后闡述它未來一段時間內的演化會給開發人員帶來哪些好處,尤其會重點介紹全棧GraphQL集成的三個樣例:緩存、性能跟蹤和模式拼接(schema stitching)。

GraphQL的與眾不同之處是什么?

主要有三個因素使得GraphQL在與其他API技術的對比中脫穎而出:

  1. GraphQL有一個很好的查詢語言,這是用來描述 數據需求(data requirement) 的好辦法,另外它還具有一個定義良好的模式,它暴露了 API的能力(API capability) 。在主流技術中,GraphQL是唯一一個同時指定了等式兩側的主流技術,它的所有好處都來源于這兩個概念的相互作用。
  2. GraphQL能夠幫助我們將API的消費者與提供者解耦。在像REST這種基于端點的API中,所返回數據的形式是由服務器決定的。在GraphQL中,數據的形式則是由使用它的UI代碼所決定的,這樣的話會更加自然,能夠讓我們聚焦于關注點分離,而不是技術。
  3. GraphQL查詢是與使用它的代碼息息相關的,所以我們可以將查詢視為一個 數據獲取單元 。GraphQL預先了解UI組件的所有數據需求,因此能夠實現一些新類型的服務器功能。比如,在某個查詢的底層API調用中,使用批處理和緩存,這些調用代表了UI部分所需的數據,借助GraphQL來實現就會變得非常容易。

GraphQL技術棧概覽:如何將所有的功能組合起來

分離關注點,而不是分離技術:GraphQL將數據的需求放到了客戶端

接下來,我們看一下人們經常提到的關于數據獲取的三個方面,然后討論GraphQL如何使用上述特性來對其進行改善。

GraphQL技術棧概覽:如何將所有的功能組合起來

需要注意的是我所討論的功能有很大一部分是現在就可用的,還有一部分是將來要實現的。如果這些功能讓你感到興奮的話,那么可以滾動的頁面底部了解如何參與。

1.跨請求緩存

人們經常問到的一個問題就是如何為GraphQL API實現跨請求的緩存。在將常規的HTTP緩存應用到GraphQL上時,會有一些問題:

  • HTTP緩存通常不支持POST請求或較長的cache key;
  • 請求的多樣性通常會意味著更低的緩存命中率;
  • GraphQL是獨立于傳輸層的,所以HTTP并不一定總是有效。

但是,GraphQL同時帶來了眾多新的機會:

  • 在訪問后端的模式和解析器(resolver)上聲明緩存控制信息;
  • 模式方案所帶來的自動化細粒度緩存控制,而不需要考慮每個請求的命中率。

在GraphQL中我們該如何更好地使用緩存呢,我們又該如何利用這些新機會呢?

應該將緩存功能放在何處?

我們首先需要決定將緩存功能放到何處。最初的設想可能會計劃將緩存邏輯放到GraphQL服務器里面。但是,像DataLoader這樣的簡單工具無法跨GraphQL請求良好地運行,另外將緩存功能放到服務器端的代碼中有可能會導致實現變得非常復雜。所以,我們應該將其放到其他的地方。

就像REST一樣,在API層的兩側都進行緩存是非常明智的做法:

  1. 在GraphQL API外邊的基礎設施層緩存整個響應;
  2. 在GraphQL服務器之下緩存底層對數據庫和微服務訪問所獲取到的結果。

對于第二項,已有的緩存基礎設施依然可用。對于第一項,我們需要在API之外創建一個新的分層,它能夠以感知GraphQL的方式實現諸如緩存這樣的功能。從本質上來講,這種架構能夠讓我們將復雜性放到GraphQL服務器之外:

GraphQL技術棧概覽:如何將所有的功能組合起來

將復雜性轉移到客戶端和服務器之間的一個新的層中

我將這個組件稱為GraphQL網關。在Apollo團隊中,我們認為這種新的網關層非常重要,每個人都需要將其作為GraphQL架構的一部分。

這也是為什么在本年的GraphQL峰會期間,我們 啟動了Apollo Engine ,將其作為第一個GraphQL網關。

用于緩存控制的GraphQL響應擴展

正如我在前面的序言中所述,GraphQL的優勢之一就是它有一個巨大的工具生態系統,它們都是通過GraphQL的查詢和模式來運行的。我認為緩存應該按照相同的方式運行,為此我們引入了 Apollo 緩存控制 ,它使用了GraphQL規范內置的一項名為 擴展(extension) 的特性,在響應中包含緩存控制信息。

通過我們的 JavaScript參考實現 ,很容易就可以在模式中添加緩存控制信息:

GraphQL技術棧概覽:如何將所有的功能組合起來

通過apollo-cache-control-js在模式中定義緩存信息

在這里,我們在GraphQL的主要功能之上創建了這個新的緩存控制規范,對這種實現方式我感到很興奮。它能夠以細粒度的方式指定數據的信息,并且利用GraphQL的擴展機制將相關的緩存控制信息發送給消費者。在實現方式上,它完全是獨立于語言和傳輸的。

我在GraphQL峰會發表完演講之后, Oleg Ilyenko 發布了一個 針對Sangria的可運行緩存控制功能 ,他在維護著Scala GraphQL實現。

通過網關實現緩存

現在,我們重新回到GraphQL服務器中的緩存控制信息,借助網關,我們能夠以一種清晰的方式來實現緩存功能。棧中的每一部分都能在各自的位置發揮作用:

GraphQL技術棧概覽:如何將所有的功能組合起來

緩存會協調技術棧中的每個組成部分

還有另外一件很酷的事情值得一提,大多數人已經在GraphQL技術棧中使用過緩存了:比如在前端使用Apollo Client和Relay緩存數據。在未來版本的Apollo Client中,來自響應中的緩存控制信息將會自動過期來自客戶端的舊數據。所以,就像GraphQL中的其他組成部分一樣,服務器描述了它的功能,客戶端指定其數據需求,所有組成部分都能很好地協作。

接下來,我們看一下另外一個跨越整個棧的GraphQL功能樣例。

2.跟蹤

相對于基于端的系統,GraphQL能夠讓前端開發人員以一種更加細粒度的方式來使用數據。他們能夠精確地請求想要的數據,忽略不會使用的字段。這樣的話,就有機會探測詳細的性能信息,并且能夠以過去無法實現的方式來進行性能的跟蹤。

GraphQL技術棧概覽:如何將所有的功能組合起來

不要滿足于一個不透明的總查詢時間——GraphQL能夠讓我們獲取每個字段詳細計時

我們可以說GraphQL是第一個能夠細粒度獲取內部信息的API技術。這并不是某項工具做到的——GraphQL第一次能夠讓前端開發人員以合法的方式獲取每個字段的執行計時,然后讓他們基于此修改查詢以解決相關的問題。

跨越整個棧進行跟蹤

跟蹤與緩存類似,協調整個棧才能真正有用。

GraphQL技術棧概覽:如何將所有的功能組合起來

在提供跟蹤信息時,每個組成部分都有其作用,并且都可以參與進來

服務器可以在結果中提供額外信息,就像提供緩存相關的信息類似,網關可以抽取并聚集這些信息。與緩存類似,在服務器中不想關心的復雜功能,都由網關組件負責處理。

在這里,客戶端的主要角色將查詢與UI組件連接起來。這是非常重要的,我們就可以將API層的性能與其對前端影響關聯起來。我們第一次能夠把后端獲取數據的性能與它所影響的UI組件在頁面上顯示出來。

GraphQL跟蹤擴展

與緩存非常類似,我們可以借助GraphQL的響應擴展功能,以獨立于服務器的方式來實現。Apollo Tracing規范目前已經有了 NodeRubyScalaJavaElixir 實現,該規范定義了GraphQL服務器返回計時數據的方式,解析器(resolver)會以一種標準的方式進行解析,其他的工具都可以使用解析得到的性能數據。

我們假設所有GraphQL工具都要訪問性能數據:

GraphQL技術棧概覽:如何將所有的功能組合起來

抽象共享讓所有工具都能使用像跟蹤數據這樣的信息

借助Apollo Tracing,我們能夠在GraphiQL、編輯器或其他任意地方使用性能數據。

到目前為止,我們已經看過了一個客戶端和一個服務器之間的交互。最后一個樣例,我們看一下GraphQL能夠如何幫助我們模塊化架構。

3.模式拼接

GraphQL最大的好處之一就是能夠在一個地方訪問所有的數據。但是,直到最近,這種方式也是有一定成本的:我們需要將整個GraphQL模式實現為一個代碼庫,這樣的話,才能在一個請求中對所有數據進行查詢。如果你的架構是模塊化的,又想使用統一GraphQL API所帶來的收益,那該怎么處理呢?

模式拼接是一個很簡單的理念:GraphQL能夠很容易地將多個API合并成一個,這樣的話,我們就可以按照獨立服務的方式來實現模式中的各個組成部分。這些服務可以獨立進行部署,使用不同的語言進行編寫,甚至還可以歸屬不同的組織。

如下是一個 樣例

GraphQL技術棧概覽:如何將所有的功能組合起來

將GraphQL峰會票務系統的數據和一個天氣API的數據組合到一個查詢之中: https://launchpad.graphql.com/130rr3r49

在上面的截圖中,我們可以看到拼接后的API是如何將針對兩個不同服務的獨立查詢聯合起來的,這種方式對客戶端是完全不可見的。通過這種方式,我們完全可以像搭建樂高積木那樣組合GraphQL模式。

我們目前正在提供一個該功能的實現,讀者現在就可以進行嘗試,它作為Apollo graphql-tools庫的一部分,通過 文檔 可以了解更多信息。

在網關中進行拼接

模式拼接也可以在整個棧中很好地運行。長期來看,我們認為非常適合在新的網關層進行拼接,這樣的話,就能使用任意你想要的技術來構建模式了,比如 Node.jsGraphcoolNeo4j

GraphQL技術棧概覽:如何將所有的功能組合起來

最終,拼接會與棧中的每個組成部分關聯

客戶端也可以加入進來。就像可以通過一個查詢加載多個后端的數據,我們同樣可以在客戶端組合數據源。在最近發布的 Apollo Client 2.0 中新增了狀態管理功能,該功能允許我們在一個查詢中加載來自客戶端狀態和任意數量后端的數據。

結論

通過閱讀本文或觀看演講,我希望讀者能夠意識到GraphQL工具如今已經非常強大了,未來有非常大的潛力。我們剛剛所接觸的只是GraphQL抽象和功能的一個皮毛。

最后,我想基于以上的理念分享一個TODO列表:

GraphQL技術棧概覽:如何將所有的功能組合起來

要集成這些新的特性,還有很多工作需要完成,尤其是開發工具和編輯器領域

要釋放GraphQL的全部潛力,還有很多的事情要做。在Apollo團隊中,我們正為此竭盡全力,但是沒有任何一個人、團隊或組織能夠完成所有的事情。為了讓未來的藍圖實現,我們需要協作工作,將這些解決方案構建出來。

不管怎樣,有一件事情是非常清晰的:GraphQL已經作為一項變革性的技術用到了成千上萬的企業中,但這只是開始!我迫不及待地想知道在未來的兩年、五年和十年內,我們該如何構建應用,因為這肯定是非常美妙的!

如何參與

如果你像Apollo一樣相信GraphQL的潛力,那么可以參與到社區中來。為了讓讀者快速起步,我們創建了一個 幫助頁面

感謝徐川對本文的審校。

 

來自:http://www.infoq.com/cn/articles/the-graphql-stack-how-everything-fits-together

 

 本文由用戶 caobiao 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!