[譯] 我經常聽到的 GraphQL 到底是什麼?

lsvih發表於2019-03-04

[譯] 我經常聽到的 GraphQL 到底是什麼?

我經常聽到的 GraphQL 到底是什麼?

當聽說出了一門新技術的時候,你可能會和我一樣有以下 3 種反應:

1. 嫌棄

又來一個 JavaScript 類庫?反正我只用 JQuery 就行了。

2. 感興趣

嗯,也許我應該去了解一下這個我總是聽別人說到的新庫。

3. 恐慌

救命啊!我必須馬上去學這個新庫,否則我就會被淘汰了!

在這個迅速發展的時代,讓你保持理智的方法就是保持上述第二或第三種態度去學一些新的知識,走在潮流之前的同時激起你的興趣。

因此,現在就是學習 GraphQL 這個你常常聽到別人談論的東西的最好時機!

基礎

簡單的說,GraphQL 是一種描述請求資料方法的語法,通常用於客戶端從服務端載入資料。GraphQL 有以下三個主要特徵:

  • 它允許客戶端指定具體所需的資料。
  • 它讓從多個資料來源彙總取資料變得更簡單。
  • 它使用了型別系統來描述資料。

如何入門 GraphQL 呢?它實際應用起來是怎樣的呢?你如何開始使用它呢?要找到以上問題的答案,請繼續閱讀吧!

[譯] 我經常聽到的 GraphQL 到底是什麼?

遇到的問題

GraphQL 是由 Facebook 開發的,用於解決他們巨大、老舊的架構的資料請求問題。但是即使是比 Facebook 小很多的 app,也同樣會碰上一些傳統 REST API 的侷限性問題。

例如,假設你要展示一個文章(posts)列表,在每篇文章的下面顯示喜歡這篇文章的使用者列表(likes),其中包括使用者名稱和使用者頭像。這個需求很容易解決,你只需要調整你的 posts API 請求,在其中嵌入包括使用者物件的 likes 列表,如下所示:

[譯] 我經常聽到的 GraphQL 到底是什麼?

但是現在你是在開發移動 app,載入所有的資料明顯會降低 app 的速度。所以你得請求兩個介面(API),一個包含了 likes 的資訊,另一個不含這些資訊(只含有文章資訊)。

現在我們再摻入另一種情況:posts 資料是由 MySQL 資料庫儲存的,而 likes 資料卻是由 Redis 儲存的。現在你該怎麼辦?

按著這個劇本想一想 Facebook 的客戶端有多少個資料來源和 API 需要管理,你就知道為什麼現在評價很好的 REST API 所體現出的侷限性了。

解決的方案

Facebook 提出了一個概念很簡單的解決方案:不再使用多個“愚蠢”的節點,而是換成用一個“聰明”的節點來進行復雜的查詢,將資料按照客戶端的要求傳回。

實際上,GraphQL 層處於客戶端與一個或多個資料來源之間,它接收客戶端的請求然後根據你的設定取出需要的資料。還是不明白嗎?讓我們打個比方吧!

之前的 REST 模型就好像你預定了一塊披薩,然後又要叫便利店送一些日用品上門,接著打電話給乾洗店去取衣服。這有三個商店,你就得打三次電話。

[譯] 我經常聽到的 GraphQL 到底是什麼?

GraphQL 從某方面來說就像是一個私人助理:你只需要給它這三個店的地址,然後簡單地告訴它你需要什麼 (“把我放在乾洗店的衣服拿來,然後帶一塊大號披薩,順便帶兩個雞蛋”),然後坐著等他回來就行了。

[譯] 我經常聽到的 GraphQL 到底是什麼?

換句話說,為了讓你能和這個神奇的私人助手溝通,GraphQL 建立了一套標準的語言。

[譯] 我經常聽到的 GraphQL 到底是什麼?

上圖是 Google 圖片找的,有的私人助理甚至有八條手臂。

[譯] 我經常聽到的 GraphQL 到底是什麼?

理論上,一個 GraphQL API 主要由三個部分組成:schema(型別)queries(查詢) 以及 resolvers(解析器)

查詢(Queries)

你向你的 GraphQL 私人助理提出的請求就是 query ,query 的形式如下所示:

query {
  stuff
}複製程式碼

在這裡,我們用 query 關鍵字定義了一個新的查詢,它將取出名叫 stuff 的欄位。GraphQL 查詢(Queries)最棒之處就是它支援多個欄位巢狀查詢,我們可以在上面的基礎上加深一個層級:

