[譯]GraphQL:你需要知道的一切

原文鏈接:medium.com/@weblab_tech

原文作者:Weblab Technology

譯者:楊濤

你可能已經構建和使用REST API一段時間了,並且最近開始聽說GraphQL--一種新型的API技術。有些人說它很好,但一些人並不認同。那麼,我相信你肯定很想知道GraphQL讓人驚奇的地方在哪和它與傳統方法有什麼不一樣。

這篇文章的目的是指出GraphQL相關的主要功能和討論特定API規範的優點和缺點。

GraphQL通常被描述為一種"前端導向"的API技術,因為它讓前端開發者以一種比以前簡單得多的方式請求數據。Facebook引入了這種查詢語言,它的目標是以符合直覺和可伸縮的方式定製客戶端應用,以描述數據的先決條件和交互。最好的一點是這種查詢語言不依賴於任何特定的資料庫管理系統,並且得到了當前數據格式和編碼方式的支持。

傳統REST的一個基本問題是,客戶端不能個性化的收集數據。除此之外,運行和控制多個端點(譯者注:表示API的具體網址,也可以理解為 介面)是另一個難點,因為客戶端經常需要從多個端點獲取數據。

當建立起一個GraphQL伺服器,只需要簡單的URL就能獲取和修改數據。因此,一個用戶可以通過傳遞查詢字元串和聲明他們需要什麼來向伺服器請求數據集。

在我們繼續之前,在這你可以找到我們的個人實踐。

weblab-technology/graphql-example?

github.com圖標

GraphQL VS REST

說到相似之處,REST和GraphQL都用於構建API。 另外,它們都可以通過HTTP進行管理。

至於差異,REST主要是一個以軟體為中心的結構化概念,沒有規範,也不要求明確的工具集。它更關注API的穩定性而不是性能。

GraphQL,另一方面,是一種被設計於通過HTTP管理端點,提高性能和適用性的查詢語言。我甚至可以說,查詢語言和開發web的架構風格放在一起做比較,可能看起來很奇怪:)。一些其他顯著的不同包括:

數據獲取

毫無疑問,數據獲取是GraphQL的一個最引人矚目的特點之一。通過標準的REST API去生成和獲取數據,我們可能需要向多個端點發起請求。相比之下,GraphQL提供了可以獲取伺服器數據的單端點

query { books { id title author isbn price } }

數據獲取之外

由於在REST中每個介面都包含固定的數據格式,相比GraphQL,它會讓你拿到更多的多餘數據。相似的,REST會發送額外的請求去獲取相關數據。

對於上一個例子,GraphQL是很不一樣的。因為它是一種查詢語言並且支持聲明式獲取數據,用戶可以從伺服器只獲取他們需要的數據。

只查詢books的title和price

query { books { title price } }

錯誤管理

在REST風格中,錯誤管理是非常簡單的。我們需要做的是檢查HTTP的headers以及了解response的位置。通過狀態碼,我們能快速的找到錯誤和合適的方式去解決它。另一方面,在GraphQL中,我們總是收到200 OK的狀態碼。

Request: query { books { error_field } }Response:Request Method:POSTStatus Code: 200 OK{「errors」:[{「message」:」Cannot query field 」error_field」 on type 」Book」.」,」category」:」graphql」,」locations」:[{「line」:3,」column」:3}]}]}

緩存

因為REST強制使用具有緩存機制的HTTP協議,你可以通過它避免獲取多餘資源。GraphQL,另一方面,沒有緩存機制,它把緩存的重任交給了用戶。

GraphQL的優點

版本

數據控制會帶來API的邊界,任何的變動都會被視為一種破壞性的改變,而破壞性改變就需要更新API的版本。這也許就是大多數API選擇版本控制的原因。如果新API需要最新的版本,我們就需要頻繁在新API和原有API之間調整。[譯者注:例如介面改變了某個欄位的數據類型]

相比之下,GraphQL只返回我們需要的數據,在不改變原有的請求的情況下,拿到最新的數據類型和欄位。

棄用很容易

