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可以組合成為一個.
- 社區支持好. 多種語言: https://graphql.org/code/#server-libraries; 多種客戶端: https://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庫: https://graphql.org/code/#server-libraries
Client端
客戶端查詢, 更加自主的結構, 字段級別的粒度.
Client庫: https://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命令模擬得到相同的效果, 見:
https://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兩者可以共存.