為什麼我們不使用GraphQL? - Wundergraph

banq發表於2020-11-08

我認為GraphQL將改變世界。將來,您可以使用GraphQL查詢世界上的任何系統。我正在建立這個未來。那麼,為什麼我反對使用GraphQL?
我個人的煩惱是,當前社群採取GraphQL的理由實際上與GraphQL無關。如果我們想推動採用,我們應該誠實並脫掉玫瑰色的眼鏡。這篇文章是對Kyle Schrade的“為什麼使用GraphQL”的回應(https://www.apollographql.com/blog/why-use-graphql/),我並不是要直接批評該文,我認為Kyle的文章應命名為“為什麼使用Apollo”。
 

REST缺點
作者指出REST API具有一些缺點,以及GraphQL如何解決所有這些缺點:過度獲取多個資源的多個請求,會產生基於巢狀資料上的瀑布網路請求,要獲得這些巢狀資料,每個客戶端都需要訪問提供這些巢狀資料的每個服務。
解決過度請求可以透過編寫另一個REST API作為特定使用者介面的外觀來解決。以Next.JS為例。接下來,您可以使用非常輕量級的語法來定義API。您可以將這些呼叫包裝到API中並使它們在伺服器端,而不是從客戶端發出多個請求。
使用這種方法也可以解決過度獲取和不足獲取,因為您可以在將資料傳送回客戶端之前對其進行操作。所描述的模式稱為“後端的前端”(BFF)。它不限於Next.JS之類的完整堆疊框架。您也可以為移動應用程式構建BFF。
使用BFF模式,客戶端本身不必知道每個服務的位置。但是,實施BFF的開發人員需要了解服務格局。希望您對所有服務都有開放的API規範,並在開發人員門戶中很好地介紹了這些規範。如果做到這樣地步,編寫BFF應該很容易。
使用GraphQL,仍然需要一個實現解析器的開發人員。實現解析器與構建BFF差不多是相同的任務,其邏輯非常相似。那麼,真正的區別是什麼?
BFF易於實現,因為有更多可用的工具。例如,如果將Next.JS之類的框架與swr掛鉤(重新驗證時失效)結合使用,則可以自動使用Etags進行快取,並且可以使快取失效。這減少了伺服器和客戶端之間傳送的資料量。與GraphQL相比,它的資料更少,因為您沒有傳送查詢有效載荷,並且如果響應仍然有效,伺服器將以304(未修改)進行響應。此外,您不必使用像Apollo這樣的重量級客戶端。Vercel的庫swr很小,非常易於使用。它帶有對分頁,掛鉤的支援,並有助於非常有效地來回導航。
GraphQL保留了查詢,但是要實現這一點會帶來額外的開銷。如果您沒有使用像Relay這樣的客戶端(預設情況下會保留查詢),則必須自己完成操作或使用第三方庫來實現它。與使用Next.JS的BFF方法相比,在前端獲得相同結果要涉及更多的複雜性。您將如何使用GraphQL實現Etags?如果未做任何更改,如何使GraphQL伺服器返回304狀態程式碼?您不是首先必須將所有查詢都轉換為GET請求嗎?如果是這樣,您的GraphQL客戶端和伺服器是否輕鬆支援此功能?
在使用者體驗和易於開發方面,BFF無疑是贏家。客戶端和伺服器之間的資料傳輸更少。易於實施。客戶更小,活動部件更少。
但是有一個陷阱。您必須為每個前端構建一個BFF。如果您有很多,那麼可能會需要很多工作。您必須維護所有BFF。您必須對其進行操作。您必須保護它們。
如果您在不進行折衷的情況下同時獲得兩者的好處,那豈不是很好嗎?這正是WunderGraph的含義,它是使用GraphQL構建BFF的框架。
 

沒有更多的版本的API
在下一段中,Kyle繼續探討版本API所涉及的問題。他絕對正確,因為API版本過多會使跟蹤變得非常困難。然後他得出結論,在GraphQL中,只有一個版本的圖形,並且可以在架構登錄檔中跟蹤更改,這是Apollo的付費功能。因此,您不會在版本控制方面遇到任何問題,他說。
我很難得出相同的結論。僅僅因為GraphQL模式本身不支援版本控制,並不意味著問題就消失了。如果您不對REST API進行版本控制,則將獲得相同的效果。實際上,許多專家說,如果不需要也應該始終不要嘗試引入API版本。話雖這麼說,是什麼讓您無法執行兩個版本的GraphQL模式?我並不是說這是個好主意,但在技術上是可行的。
如果您的組織中存在太多的REST API版本問題,那麼在丟擲類似GraphQL之類的新工具之前,也許您應該首先看一下組織。有這麼多版本的原因是什麼?也許流程的改變或新的團隊結構會有所幫助?GraphQL絕對不會解決您的版本問題。相反,我認為這實際上使情況變得更糟。
您必須支援移動應用程式嗎?您應該意識到,交付本地應用程式需要時間。您必須等待應用商店的批准,並且可以期望許多使用者從不(或緩慢地)安裝新版本。如果您想在不破壞客戶的情況下在這種情況下進行重大更改怎麼辦?不可能。您必須以不間斷的方式引入此類更改。
在GraphQL的情況下發展模式將意味著您不贊成使用舊欄位並新增新欄位。新客戶使用新欄位,而您希望使用舊欄位的客戶數量會越來越少。希望您擁有一個可以迫使您的使用者在某個時間點下載新版本的系統。否則,您可能會被迫無限期地支援不推薦使用的欄位。如果是這種情況,GraphQL的棄用模型根本無法幫助您。
使用REST,您可以建立一個新的端點或現有端點的另一個版本。問題是一樣的,解決方案看起來有點不同。
明確地說,如果您無法控制客戶那邊的開發,則就確實需要某種版本控制。如果您只有一個Web應用程式,則不需要此功能。但話又說回來,GraphQL可能也太過殺手了。
  

更小的載荷
在本段中,原文作者Kyle聲稱RESTful API不允許部分響應。
這是錯誤的。這是一個例子:

GET /users?fields=results(gender,name)


作者Kyle實際上是什麼意思?我很確定他知道部分回應。我想他想說的是某人需要實施部分響應。實際上,當您從資源中選擇子欄位時,它對於GraphQL看起來非常熟悉。使用GraphQL,我們可以立即使用此功能。
另一方面,使用BFF方法,則不需要此方法。只需準確返回所需的資料即可。同樣,像Next.JS這樣的全棧框架使實現此過程更簡單,使快取更加容易,並且使您免費獲得基於Etag的快取失效。
總結本節,GraphQL可以為您提供所需的確切資料。部分響應可以達到相同的結果。BFF附帶了實施和維護的額外費用,但具有更好的UX和DX。
 

嚴格型別介面
在本段中,Kyle解決了未嚴格鍵入REST API的問題。他談到了API的問題,這些問題尚不清楚,如果您獲得大量帖子或其他內容的陣列,那麼查詢引數如何使情況複雜化。他還指出,由於GraphQL具有嚴格的型別系統,因此不會出現此問題。
我認為Kyle所說的是一個組織問題,您需要一個組織解決方案。
當您允許開發人員部署REST API而不釋出Open API Specification(OAS)或類似內容時,您會遇到他所描述的那種問題。使用OAS,可以很容易地描述所有資源。OAS還允許您描述每個端點的OAuth2流和所需範圍。此外,您可以描述查詢引數的確切型別和驗證規則,這是GraphQL所缺少的功能。
從GraphQL來看,無法描述身份驗證,授權和輸入驗證。GraphQL缺少這些功能,因為Facebook的發明者在不同的層上解決了這個問題。無需他們將這些功能新增到GraphQL。您可以向架構中新增自定義指令,以實現類似於OAS的結果,但這將是您必須維護的自定義實現。
您可能會認為OAS無法保證API的響應符合規範。你說的沒錯。但是GraphQL模式如何保證任何內容?
GraphQL自省是將特定的GraphQL查詢傳送到伺服器以獲取有關GraphQL模式的資訊的操作。GraphQL伺服器可以自由選擇所需的任何型別。如果您傳送查詢,則伺服器可以使用內省響應中不符合GraphQL模式的響應進行回答。
以Apollo聯盟為例。您將架構上載到架構登錄檔中,然後錯誤地部署了錯誤版本的GraphQL伺服器。如果更改欄位的型別,客戶端可能會感到困惑。
當我們談論GraphQL中的型別安全性時,實際上是指我們相信GraphQL伺服器的行為完全符合自省查詢響應所通告的行為。為什麼我們不能以相同的方式信任Open API規範?我想我們可以。如果我們不這樣做,那就是人員問題,而不是技術問題。
 

更好的客戶端效能
下一段簡短介紹了GraphQL如何提高客戶端效能並減少網路往返次數。
我認為,與重量級的GraphQL客戶端相比,我已經充分解釋了BFF的功能強大得多,以及從“過時的重新驗證模式”中獲得了多少收益。
也就是說,GraphQL確實確實減少了請求數量並減少了整體資料傳輸。但是,您應始終考慮將GraphQL客戶端新增到前端的成本。
 

減少記錄和瀏覽API的時間

下一部分將介紹如何將OAS之類的工具用於RESTful API開發以及在微服務環境中維護多個OAS的挑戰。Kyle將單個GraphQL模式與分佈在多個git儲存庫中的Swagger檔案進行了比較。
我認為很明顯,導航單個GraphQL模式比坐在git儲存庫中檢視多個OAS檔案要簡單得多。但是,公平地說,我們必須將在一個蘋果與另外一個蘋果進行比較。如果您想提高開發人員的工作效率,就不會將OAS檔案貼上到git儲存庫中,而是每天都將其命名。您執行的是一個開發人員門戶,您可以在其中搜尋API並在它們之間導航。
OAS依賴於JSON-Schema,該功能具有驚人的功能:您可以引用另一個文件中的物件型別。您可以將OAS分為多個檔案,如果需要,它們可以互相引用。還有工具可以將多個OAS檔案合併到一個OAS文件中。然後,您可以使用此文件,並將其輸入到開發人員門戶中,該門戶可讓您整體瀏覽所有API。請記住,設定所有這些都會產生額外的費用。您需要執行一個開發門戶或購買一個。您必須描述所有的API,至少在開始時,這可能是一種負擔。
要新增的一件事是,有許多框架可以讓您用自己喜歡的程式語言來描述架構,例如透過定義物件或類。然後,您將獲得一個自動生成的Open API規範,該規範將在知名端點上提供。
讓我們將其與GraphQL進行比較。基本上有兩種方法,首先是SDL,然後是程式碼。無論採用哪種方式,最終都會得到一個GraphQL模式,該模式描述所有型別以及欄位,並允許您對其進行註釋。
那麼,有什麼區別呢?OAS帶有更多的開銷來進行設定。另一方面,OAS具有內建的支援文件記錄示例用例,身份驗證和授權以及輸入驗證規則。
請記住,GraphiQL本身沒有多個GraphQL模式的概念。如果您具有多個GraphQL(微)服務,則必須執行或購買專用元件,例如,類似於REST API開發人員門戶的架構登錄檔。
我想專門介紹一個額外的段落是API用例。僅僅因為您擁有OAS或GraphQL模式,並不意味著您的API有充分的文件記錄。API使用者可以使用該API做什麼?他們如何使用它?什麼是好用例?有什麼不好的?在哪裡尋求幫助?如何驗證使用者?我需要API金鑰嗎?用一種可以幫助API使用者使用API​​的方式來記錄您的API,比在型別和欄位中新增描述要多得多。OAS允許您新增示例有效負載並對其進行描述。GraphQL缺少此功能。在Stripe上看到一個積極的例子。它們遠遠超出了Swagger或GraphQL Playground所能達到的範圍。
另一方面,如果您檢視GitHub的公共GraphQL API,您將找不到單個示例查詢。假設您要獲取有關儲存庫及其所有問題的資訊。您必須開啟GraphiQL並開始搜尋。但是,GraphiQL中的搜尋功能並沒有真正幫助您。有人需要坐下來寫示例查詢和有關如何使用API​​的用例。否則,真的很難上手。
因此,儘管社群一直在說“ GraphQL正在自我記錄”,但僅此功能並不能提供有用的API。OAS為您提供了新增用例的工具,但是您仍然必須編寫它們。無論您選擇哪種工具或語言,都需要努力使API對其他人有用。
 

傳統應用程式的支援
在這一段中,作者說,為移動應用保留舊版本的REST API很痛苦。他的結論是,由於我們僅使用單個GraphQL伺服器,因此不會出現此問題。
抱歉,我再次得出完全不同的結論。如果將規則設定為禁止版本控制,則可以新增新端點或交換現有端點的實現。在這種情況下,GraphQL和REST之間沒有區別。對於REST和GraphQL API而言,支援舊版應用程式都是一個挑戰。您需要找到一種不破壞客戶端和伺服器之間合同的方法。伺服器是否公開REST或GraphQL都無關緊要,問題是相同的。
  

更好的錯誤處理
關於錯誤處理,作者描述了一個場景,即與將用部分資料進行響應的單個GraphQL查詢相比,客戶端必須進行3個後續REST API呼叫。
使用GraphQL,解析部分資料的邏輯就在伺服器中。客戶端需要具有其他邏輯以對部分響應做出適當反應。
藉助REST,獲取部分資料的邏輯可以位於客戶端或BFF中。無論哪種方式,其邏輯或多或少都與GraphQL相同,只是位於其他地方。顯然,REST API用例還需要客戶端中的邏輯來處理部分響應。這種邏輯幾乎與GraphQL用例中的邏輯相同。
沒有什麼可以阻止您在REST響應中返回有關失敗原因的特定資訊。OAS允許聯合型別,因此您可以自由地向客戶提供有關部分響應的豐富資訊。這類似於Sascha Solomon(https://sachee.medium.com/200-ok-error-handling-in-graphql-7ec869aec9bc)描述的響應聯合的概念。
GraphQL確實具有更好的錯誤處理能力嗎?我認為OAS和GraphQL都為您提供了很好的工具,以非常使用者友好的方式處理錯誤。開發人員應充分利用這些工具。沒有免費的午餐。

 

結論
Kyle在全文中總結說,GraphQL是API的未來,因為它在效能,有效負載大小,開發人員時間和內建文件方面都優越。
我同意GraphQL是API的未來,但出於不同的原因。
更好的效能和更小的有效負載大小不是GraphQL的獨特功能。您可以使用其他工具獲得更好的結果,或者必須擴充套件GraphQL,例如使用Relay來獲取持久化查詢。為了從GraphQL文件中獲得真正的好處,您肯定要做的不只是在架構中新增描述。
一旦塵埃落定,炒作就消失了,我們必須看看事實。我們不應該試圖讓世界相信GraphQL。使用GraphQL有很多優點,但是根據您的用例,您可能不會真正從中受益。與其說GraphQL是聖盃,不如說是更微妙的回應。
解決此問題的最佳方法是先檢視問題,然後對解決問題的可能工具進行獨特的比較。如果您的組織無法實現REST API,那麼GraphQL又能如何解決此問題?也許您組織內的某些事情必須改變?另一方面,如果這不是組織上的問題,並且您完全確定REST不是您的用例的好選擇,那麼我敢打賭,您一定會喜歡GraphQL。
 
GraphQL本身幾乎沒有用。而是GraphQL工具使GraphQL如此強大。是社群,是我們!像Apollo,Hasura,The Guild,FaunaDB,Dgraph,GraphCMS之類的公司,我也希望WunderGraph也如此,它們使GraphQL如此強大。它是GraphiQL,各種GraphQL客戶端,模式縫合,聯合。整個工具生態系統是GraphQL成為下一件大事的原因。
更多工具和服務將加強生態系統。更強大的生態系統將導致更多的採用,這又將吸引更多的公司為GraphQL生態系統新增服務和工具,這是一個非常積極的迴圈。
GraphQL在這方面與Kubernetes非常相似。Docker(容器執行時)還不夠。將複雜的Syscall封裝為易於使用的API是使能因素,但是為了建立一個豐富的生態系統,需要一個排程程式,該排程程式應具有足夠的表現力並具有非常容易的擴充套件性
GraphQL提供了一種與Docker一樣簡單的語言來定義和使用API​​。如果您以前看過幾行Javascript和JSON,則GraphQL會立即讓您感到熟悉。但是類似於Docker,該語言本身並不強大。它是可擴充套件性及其周圍的工具。
 
當Kyle問“ Why GraphQL”時,我認為他的實際意思是“ Why Apollo”。答案很簡單。沒有人願意圍繞REST API構建一個豐富的生態系統。嘗試根據開放API規範生成React.JS客戶端。與GraphQL客戶給您的東西相比,這種體驗很爛。沒有人想出一種好的商業模式來解決這個問題。輸入GraphQL,您將獲得大量工具來抽象出您不想處理的問題。
REST API與所描述的用例的相關性將降低,而不是因為GraphQL是高階的。它是使GraphQL繼續獲得市場份額的工具和生態系統。與REST相比,GraphQL生態系統的擴充套件速度非常快。
超媒體API在伺服器呈現的Web應用程式中一直髮揮著巨大作用,並且仍然扮演著重要角色。但是,網路正在向前發展。使用者期望從網站獲得的原生體驗。Jamstack正在接管前端。具有伺服器端渲染和動態Javascript客戶端的混合模型是這些應用程式的實現者。
RESTful API擅長解決一系列不同的問題。他們不會消失,恰恰相反!對於行業正在轉變的這種型別的應用程式,它們並不是正確的工具。我認為REST API是內部API,合作伙伴API和伺服器到伺服器通訊的理想工具。這是GraphQL在REST方面並未真正帶來任何好處的領域。與RPC一起,它將在這一領域擁有美好的未來。



 

相關文章