query{
  stuff {
    eggs
    shirt
    pizza
  }
}複製程式碼

正如你所見,客戶端在查詢的時候不需要關心資料是來自於哪一個“商店”的。你只需要請求你要的資料,GraphQL 服務端將會完成其它所有的工作。

還有一點值得注意,query 欄位也可以指向一個陣列。例如,以下是一個查詢一個文章列表的常用模式:

query {
  posts { # this is an array
    title
    body
    author { # we can go deeper!
      name
      avatarUrl
      profileUrl
    }
  }
}複製程式碼

Query 欄位也支援使用引數。如果我想展示一篇特別的文章,我可以將 id 引數放在 post 欄位中:

query {
  post(id: "123foo"){
    title
    body
    author{
      name
      avatarUrl
      profileUrl
    }
  }
}複製程式碼

最後,如果我想讓 id 引數能動態改變,我可以定義一個變數,然後在 query 欄位中重用它。(請注意,我們在 query 欄位處也要定義一次這個變數的名字)

query getMyPost($id: String) {
  post(id: $id){
    title
    body
    author{
      name
      avatarUrl
      profileUrl
    }
  }
}複製程式碼

有個很好的方式來實踐這些方法:使用 GitHub’s GraphQL API Explorer 。例如,你可以嘗試下面的查詢:

query {
  repository(owner: "graphql", name: "graphql-js"){
    name
    description
  }
}複製程式碼

[譯] 我經常聽到的 GraphQL 到底是什麼?

GraphQL 的自動補全功能

當你嘗試在下面輸入一個名為 description 的新欄位名時,你可能會注意到 IDE 會根據 GraphQL API 將可選的欄位名自動補全。真棒!

[譯] 我經常聽到的 GraphQL 到底是什麼?

The Anatomy of a GraphQL Query

你可以讀讀這篇超棒的文章《Anatomy of a GraphQL Query》,瞭解更多 GraphQL 查詢的知識。

直譯器(Resolvers)

除非你給他們地址,否則即使是這個世界上最好的私人助理也不能去拿到乾洗衣物。

同樣的,GraphQL 服務端並不知道要對一個即將到來的查詢做什麼處理,除非你使用 resolver 來告訴他。

一個 resolver 會告訴 GraphQL 在哪裡以及如何去取到對應欄位的資料。例如,下面是之前我們取出 post 欄位例子的 resolver(使用了 Apollo 的 GraphQL-Tools ):

Query: {
  post(root, args) {
    return Posts.find({ id: args.id });
  }
}複製程式碼

在這個例子中,我們將 resolver 放在 Query 中,因為我們想要直接在根層級查詢 post。但你也可以將 resolver 放在子欄位中,例如查詢 post(文章)的 author(作者)欄位可以按照下面的形式:

Query: {
  post(root, args) {
    return Posts.find({ id: args.id });
  }
},
Post: {
  author(post) {
    return Users.find({ id: post.authorId})
  }
}複製程式碼

還有,resolver 不僅僅只能返回資料庫裡的內容,例如,如果你想為你的 Post 型別加上一個 commentsCount(評論數量)屬性,可以這麼做:

Post: {
  author(post) {
    return Users.find({ id: post.authorId})
  },
  commentsCount(post) {
    return Comments.find({ postId: post.id}).count() 
  }
}複製程式碼

理解這裡的關鍵在於:對於 GraphQL,你的 API 結構與你的資料庫結構是解耦的。換一種說法,我們的資料庫中可能根本就沒有 authorcommentsCount 這兩個欄位,但是我們可以通過 resolver 的力量將它們“模擬”出來。

正如你所見,我們可以在 resolver 中寫任何你想寫的程式碼。因此,你可以通過改變 resolver 任意地修改資料庫中的內容,這種形式也被稱為 mutation resolver。

型別(Schema)

GraphQL 的型別結構系統可以讓很多事情都變得可行。我今天的目標僅僅是給你做一個快速的概述而不是詳細的介紹,所以我不會在這個內容上繼續深入。

話雖如此,如果你想了解更多這方面的資訊,我建議你閱讀 GraphQL 官方文件

[譯] 我經常聽到的 GraphQL 到底是什麼?

常見問題

讓我們先暫停,回答一些常見的問題。

你肯定想問一些問題,來吧,儘管問別害羞!

GraphQL 與圖形資料庫有什麼關係?

