一張腦圖總結全文:

GraphQL 是由 Facebook 開發并開源的。提到 GraphQL ,大家自然而然會提起 RESTful api。下面對比一下 RESTful api 和 GraphQL 的優缺點。
聲明式的接口擷取 RESTful api 傳回的字段備援, 當多個終端共用接口時,尤其明顯。GraphQL 可精準的傳回所需的資料結果,減少資料傳輸大小。
嵌套複雜資料僅需一次調用 RESTful 對于嵌套的複雜資料需要多次調用,而 GraphQL 隻需要一次。
愉快地前後端聯調效率 REST 每次新加字段,需頻繁溝通,且需借助 swagger 生成接口文檔, GraphQL 自動生成标準文檔。
如果上面的優點看不懂,沒關系,我們來舉一個栗子,加速了解:
服務端 getUser 接口傳回了 id, name 資訊, 但是另外一個場景,需要額外多傳回幾個字段, 比如 email, adress 等。此時服務端要怎麼做?有以下三種做法:
新開一個接口, 傳回所需要的所有字段
請求增加一個 type ,用于區分場景,服務端根據不同 type 傳回不同的字段
不管三七二十一, 在原有接口上增加多的字段。
如果隻是 1 個,2 個場景還好,但如果後期有 n 個場景,需要傳回非常多的字段,這不僅會浪費帶寬,用戶端資料解析也會影響響應時間,進而影響使用者體驗。那讓背景新增一個接口可以嗎?當然可以,可是這樣背景需要額外維護這種“業務邏輯”。
查詢( query )
更新( mutation )
訂閱( subscription )
我一直提倡,剛開始學習一門新的技術,别看太多文檔,先用它的 api, 快速做一個 demo ,跑起來之後。再開始系統學習,這樣效率是最高的。是以,下面我們會實戰來做一個 GraphQL .
跟着官方文檔[1]簡單快速建立一個栗子。
打開 index.js ,将以下代碼複制粘貼進去。
我們在上面的 index.js 檔案後面,繼續複制粘貼
在指令行中運作 index.js
好了, 就是這麼簡單,一個 graphql 就寫好了。實際中的項目可能使用 egg 或者 koa 或者 express。本質的思想是一樣的, 都是先定義 GraphQL schema ,再定義 resolver ,resolver 這裡從不同地方取數,再之後就是傳遞 schema 和 resolver,建立執行個體。
上面的代碼運作起來了,要去哪裡調用?如果是用 RESTful api ,我們會用 postman 來測試接口是否可以跑通。同樣的,GraphQL 可以用 GraphiQL 來測試。
按需取用:
除了可以用來測試接口之後,它還是一個文檔工具,使用 GraphiQL 可以很容易地讓人感受到“代碼即文檔”的快樂。
你可以在這裡檢視測試的曆史
從上面的例子看出,要先定義 Schemas, 那我們就來學習下 Schemas。如果你使用過 Typescript ,會發現它的類型跟 Typescript 特别的類似。
Int, Float, String, Boolean, ID(唯一辨別符)
enum, Date, interface
!(不可為 null) 可通過 Union types 或 implements 擴充上面的類型。
查詢(query)和變更類型(mutation)
檢視官方文檔[2]
我們可以簡單地了解成,針對我們暴露的接口,調用相應的方法去取數傳回。resolver 的解析規則是, 從外到内依次處理查詢塊,為每一個查詢塊執行對應的 resolver 函數,并傳遞外層調用傳回的結果作為第一個參數,也就是下面代碼中的 obj 。
resolver 函數它接收 4 個參數
同樣的,我們直接來看一個例子:在 index.js 中修改對應的 Schemas 和 Resolver
由于這個 resolver 函數第一個參數是傳遞外層調用的傳回結果,這裡我們沒有嵌套 resolver ,是以我們直接用第二個參數 id 擷取前端傳入的參數。
更多内容檢視 resolver 文檔[3]
然後我們在 http://127.0.0.1:4000/graphql 或者在用戶端 GraphiQL 中測試
已經成功找到對應 id 的資料了,但是這裡的 id 是寫死的,我們說 graphql 最大的好處是聲明式擷取,那如何把 id 變成一個變量,讓外部傳入?
給傳回的值設定别名
好了,接口正常傳回。
更多查詢變更可看官方文檔[4]
在實際項目中,我們會将資料庫 ,dataloaders 注入到 context 中,友善所有 resolver 調用。
Dataloader 是 facebook 搞的一個 js 庫,可以大幅降低資料庫的通路頻次,進而降低系統負載,經常在 Graphql 場景中使用。通過使用 dataloader,資料庫的通路頻次可以指數級别下降。
dataloader 是如何工作的呢,可以看下圖:
對于 User 表的多次通路,通過 dataloader 去取,會自動合并為一個請求。dataloader 之是以可以實作這樣的能力,是因為他把每一次資料請求,都推遲到 node 的 Next Tick 後集中批處理運作,這樣就可以對請求進行加工合并。