當使用GraphQL,你可以方便的棄用一個欄位。GraphQL用戶肯定會聲明他們需要的欄位。

author_name => [ type => Type::string(), deprecationReason => Deprecated. Use author field, ],

REST API 以不同的方式運作。雖然基本的端點都能在REST API中獲取,但不是所有端點都能返回稀疏欄位。[譯者注:即可能包含多餘的欄位]

相比之下,GraphQL非常容易監控特定欄位的使用。API使用者能在特定的客戶端部署獲取到的欄位。

性能優化

REST的請求默認作為一個整體,GraphQL通常盡量發送最少的請求。即便REST的每個請求返回最基本的部分,相同情況下,GraphQL能傳輸更多的數據片段。

GraphQL的缺點

GraphQL緩存不容易

和默認採用能讓客戶端和代理端完美的工作的HTTP的REST不同,GraphQL以完全不同的方法調用。當然,事情並沒有像REST一樣簡單,因為你需要調整你的數據集,使用Redis的集合和總是需要祈禱客戶端能緩存。

正如官方文檔解釋的那樣,

"在一個基於端點的API,客戶端能夠使用HTTP緩存輕易的避免重複獲取資源和識別什麼時候兩個資源是一樣的。客戶端可以根據API中的URL作為全局唯一的標識符構建緩存。在GraphQL中,沒有類似URL的對象能夠作為全局唯一的標識符。最佳實踐是提供這麼一個標識符供客戶端使用"

鑒權問題

鑒權問題也是我們在使用GraphQL時關注的一個重要問題。將GraphQL作為一個特定領域語言考慮,它只是薄薄的一層放置在伺服器和客戶端中間。鑒權是單獨的一層,語言本身並不會對應用進行驗證和授權。但是你可以使用入口令牌(entry tokens)把客戶端和響應關聯起來。這與我們在REST中遵循的方法非常相似。

檢測和解決n+1問題

什麼是n+1問題?

n+1問題是在做GraphQL後端時最明顯的可能遇到的優化問題。

如果你沒有優化你的GraphQL查詢,你可能在一次query進行多次查詢。沒有合適的緩存和批量處理系統,每次確定欄位的時候伺服器都會響應一次請求。DataLoader無疑是最好的解決方案,可以極大地增強後端的性能,特別是在GraphQL伺服器中。

用一個簡單的例子描述n+1問題

query { users { name education { degree year } age address { country city street } }}

使用REST API是很容易評估,識別和解決n+1問題的。對於GraphQL有所不同。幸運的是,Facebook正在努力通過DataLoader解決這個問題

什麼是DataLoader

DataLoader是一個用於用戶在GraphQL函數中讀取數據和訪問數據的基礎設施。

我們可以通過這個基礎設施直接從記錄中讀取數據而不是從SQL查詢。

它是怎麼運行的?

DataLoader主要使用了批處理和緩存。它用於批量載入客戶端的多個 問題/請求的響應。此外,它可以緩存響應和讓它們能響應連續類似的資源請求。

GraphQL中的Queries, Mutations, and Subscriptions

好的,我們已經強調了一些GraphQL重要的方面。但是要開發一個功能齊全的app,我們也需要知道一些其他用來增強功能和性能的部分。

Queries

正如它的名字,Queries是客戶端從服務端獲取數據。和從多個端點返回詳細信息的REST不一樣,GraphQL只提供了一個端點,讓客戶端從預定義的框架決定它需要的數據。

例如:

{ Users { name }}

上面的查詢提到的Users欄位稱為根欄位,其他數據稱為載荷。

這個查詢將會返回用戶名的列表:

{ 「Users」: [ {「name」: 「Damira」}, {「name」: 「Michael」} {「name」: 「Salman」} {「name」: 「Sara」} {「name」: 「Maria」}]}

值得注意的是,這個查詢只返回了用戶名(因為在我們的查詢中,我們只聲明了我們需要用戶名)。對於二外的請求,我們需要為它增加特定的細節。

例如,假設我們只希望獲取列表中的最後3個用戶的信息。我們可以這麼寫參數來實現它。

{ Users (last: 3) { name username}}

