天天看點

何為GraphQL?

概要

何為GraphQL?

GraphQL是一種新型的,令人興奮的,用于特定查詢和操作的API。它非常靈活并且有很多好處。 它特别适合以圖形和樹型為組織的資料。Facebook在2012年研發出了GraphQL并在2015年将其開源。

它快速地成長成為最熱門的技術之一。許多創新公司在生産環境中使用GraphQL。在此篇教程中你将學到:

GraphQL的原理

它如何與REST進行比較

如何設計資料模式

如何配置一個GraphQL伺服器

如何實作查詢和變動

和一些額外的進階主題

何為GraphQL?

GraphQL的亮點在哪裡?

當你的資料按層次結構或圖形組織時,并且前端想要通路這個層次結構或圖形的不同子集時,GraphQL最能發揮作用。 考慮一個提供NBA資訊的應用程式。你有球隊,球員,教練,冠軍,和許多與此相關的資訊。這裡是一些查詢的樣本:

目前金州勇士隊名單上的球員名字是什麼?

華盛頓奇才首發隊員的名字,身高和年齡是什麼?

哪個在任的教練擁有最多的總冠軍?

哪支球隊在哪一年在此教練的執教下赢得了冠軍?

哪個球員赢得了最有價值隊員獎?

我可以給出幾百個與此類似的查詢。想象一下你不得不設計一個API對前端提供所有這些查詢,并且還能夠在你的使用者和産品經理有新查詢需求的時候友善地針對新查詢類型擴充此API。

這并不容易。GraphQL旨在解決這個實際的問題,它隻用一個API終點就能提供無比強大的能量,很快你将會看到。

何為GraphQL?

GraphQL與REST

在深入讨論GraphQL的細節之前,讓我們将其與REST進行比較,誰是目前最流行的web API。

REST遵循一個以資源為導向的模型。如果我們的資源是隊員,教練和球隊,那麼可能會有像下面這樣的API終點:

/players

/players/<id>

/coaches

/coaches/<id>

/teams

/teams/<id>

通常不帶id的API終點隻傳回一組id,帶id的API終點傳回一個資源的完整資訊。你當然也能以其它方式設計你的API(比如/player API終點也可以傳回每個隊員的名字或者每個隊員的所有資訊)。

此方法在一個動态環境中的問題在于你無法擷取充足的資訊(比如你隻擷取了一組id但你需要更多的資訊)或者得到太多的資訊(比如當你隻需要隊員名字時你确收到隊員所有的資訊)。

這些都是很難解決的問題。當無法擷取足夠資訊時,如果你拿到100個id,你将需要去執行100個獨立的API調用去擷取每個隊員的資訊。 當擷取過多的資訊時,你浪費了許多背景的處理時間和用來準備和傳輸很多不需要的資料的網絡帶寬。

REST有對此的解決方案。你可以設計許多定制的API終點,這些終點提供那些你正好需要的資料。但此方案沒有什麼擴充性。 很難去保持定制API終點的一緻性。很難去繼續開發定制API終點。很難去寫定制API終點的文檔并使用它。很難去維護定制API終點當它們的功能之間有很多的重疊。

考慮一下這些額外的終點:

/players/names

/players/names_and_championships

/team/starters

另一個方法是保持一小部分數量的通用API終點,但提供豐富的查詢參數。這個方法避免了許多API終點的問題,但它違背了REST模型的理念。

你可以說GraphQL已将此方法用到了極緻。它不是根據明确定義的資源來思考,而是根據整個資源領域的子圖來進行思考。

何為GraphQL?

GraphQL類型系統

GraphQL使用一種由類型和屬性組成的類型系統給領域模組化。每一個屬性都有一個類型。屬性類型可以是由GraphQL提供的基礎類型的一種,像ID,字元串,布爾函數或使用者自定義類型。 GraphQL圖的節點是使用者自定義的類型,連接配接節點的線是使用者自定義類型的屬性。

例如,如果一個“Player(球員)”類型有一個帶“Team(球隊)”類型的“team(球隊)”屬性,那麼它意味着在每一個球員節點和一個球隊節點之間有一條連接配接線。所有類型都在描述GraphQL領域對象模型的模式中定義。

這是NBA領域的一個非常簡化的模式。 球員有一個名字,一個與他最相關的球隊(是的,我知道球員有時會從一個球隊轉會到另一個球隊),以及球員赢得的總冠軍數量。

球隊有一個名字,一隊球員,以及球隊赢得的冠軍數量。

