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

原文連接:https://medium.com/@weblab_tech/graphql-everything-you-need-to-know-58756ff253d8前端

原文做者:Weblab Technologygit

譯者:楊濤github

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

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

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

傳統REST的一個基本問題是,客戶端不能個性化的收集數據。除此以外,運行和控制多個端點(譯者注:表示API的具體網址,也能夠理解爲 接口)是另外一個難點,由於客戶端常常須要從多個端點獲取數據。數據庫

當創建起一個GraphQL服務器,只須要簡單的URL就能獲取和修改數據。所以,一個用戶能夠經過傳遞查詢字符串和聲明他們須要什麼來向服務器請求數據集。後端

在咱們繼續以前,在這你能夠找到咱們的我的實踐。 graphlql-example緩存

GraphQL VS REST

說到類似之處,REST和GraphQL都用於構建API。 另外,它們均可以經過HTTP進行管理。 至於差別,REST主要是一個以軟件爲中心的結構化概念,沒有規範,也不求明確的工具集。它更關注API的穩定性而不是性能。 GraphQL,另外一方面,是一種被設計於經過HTTP管理端點,提升性能和適用性的查詢語言。我甚至能夠說,查詢語言和開發web的架構風格放在一塊兒作比較,可能看起來很奇怪:)。一些其餘顯著的不一樣包括:性能優化

數據獲取

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

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:POST
Status 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.org/learn/queri… 獲取詳細信息

一箭雙鵰的辦法

儘管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的見解。

一些有用的資料

https://github.com/weblab-technology/graphql-example

Implementing GraphQL as a Query Language for Deductive Databases in SWI-Prolog Using DCGs, Quasi Quotations, and Dicts

REST and Web Services — In Theory and in Practice — Springer

by Oleksandr 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這個項目中都獲得了必定程度的解決,比加緩存。

相關文章
相關標籤/搜索