它們真的沒有關係,GraphQL 與諸如 Neo4j 之類的圖形資料庫沒有任何關係。名稱中的 “Graph” 是來自於 GraphQL 使用欄位與子欄位來遍歷你的 API 圖譜;“QL” 的意思是“查詢語言”(query language)。

我用 REST 用的很開心,為什麼我要切換成 GraphQL 呢?

如果你使用 REST 還沒有碰上 GraphQL 所解決的那些痛點,那當然是件好事啦!

但是使用 GraphQL 來代替 REST 基本不會對你 app 的使用者體驗產生任何影響,所以“切換”這件事並不是所謂“生或死”的抉擇。話雖如此,我還是建議你如果有機會的話,先在專案裡小範圍地嘗試一下 GraphQL 吧。

如果我不用 React、Relay 等框架,我能使用 GraphQL 嗎?

當然能!因為 GraphQL 僅僅是一個標準,你可以在任何平臺、任何框架中使用它,甚至在客戶端中也同樣能應用它(例如,Apollo 有針對 web、iOS、Angular 等環境的 GraphQL 客戶端)。你也可以自己去做一個 GraphQL 服務端。

GraphQL 是 Facebook 做的,但是我不信任 Facebook

再強調一次,GraphQL 只是一個標準,這意味著你可以在不用 Facebook 一行程式碼的情況下實現 GraphQL。

並且,有 Facebook 的支援對於 GraphQL 生態系統來說是一件好事。關於這塊,我相信 GraphQL 的社群足夠繁榮,即使 Facebook 停止使用 GraphQL,GraphQL 依然能夠茁壯成長。

“讓客戶端自己請求需要的資料”這整件事情聽起來似乎不怎麼安全……

你得自己寫自己的 resolver,因此在這個層面上是否會出現安全問題完全取決於你。

例如,為了防止客戶端一遍又一遍地請求查詢記錄造成 DDOS 攻擊,你可以讓客戶端指定了一個 limit 引數去控制它接受資料的數量。

那麼我如何上手 GraphQL?

通常來說,一個 GraphQL 驅動的 app 起碼需要以下兩個元件:

  • 一個 GraphQL 服務端 來為你的 API 提供服務。
  • 一個 GraphQL 客戶端 來連線你的節點。

瞭解更多可用的工具,請繼續閱讀。

[譯] 我經常聽到的 GraphQL 到底是什麼?

現在你應該對 GraphQL 有了一個恰當的認識,下面讓我們來介紹一下 GraphQL 的主要平臺與產品。

GraphQL 服務端

萬丈高樓平地起,蓋起這棟樓的第一塊磚就是一個 GraphQL 服務端。 GraphQL 它本身僅僅是一個標準,因此它敞開大門接受各種各樣的實現。

GraphQL-JS (Node)

它是 GraphQL 的最初的實現。你可以將它和 express-graphql 一起使用,建立你自己的 API 服務

GraphQL-Server (Node)

Apollo 團隊也有他們自己的一站式 GraphQL 服務端實現。它雖然還沒有像 GraphQL-JS 一樣被廣泛使用,但是它的文件、支援都做得很棒,使用它能快速取得進展。

其它平臺

GraphQL.org 列了一個清單: GraphQL 在其它平臺下的實現清單 (包括 PHP、Ruby 等)。

GraphQL 客戶端

雖然你不使用客戶端類庫也可以很好地查詢 GraphQL API,但是一個相對應的客戶端類庫將會讓你的開發更加輕鬆

Relay

Relay 是 Facebook 的 GraphQL 工具。我還沒用過它,但是我聽說它主要是為了 Facebook 自己的需求量身定做的,可能對大多數的使用者來說不是那麼人性化。

Apollo Client

在這個領域的最新參賽者是 Apollo,它正在迅速發展。典型的 Apollo 客戶端技術棧由以下兩部分組成:

另外,在預設的情況下 Apollo 客戶端使用 Redux 儲存資料。這點很棒,Redux 本身是一個有著豐富生態系統的超棒的狀態管理類庫。

[譯] 我經常聽到的 GraphQL 到底是什麼?

Apollo 在 Chrome 開發者工具中的外掛

開源 App

雖然 GraphQL 還屬於新鮮事物,但是它已經被一些開源 app 使用了。

VulcanJS

[譯] 我經常聽到的 GraphQL 到底是什麼?