還有預先定義好的進入點。 這些是Query(查詢),Mutation(變動)和Subscription(訂閱)。 前端通過入口點與後端進行通信,并根據需要進行定制。

這是一個簡單地傳回所有玩家的查詢:

感歎号表示該值不能為空值(null)。 在allPlayers查詢的情況下,它可以傳回一個空清單,但不能為空值。 此外,這意味着清單中的球員也不能為空值(因為它也有一個感歎号)。

何為GraphQL?

設定GraphQL伺服器

何為GraphQL?

這是一個基于node-express的全功能GraphQL伺服器。 它有一個在記憶體裡寫死的資料庫。 通常,資料将存儲在資料庫中或從其它服務中擷取。 資料在這裡定義(如果你最喜歡的球隊或球員沒有在這裡,我先向你道歉):

我使用的庫有:

這是構模組化式的代碼。 請注意,我向allPlayers根查詢添加了一些變量。

關鍵的部分是:連接配接查詢并真正地提供資料。 rootValue對象可以包含多個根。

這裡隻有allPlayers查詢。 它從參數中提取offset(偏差)和limit(限制),以此對所有球員資料進行分切,然後根據球隊ID給每個球員的球隊屬性指派。 這使得每個球員都是一個嵌套對象。

最後,這裡是graphql的API終點,傳遞模式和根值對象:

把graphiql設定為true使我們能夠用一個很優秀的内置在浏覽器中的IDE來測試伺服器。我強烈推薦使用它來測試不同的查詢。

何為GraphQL?

使用GraphQL的特别查詢

何為GraphQL?

一切都設定好了。 讓我們導航到http://localhost:3000/graphql并找點樂子。

我們可以從簡單的查詢開始,查詢一個玩家名字清單:

好的。 我們在這裡查詢到了一些超級明星。 毫無疑問。 讓我們來看看更有趣的事情:從偏移(offset)4開始,查詢2名球員。 對于每個球員,請傳回他們的名字,他們獲得的冠軍數量,球隊名稱以及球隊赢得的冠軍數量。

是以科比在湖人隊中赢得了五次總冠軍,湖人隊總共赢得了16次總冠軍。 凱文杜蘭特在勇士隊中僅赢得了一次總冠軍,勇士隊總共赢得了五次總冠軍。

何為GraphQL?

GraphQL的變動

何為GraphQL?

魔術師約翰遜肯定是賽場上的魔術師。 但是如果沒有他的朋友卡裡姆·阿蔔杜勒·賈巴爾,他是無法成功的。 讓我們将卡裡姆添加到我們的資料庫。 我們可以定義GraphQL變動來執行操作,如添加,更新和删除圖中的資料。

首先,讓我們在模式中添加一個變動類型。 它看起來有點像功能簽名:

然後,我們需要實作它并将其添加到根值。 該實作簡單地使用查詢提供的參數并向data['allPlayers']添加新對象。 它也確定我們正确地設定了球隊。 最後,它傳回新的球員。

要真正地添加卡裡姆,我們可以調用這個變動(mutation)并查詢傳回的球員:

這是一個關于變動(mutation)的黑暗小秘密......它們實際上與查詢是完全一樣的。 您可以在查詢中修改資料,并且您可以僅傳回來自變動(mutation)的資料。 GraphQL不會窺探你的代碼。 查詢和突變都可以接受參數并傳回資料。 它更像是文法糖,讓你的模式更具人性化。

何為GraphQL?

進階主題

何為GraphQL?

訂閱

訂閱是GraphQL的另一個殺手級的功能。 通過訂閱,用戶端可以訂閱無論何時伺服器狀态發生變化都會觸發的事件。 訂閱是在後期被引入的,并以不同的方式通過不同的架構被實施的。

何為GraphQL?

驗證

GraphQL将針對模式驗證每個查詢或變動。 當輸入資料具有複雜形态時,這會是一個巨大的勝利。 您不必編寫煩人且脆弱的驗證代碼。 GraphQL将為您處理它。 

模式自省

您可以檢查和查詢目前模式本身。 這會賦予您權力去動态地發現模式。 這是一個傳回所有類型名稱及其描述的查詢:

何為GraphQL?

GraphQL是一個令人興奮的新API技術,它提供了許多優于REST API的優點。在其背後有一個充滿活力的社群,更不用說Facebook。 我預測它會很快成為前端的主流。 試一試, 你會喜歡的。