Facebook將GraphQL作為開源項(xiàng)目發(fā)布已經(jīng)有兩年的時間了。從那時算起,社區(qū)就以指數(shù)級的速度在增長,現(xiàn)在成千上萬的公司在生產(chǎn)環(huán)境中使用GraphQL。在2017年10月舉行的GraphQL峰會上,我非常榮幸地受邀在第二天演講。讀者可以在YouTube上觀看 完整的視頻 ,也可以通過閱讀本文對演講有一個大致的了解(演講的演示文稿可以在SlideShare 站點(diǎn) 下載 ——譯者注)。
首先,我會簡要介紹一下GraphQL的現(xiàn)狀,然后闡述它未來一段時間內(nèi)的演化會給開發(fā)人員帶來哪些好處,尤其會重點(diǎn)介紹全棧GraphQL集成的三個樣例:緩存、性能跟蹤和模式拼接(schema stitching)。
GraphQL的與眾不同之處是什么?
主要有三個因素使得GraphQL在與其他API技術(shù)的對比中脫穎而出:
- GraphQL有一個很好的查詢語言,這是用來描述 數(shù)據(jù)需求(data requirement) 的好辦法,另外它還具有一個定義良好的模式,它暴露了 API的能力(API capability) 。在主流技術(shù)中,GraphQL是唯一一個同時指定了等式兩側(cè)的主流技術(shù),它的所有好處都來源于這兩個概念的相互作用。
- GraphQL能夠幫助我們將API的消費(fèi)者與提供者解耦。在像REST這種基于端點(diǎn)的API中,所返回數(shù)據(jù)的形式是由服務(wù)器決定的。在GraphQL中,數(shù)據(jù)的形式則是由使用它的UI代碼所決定的,這樣的話會更加自然,能夠讓我們聚焦于關(guān)注點(diǎn)分離,而不是技術(shù)。
- GraphQL查詢是與使用它的代碼息息相關(guān)的,所以我們可以將查詢視為一個 數(shù)據(jù)獲取單元 。GraphQL預(yù)先了解UI組件的所有數(shù)據(jù)需求,因此能夠?qū)崿F(xiàn)一些新類型的服務(wù)器功能。比如,在某個查詢的底層API調(diào)用中,使用批處理和緩存,這些調(diào)用代表了UI部分所需的數(shù)據(jù),借助GraphQL來實(shí)現(xiàn)就會變得非常容易。
分離關(guān)注點(diǎn),而不是分離技術(shù):GraphQL將數(shù)據(jù)的需求放到了客戶端
接下來,我們看一下人們經(jīng)常提到的關(guān)于數(shù)據(jù)獲取的三個方面,然后討論GraphQL如何使用上述特性來對其進(jìn)行改善。
需要注意的是我所討論的功能有很大一部分是現(xiàn)在就可用的,還有一部分是將來要實(shí)現(xiàn)的。如果這些功能讓你感到興奮的話,那么可以滾動的頁面底部了解如何參與。
1.跨請求緩存
人們經(jīng)常問到的一個問題就是如何為GraphQL API實(shí)現(xiàn)跨請求的緩存。在將常規(guī)的HTTP緩存應(yīng)用到GraphQL上時,會有一些問題:
- HTTP緩存通常不支持POST請求或較長的cache key;
- 請求的多樣性通常會意味著更低的緩存命中率;
- GraphQL是獨(dú)立于傳輸層的,所以HTTP并不一定總是有效。
但是,GraphQL同時帶來了眾多新的機(jī)會:
- 在訪問后端的模式和解析器(resolver)上聲明緩存控制信息;
- 模式方案所帶來的自動化細(xì)粒度緩存控制,而不需要考慮每個請求的命中率。
在GraphQL中我們該如何更好地使用緩存呢,我們又該如何利用這些新機(jī)會呢?
應(yīng)該將緩存功能放在何處?
我們首先需要決定將緩存功能放到何處。最初的設(shè)想可能會計劃將緩存邏輯放到GraphQL服務(wù)器里面。但是,像DataLoader這樣的簡單工具無法跨GraphQL請求良好地運(yùn)行,另外將緩存功能放到服務(wù)器端的代碼中有可能會導(dǎo)致實(shí)現(xiàn)變得非常復(fù)雜。所以,我們應(yīng)該將其放到其他的地方。
就像REST一樣,在API層的兩側(cè)都進(jìn)行緩存是非常明智的做法:
- 在GraphQL API外邊的基礎(chǔ)設(shè)施層緩存整個響應(yīng);
- 在GraphQL服務(wù)器之下緩存底層對數(shù)據(jù)庫和微服務(wù)訪問所獲取到的結(jié)果。
對于第二項(xiàng),已有的緩存基礎(chǔ)設(shè)施依然可用。對于第一項(xiàng),我們需要在API之外創(chuàng)建一個新的分層,它能夠以感知GraphQL的方式實(shí)現(xiàn)諸如緩存這樣的功能。從本質(zhì)上來講,這種架構(gòu)能夠讓我們將復(fù)雜性放到GraphQL服務(wù)器之外:
將復(fù)雜性轉(zhuǎn)移到客戶端和服務(wù)器之間的一個新的層中
我將這個組件稱為GraphQL網(wǎng)關(guān)。在Apollo團(tuán)隊(duì)中,我們認(rèn)為這種新的網(wǎng)關(guān)層非常重要,每個人都需要將其作為GraphQL架構(gòu)的一部分。
這也是為什么在本年的GraphQL峰會期間,我們 啟動了Apollo Engine ,將其作為第一個GraphQL網(wǎng)關(guān)。
用于緩存控制的GraphQL響應(yīng)擴(kuò)展
正如我在前面的序言中所述,GraphQL的優(yōu)勢之一就是它有一個巨大的工具生態(tài)系統(tǒng),它們都是通過GraphQL的查詢和模式來運(yùn)行的。我認(rèn)為緩存應(yīng)該按照相同的方式運(yùn)行,為此我們引入了 Apollo 緩存控制 ,它使用了GraphQL規(guī)范內(nèi)置的一項(xiàng)名為 擴(kuò)展(extension) 的特性,在響應(yīng)中包含緩存控制信息。
通過我們的 JavaScript參考實(shí)現(xiàn) ,很容易就可以在模式中添加緩存控制信息:
通過apollo-cache-control-js在模式中定義緩存信息
在這里,我們在GraphQL的主要功能之上創(chuàng)建了這個新的緩存控制規(guī)范,對這種實(shí)現(xiàn)方式我感到很興奮。它能夠以細(xì)粒度的方式指定數(shù)據(jù)的信息,并且利用GraphQL的擴(kuò)展機(jī)制將相關(guān)的緩存控制信息發(fā)送給消費(fèi)者。在實(shí)現(xiàn)方式上,它完全是獨(dú)立于語言和傳輸?shù)摹?/p>
我在GraphQL峰會發(fā)表完演講之后, Oleg Ilyenko 發(fā)布了一個 針對Sangria的可運(yùn)行緩存控制功能 ,他在維護(hù)著Scala GraphQL實(shí)現(xiàn)。
通過網(wǎng)關(guān)實(shí)現(xiàn)緩存
現(xiàn)在,我們重新回到GraphQL服務(wù)器中的緩存控制信息,借助網(wǎng)關(guān),我們能夠以一種清晰的方式來實(shí)現(xiàn)緩存功能。棧中的每一部分都能在各自的位置發(fā)揮作用:
緩存會協(xié)調(diào)技術(shù)棧中的每個組成部分
還有另外一件很酷的事情值得一提,大多數(shù)人已經(jīng)在GraphQL技術(shù)棧中使用過緩存了:比如在前端使用Apollo Client和Relay緩存數(shù)據(jù)。在未來版本的Apollo Client中,來自響應(yīng)中的緩存控制信息將會自動過期來自客戶端的舊數(shù)據(jù)。所以,就像GraphQL中的其他組成部分一樣,服務(wù)器描述了它的功能,客戶端指定其數(shù)據(jù)需求,所有組成部分都能很好地協(xié)作。
接下來,我們看一下另外一個跨越整個棧的GraphQL功能樣例。
2.跟蹤
相對于基于端的系統(tǒng),GraphQL能夠讓前端開發(fā)人員以一種更加細(xì)粒度的方式來使用數(shù)據(jù)。他們能夠精確地請求想要的數(shù)據(jù),忽略不會使用的字段。這樣的話,就有機(jī)會探測詳細(xì)的性能信息,并且能夠以過去無法實(shí)現(xiàn)的方式來進(jìn)行性能的跟蹤。
不要滿足于一個不透明的總查詢時間——GraphQL能夠讓我們獲取每個字段詳細(xì)計時
我們可以說GraphQL是第一個能夠細(xì)粒度獲取內(nèi)部信息的API技術(shù)。這并不是某項(xiàng)工具做到的——GraphQL第一次能夠讓前端開發(fā)人員以合法的方式獲取每個字段的執(zhí)行計時,然后讓他們基于此修改查詢以解決相關(guān)的問題。
跨越整個棧進(jìn)行跟蹤
跟蹤與緩存類似,協(xié)調(diào)整個棧才能真正有用。
在提供跟蹤信息時,每個組成部分都有其作用,并且都可以參與進(jìn)來
服務(wù)器可以在結(jié)果中提供額外信息,就像提供緩存相關(guān)的信息類似,網(wǎng)關(guān)可以抽取并聚集這些信息。與緩存類似,在服務(wù)器中不想關(guān)心的復(fù)雜功能,都由網(wǎng)關(guān)組件負(fù)責(zé)處理。
在這里,客戶端的主要角色將查詢與UI組件連接起來。這是非常重要的,我們就可以將API層的性能與其對前端影響關(guān)聯(lián)起來。我們第一次能夠把后端獲取數(shù)據(jù)的性能與它所影響的UI組件在頁面上顯示出來。
GraphQL跟蹤擴(kuò)展
與緩存非常類似,我們可以借助GraphQL的響應(yīng)擴(kuò)展功能,以獨(dú)立于服務(wù)器的方式來實(shí)現(xiàn)。Apollo Tracing規(guī)范目前已經(jīng)有了 Node 、 Ruby 、 Scala 、 Java 和 Elixir 實(shí)現(xiàn),該規(guī)范定義了GraphQL服務(wù)器返回計時數(shù)據(jù)的方式,解析器(resolver)會以一種標(biāo)準(zhǔn)的方式進(jìn)行解析,其他的工具都可以使用解析得到的性能數(shù)據(jù)。
我們假設(shè)所有GraphQL工具都要訪問性能數(shù)據(jù):
抽象共享讓所有工具都能使用像跟蹤數(shù)據(jù)這樣的信息
借助Apollo Tracing,我們能夠在GraphiQL、編輯器或其他任意地方使用性能數(shù)據(jù)。
到目前為止,我們已經(jīng)看過了一個客戶端和一個服務(wù)器之間的交互。最后一個樣例,我們看一下GraphQL能夠如何幫助我們模塊化架構(gòu)。
3.模式拼接
GraphQL最大的好處之一就是能夠在一個地方訪問所有的數(shù)據(jù)。但是,直到最近,這種方式也是有一定成本的:我們需要將整個GraphQL模式實(shí)現(xiàn)為一個代碼庫,這樣的話,才能在一個請求中對所有數(shù)據(jù)進(jìn)行查詢。如果你的架構(gòu)是模塊化的,又想使用統(tǒng)一GraphQL API所帶來的收益,那該怎么處理呢?
模式拼接是一個很簡單的理念:GraphQL能夠很容易地將多個API合并成一個,這樣的話,我們就可以按照獨(dú)立服務(wù)的方式來實(shí)現(xiàn)模式中的各個組成部分。這些服務(wù)可以獨(dú)立進(jìn)行部署,使用不同的語言進(jìn)行編寫,甚至還可以歸屬不同的組織。
如下是一個 樣例 :
將GraphQL峰會票務(wù)系統(tǒng)的數(shù)據(jù)和一個天氣API的數(shù)據(jù)組合到一個查詢之中: https://launchpad.graphql.com/130rr3r49
在上面的截圖中,我們可以看到拼接后的API是如何將針對兩個不同服務(wù)的獨(dú)立查詢聯(lián)合起來的,這種方式對客戶端是完全不可見的。通過這種方式,我們完全可以像搭建樂高積木那樣組合GraphQL模式。
我們目前正在提供一個該功能的實(shí)現(xiàn),讀者現(xiàn)在就可以進(jìn)行嘗試,它作為Apollo graphql-tools庫的一部分,通過 文檔 可以了解更多信息。
在網(wǎng)關(guān)中進(jìn)行拼接
模式拼接也可以在整個棧中很好地運(yùn)行。長期來看,我們認(rèn)為非常適合在新的網(wǎng)關(guān)層進(jìn)行拼接,這樣的話,就能使用任意你想要的技術(shù)來構(gòu)建模式了,比如 Node.js 、 Graphcool 或 Neo4j 。
最終,拼接會與棧中的每個組成部分關(guān)聯(lián)
客戶端也可以加入進(jìn)來。就像可以通過一個查詢加載多個后端的數(shù)據(jù),我們同樣可以在客戶端組合數(shù)據(jù)源。在最近發(fā)布的 Apollo Client 2.0 中新增了狀態(tài)管理功能,該功能允許我們在一個查詢中加載來自客戶端狀態(tài)和任意數(shù)量后端的數(shù)據(jù)。
結(jié)論
通過閱讀本文或觀看演講,我希望讀者能夠意識到GraphQL工具如今已經(jīng)非常強(qiáng)大了,未來有非常大的潛力。我們剛剛所接觸的只是GraphQL抽象和功能的一個皮毛。
最后,我想基于以上的理念分享一個TODO列表:
要集成這些新的特性,還有很多工作需要完成,尤其是開發(fā)工具和編輯器領(lǐng)域
要釋放GraphQL的全部潛力,還有很多的事情要做。在Apollo團(tuán)隊(duì)中,我們正為此竭盡全力,但是沒有任何一個人、團(tuán)隊(duì)或組織能夠完成所有的事情。為了讓未來的藍(lán)圖實(shí)現(xiàn),我們需要協(xié)作工作,將這些解決方案構(gòu)建出來。
不管怎樣,有一件事情是非常清晰的:GraphQL已經(jīng)作為一項(xiàng)變革性的技術(shù)用到了成千上萬的企業(yè)中,但這只是開始!我迫不及待地想知道在未來的兩年、五年和十年內(nèi),我們該如何構(gòu)建應(yīng)用,因?yàn)檫@肯定是非常美妙的!
如何參與
如果你像Apollo一樣相信GraphQL的潛力,那么可以參與到社區(qū)中來。為了讓讀者快速起步,我們創(chuàng)建了一個 幫助頁面 。
感謝徐川對本文的審校。
來自:http://www.infoq.com/cn/articles/the-graphql-stack-how-everything-fits-together
掃碼二維碼 獲取免費(fèi)視頻學(xué)習(xí)資料
- 本文固定鏈接: http://www.wangchenghua.com/post/5886/
- 轉(zhuǎn)載請注明:轉(zhuǎn)載必須在正文中標(biāo)注并保留原文鏈接
- 掃碼: 掃上方二維碼獲取免費(fèi)視頻資料