首先我得宣告一下,我是 VulcanJS 的主要維護者。我建立 VulcanJS 是為了讓人們在不用寫太多樣板程式碼的情況下充分享受 React、GraphQL 技術棧的好處。你可以把它看成是“現代 web 生態系統的 Rails”,讓你可以在短短几個小時內做出你的 CRUD(增刪查改)型 app。(例如 Instagram clone

Gatsby

Gatsby 是一個 React 靜態網站生成器,它現在是基於 GraphQL 1.0 版本 開發。它一眼看上去像個奇怪的大雜膾,但其實它的功能十分強大。Gatsby 在構建過程中,可以從多個 GraphQL API 取得資料,然後用它們建立出一個全靜態的無後端 React app。

其它的 GraphQL 工具

GraphiQL

GraphiQL 是一個非常好用的基於瀏覽器的 IDE,它可以方便你進行 GraphQL 端點查詢。

[譯] 我經常聽到的 GraphQL 到底是什麼?

GraphiQL

DataLoader

由於 GraphQL 的查詢通常是巢狀的,一個查詢可能會呼叫很多個資料庫請求。為了避免影響效能,你可以使用一些批量出入庫框架和快取庫,例如 Facebook 開發的 DataLoader。

Create GraphQL Server

Create GraphQL Server 是一個簡單的命令列工具,它能快速地幫你搭建好基於 Node 服務端與 Mongo 資料庫的 GraphQL 服務端。

GraphQL 服務

最後,這兒列了一些 GraphQL BAAS(後臺即服務)公司,它們已經為你準備好了服務端的所有東西。這可能是一個讓你嘗試一下 GraphQL 生態系統的很好的方式。

GraphCool

一個由 GraphQL 和 AWS Lambda 組成的一個彈性後端平臺服務,它提供了開發者免費計劃。

Scaphold

另一個 GraphQL BAAS 平臺,它也提供了免費計劃。與 GraphCool 相比,它提供了更多的功能。(例如定製使用者角色、常規操作的回撥鉤子等)

[譯] 我經常聽到的 GraphQL 到底是什麼?

下面是一些能讓你學習 GraphQL 的資源。

GraphQL.org

GraphQL 的官方網站,有許多很好的文件供你學習。

LearnGraphQL

LearnGraphQL 是由 Kadira 員工共同製作的課程。

LearnApollo

LearnApollo 是由 GraphCool 製作的免費課程,是對於 LearnGraphQL 課程的一個很好的補充。

Apollo 部落格

Apollo 的部落格有成噸的乾貨,有很多關於 Apollo 和 GraphQL 的超棒的文章。

GraphQL 週報

由 Graphcool 團隊策劃的一個簡報,其內容包括任何有關 GraphQL 的資訊。

Hashbang 週報

另一個不錯的簡報,除了 GraphQL 的內容外,還涵蓋了 React、Meteor。

Awesome GraphQL

一個關於 GraphQL 的連結和資源的很全面的清單。

[譯] 我經常聽到的 GraphQL 到底是什麼?

你如何實踐你剛學到的 GraphQL 的知識呢?你可以嘗試下面這些方式:

Apollo + Graphcool + Next.js

如果你對 Next.js 與 React 很熟悉,這個例子將會幫助你使用 Graphcool 很快的搭建好你的 GraphQL 端點,並在客戶端使用 Apollo 進行查詢。

VulcanJS

Vulcan 教程將會引導你建立一個簡單的 GraphQL 資料層,既有服務端部分也有客戶端部分。因為 Vulcan 是一個一站式平臺,所以這種無需任何配置的方式是一種很好的上手途徑。如果你需要幫助,請訪問我們的 Slack 欄目

GraphQL & React 教程

Chroma 部落格有一篇《分為六部的教程》,講述瞭如何按照元件驅動的開發方式來構建一個 React/GraphQL app。

[譯] 我經常聽到的 GraphQL 到底是什麼?

總結

當你剛開始接觸 GraphQL 可能會覺得它非常複雜,因為它橫跨了現代軟體開發的眾多領域。但是,如果你稍微花點時間去明白它的原理,我認為你可以找到它很多的可取之處。

所以不管你最後會不會用上它,我相信多瞭解瞭解 GraphQL 是值得的。越來越多的公司與框架開始接受它,過幾年它可能會成為 web 開發的又一個重要組成部分。

贊同?不贊同?有疑問?請留下評論讓我們知道你的看法。如果你還比較喜歡這篇文章,請點亮?或者分享給他人。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOSReact前端後端產品設計 等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃

相關文章