Why GraphQL? 6個問題

Why GraphQL? 6個問題

GraphQL, 是一個API的標準: specification.

對於每個新技術, 要搞清楚的6個問題:

  • 1.這個技術出現的背景, 初衷, 要達到什麼樣的目標或是要解決什麼樣的問題.
  • 2.這個技術的優勢和劣勢分別是什麼, 或者說, 這個技術的trade-off是什麼.
  • 3.這個技術使用的場景.
  • 4.技術的組成部分和關鍵點.
  • 5.技術的底層原理和關鍵實現.
  • 6.已有的實現和它之間的對比.

1.這個技術出現的背景, 初衷, 要達到什麼樣的目標或是要解決什麼樣的問題.

GraphQL是相對於REST API的另一種標準.

相對於REST返回固定結構數據的多個endpoints, GraphQL的server只暴露一個endpoint, 由客戶端來規定想要的字段和結構, 服務端精確返回client要求的數據.

初衷和背景

2012年, Facebook有一個新聞類的iOS app. 隨着移動用戶增多, 網絡請求有設備電量消耗, 弱網環境等問題.
這在當時是一個非常緊迫的issue, 於是他們研究出了GraphQL, 減小了需要發送的請求個數和數據傳輸量.
2015年Facebook將GraphQL開源.

類似的嘗試還有Netflix的Falcor和Coursera, 後者後來取消了自己的effort, 加入了GraphQL的陣營.

目標和要解決的問題

GraphQL思想: enables declaratative data fetching.

GraphQL要解決的問題: 優化客戶端向服務器請求數據的過程:

  • 對於同樣的業務需求, REST API可能要請求多個endpoints, GraphQL可以用一個請求.
  • 數據形式是客戶端定義的, 只取想要的數據, 不會取多餘的數據, 減小了數據傳輸量.
  • 各個前端可以訪問自己想要的數據.
  • 快速開發, feature快速迭代. 升級改動時, 可能不需要後端改動.

2.這個技術的優勢和劣勢分別是什麼, 或者說, 這個技術的trade-off是什麼.

GraphQL的優勢

  • 客戶端可以精準取到自己想要的數據, 不再多取或者少取. 多取: 取到了不需要的數據, 可能有性能, 流量問題; 少取: 需要多發請求來滿足需求.
  • API有strong typed schema. 客戶端可以通過schema知道API支持什麼, 包括操作, 參數, 可能的響應等. 支持introspection. schema是一個API能力的contract, 不需要再額外寫文檔, 一旦定義好了之後, 前後端可以獨立工作.
  • 強類型, 利用schema, 結合build工具, 可以在編譯時期對請求進行一些檢查.
  • 有助於產品快速升級迭代. 前端的改動可以不需要後端的修改.
  • 富有洞察力的數據分析: 因為可以精細地知道client要讀的數據, 對數據的的使用情況可以有更深的理解. 在API改動的時候可以deprecate掉不用的數據. 也有助於後端的性能分析.
  • schema stitching: 多個不同的GraphQL的endpoints可以組合成為一個.
  • 社區支持好. 多種語言: //graphql.org/code/#server-libraries; 多種客戶端: //medium.com/open-graphql/exploring-different-graphql-clients-d1bc69de305f; 多種工具: Prisma, GraphQL Faker, GraphQL Playground, graphql-config.

GraphQL的缺點

  • 可能並不適合所有類型的API. 比如認證, 授權(authentication and authorization).
  • 服務器端的性能問題.
  • 服務器端的Cache. 需要一個全局的id, 討論見: Caching.
  • 通信的快速發展, 實現GraphQL節約的數據傳輸量可能不值一提, 優勢不明顯.

3.這個技術使用的場景.

GraphQL是一種規範, 具體實現有多種.
和傳輸層, 數據庫, 數據源類型都不相關.

GraphQL應用場景:

  • 在數據庫之上.
  • 和已有系統集成. 可以用來改造遺留系統, 統一接口, 隱藏實現.
  • 混合前兩者, 在已有系統和數據庫之上.

理想開發場景: 根據數據, 建立好schema之後, 前後端獨立開發, 前端可以根據需要拿到想要的數據.

4.技術的組成部分和關鍵點.

Schema

Schema定義了API的能力, 是server和client之間的協議. 規定了客戶端可以請求的數據和類型.

The Schema Definition Language (SDL): Schema Definition Language.

Root Types: Query, Mutation, Subscription.
對應查詢, 更改和訂閱.

Server端

GraphQL服務器只暴露一個endpoint.

在API的設計上, 需要把數據按照Graph來想, 而不是按照endpoints來想, 更專註於描述數據.

對於Schema定義好的結構, Server端對於每個字段實現resolver function, 進行查詢.

Server庫: //graphql.org/code/#server-libraries

Client端

客戶端查詢, 更加自主的結構, 字段級別的粒度.

Client庫: //graphql.org/code/#graphql-clients

和Server庫一樣, 這些庫為我們封裝了一些樣板代碼, 簡化方便了我們的開發.

5.技術的底層原理和關鍵實現.

Server端實現

  • schema的定義. -> structure.
  • resolver function形式的具體實現. -> behaviour.

queries/mutations都包含一個字段集合.
在server上, 每個字段都有一個resolver function, 用來讀取相應字段的數據.

Server上執行的機制:
The query is traversed field by field, executing 「resolvers」 for each field.
廣度優先. 按層級進行.

為了改善效率, JavaScript有dataloader, 把resolver的調用批處理, 減少重複調用.

Client端實現

客戶端實際上發送的是POST請求, GraphQL的query作為JSON payload的字段.

可以用curl命令模擬得到相同的效果, 見:
//graphql.org/graphql-js/graphql-clients/

introspection query可能是唯一的GET請求.

6.已有的實現和它之間的對比.

REST的好點子: stateless servers, structured access to resources.

REST的缺點: 快速變化的客戶端需求可能和REST的靜態屬性不合.

REST:

  • 業務數據不同, 可能需要client向server發送多個請求.
  • 請求中可能包含多餘數據. old client也會收到新增的數據.
  • 弱類型.
  • 錯誤返回不同的狀態碼.
  • API升級需要提供不同的版本號.

GraphQL更加靈活和有效率.

  • 單個請求.
  • 不包含多餘數據.
  • 強類型.
  • 錯誤返回是在響應中的”errors”字段, 包含錯誤list, 每個錯誤有”message”字段.
  • API升級不需要版本號. 新增數據和類型不會影響以前的查詢.

REST和GraphQL兩者可以共存.

參考