Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. JavaScript

何為GraphQL?

by
Read Time:3 minsLanguages:

Chinese (Traditional) (中文(繁體)) translation by Qiang Ji (you can also view the original English article)

概要

GraphQL是一種新型的,令人興奮的,用於特定查詢和操作的API。它非常靈活並且有很多好處。 它特別適合以圖形和樹型為組織的數據。 Facebook在2012年研發出了GraphQL並在2015年將其開源。

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

  • GraphQL的原理
  • 它如何與REST進行比較
  • 如何設計數據模式
  • 如何配置一個GraphQL服務器
  • 如何實現查詢和變動
  • 和一些額外的高級主題

GraphQL的亮點在哪裡?

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

  • 目前金州勇士隊名單上的球員名字是什麼?
  • 華盛頓奇才首發隊員的名字,身高和年齡是什麼?
  • 哪個在任的教練擁有最多的總冠軍?
  • 哪支球隊在哪一年在此教練的執教下贏得了冠軍?
  • 哪個球員贏得了最有價值隊員獎?

我可以給出幾百個與此類似的查詢。想像一下你不得不設計一個API對前端提供所有這些查詢,並且還能夠在你的用戶和產品經理有新查詢需求的時候方便地針對新查詢類型擴展此API。

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

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提供的基礎類型的一種,像ID,字符串,布爾函數或用戶自定義類型。  GraphQL圖的節點是用戶自定義的類型,連接節點的線是用戶自定義類型的屬性。

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

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

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

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

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

感嘆號表示該值不能為空值(null)。在allPlayers查詢的情況下,它可以返回一個空列表,但不能為空值。此外,這意味著列表中的球員也不能為空值(因為它也有一個感嘆號)。

設置GraphQL服務器

這是一個基於node-express的全功能GraphQL服務器。它有一個在內存裡硬編碼的數據庫。 通常,數據將存儲在數據庫中或從其它服務中獲取。數據在這裡定義(如果你最喜歡的球隊或球員沒有在這裡,我先向你道歉):

我使用的庫有:

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

關鍵的部分是:連接查詢並真正地提供數據。 rootValue對象可以包含多個根。

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

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

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

使用GraphQL的特別查詢

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

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

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

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

GraphQL的變動(Mutations)

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

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

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

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

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

高級主題

訂閱

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

驗證

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

模式自省

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

結論

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

关注我们的公众号
Advertisement
Did you find this post useful?
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.