至此,我們已經看到如何通過查詢從伺服器獲取數據。現在讓我們看一下在GraphQL中創建,省略,更新數據的方法。

Mutations

Mutations用於創建,更新或者刪除數據。除了需要在開頭增加『mutation』 欄位,它的結構和queries幾乎一樣。例如,

mutation { createUser (name : 「John」, username: 」jo123」){ name username }}

Subscriptions

Subscriptions用於設置和保存和伺服器的實時連接。它可以讓你獲取相關事件的實時信息。大多數情況下,客戶端需要訂閱特定的事件來獲取相應的數據。

請通過文檔獲取詳細信息

兩全其美的辦法

儘管GraphQL解決了一些問題,它還是有著一些缺陷和不足。校驗,策略和緩存只是其中的幾例。由於它本質上並不具備說服力,它並沒有指導用戶如何應用這些層。除此之外,在服務端和客戶端之間存在不具體的一層令人不安。

在Aollo裡面的Stack可以找到一部分問題的解決方案。

如果你有一個正在運行的項目,它是很難快速從RESTful API遷移到GraphQL的。但好消息是你可以同時享受這兩種方法的好處。例如你可以用GraphQL的queries去重構前端里獲取數據的方式,然後再開始整合mutations。它允許你緩慢的減少你的controllers里的actions。

此外,你可以在項目中長時間保持兩種方法並存。例如,如果你想簡化授權機制,你可以一直用REST架構提供幫助。

總結

回憶起90年代末作為一個健壯的計算機網路應用交互結構化數據的協議,曾受到熱烈歡迎和獲得巨大的聲譽的SOAP。但是它的載荷明顯很高並且以前的應用容易提高的數據丟失和阻塞的幾率。

REST是為了做到更好的利用web伺服器和提高適應性而引入的。這個概念非常的簡單直接,完全沒有狀態,因此可以放棄一些不相關的因素。除此之外,這種方法可以輕鬆的同時使用JSON和XML。但是,數據的統一是最大的障礙。此外版本號的分歧是另一個問題。為了解決這個問題,Facebook為開發者提供了一個兩全其美的方案-GraphQL。

GraphQL不是一個沒有具體實踐基礎的方案。RESTful已經在效率和表現方面證明了很多年。GraphQL能彌補REST的不足,REST可以填補GraphQL的空白。

值得注意的是,GraphQL和REST的情況和關係型資料庫和非關係型資料庫的關係很像。

使用GraphQL的時候,HTTP是服務端和客戶端通信協議的最佳選擇,這主要是因為它的普遍性。然而,當使用HTTP2的時候,性能還是會有問題。

儘管GraphQL解決了一些問題,選擇任何一個API規範仍是困難的,因此你可以考慮讓兩者並存。

從設計到應用的整體功能,選擇一種API風格都會對整個API過程產生影響。因此,做選擇應當根據遠見的而不僅僅是基本的信仰。

這篇文章完全基於我們對這兩種方法的個人經驗。我們很希望能聽到你們關於GraphQL和RESTful API的看法。

一些有用的資料

weblab-technology/graphql-example?

github.com圖標Implementing GraphQL as a Query Language... (PDF Download Available)?

www.researchgate.net圖標http://www.springer.com/cda/content/document/cda.../9781441983022-c1.pdf?SGWID?

www.springer.com

byOleksandr Knyga, Software Engineer

Maksim Kolesnikov, DevOps

Sergei Guliaev, Back-End Developer

Viacheslav Eremin, Front-End Developer

Sharmeen Hayat, author & Data Specialist

Dima Dmytriienko, editor & Brand Specialist

譯者注

原文提到的GraphQL一些問題,在Apollo GraphQL這個項目中都得到了一定程度的解決,比加緩存。

推薦閱讀:

有沒有開源的api管理系統?
Aspose.HTML for .NET 18.3版本新增操作功能
阿里雲API創新大賽百萬大獎花落誰家?
GraphQL,你準備好了么?
如何才能寫出簡潔好看的API文檔,有沒有開源框架可以用?

TAG:前端開發 | API | 後端技術 |