【譯】GraphQL 初學者指南
- 原文地址:A Beginner’s Guide to GraphQL
- 原文作者:Leonardo Maldonado
- 專案倉庫:GraphQL-Guide-For-Beginner
- 譯者:Seymoe
- 譯者注:此文為本人第一篇譯文,本人作為無 GraphQL 使用背景的初學者,翻譯過程亦是學習過程。如果發現譯文有錯誤或者表述不當的地方敬請指正,十分感謝!
API 是網際網路行業討論最多的術語之一,但是很多人並不確切知道 API 到底是什麼。基本上,API 代表應用程式程式設計介面(Application Programming Interface)
你可以理解為 API 就像是個酒保,你向酒保要一杯酒,他便把一杯你想要的酒遞給你,看起來很簡單的事,還有什麼問題呢?
構建 API 不是一件困難的事,但學習和理解具體的 API 可能存在一定的困難。多數開發者都會使用你的 API 去開發功能或者只是消費資料,這就要求 API 需要儘可能保持乾淨、直觀。精心設計、直觀性強的 API 會非常容易理解和使用。
一直以來,我們都在用 REST 來構建 API,使用這種方式會存在一些問題,例如:
- 多端點
- 開發人員學習理解 API 的成本比較高
- API 的資訊過度和資訊不足問題
為了解決以上的類似問題,Facebook 創造了 GraphQL。我認為 GraphQL 是當代構建 API 的最佳方式,本文將闡述為什麼你應該開始學習 GraphQL,讓你瞭解 GraphQL 的工作原理,以及如何使用 GraphQL 建立設計精良、高效並且功能強大的 API。
你可能已經聽說過 GraphQL,因為很多開發者和公司都在使用它。由於 GraphQL 是開源的,所以社群也是很龐大的存在。讓我們在實踐中學習 GraphQL 的工作原理,領略它的魔力了。
什麼是GraphQL?
GraphQL (譯者注:中文文件)是 Facebook 開發的一種開源查詢語言。它為我們提供了一種更有效的方式來設計、建立和消費我們的 API 。基本上,它是 REST 的替代品。
GraphQL 有很多功能,例如:
- 我們可以編寫自己所需的資料,並獲得所需的資料。不用再像我們習慣使用的 REST 那樣過度獲取資訊。
- GraphQL 為我們提供了單個端點,不再為同一 API 提供版本2或版本3。
- GraphQL 是強型別的,所以我們可以在執行之前在 GraphQL 型別系統中驗證查詢。有助於構建更強大的 API。
這是對 GraphQL 的基本介紹,解釋了為什麼它如此強大以及為什麼它如今獲得了很多人氣。如果想了解更多相關資訊,我建議訪問 GraphQL 網站去了解。
入門
本文主要目的不是學習如何配置 GraphQL 伺服器,所以我們現在不會深入研究。本文的目標是瞭解 GraphQL 在實踐中的工作原理,因此我們將使用一個叫做☄️Traderpack的零配置GraphQL伺服器庫。
第一步,我們需要建立一個新資料夾,你可以隨意命名。我將它命名為 graphql-server :
mkdir graphql-server
複製程式碼
假定你已經在自己的機器中安裝了 npm 或 yarn。如果你不知道它們是什麼,npm 和 yarn 是 JavaScript 程式語言的包管理器。對於 Node.js,預設包管理器是 npm。
在建立的資料夾中,輸入以下命令:
npm init -y
複製程式碼
如果你使用 yarn :
yarn init
複製程式碼
npm 會建立一個 package.json
檔案,專案安裝的所有依賴項和命令都在這個檔案中。
接下來,我們來安裝本專案要使用的唯一依賴項,☄️Traderpack 允許你建立零配置的 GraphQL 伺服器。由於我們剛剛開始使用 GraphQL,這將幫助我們繼續學習更多內容,而不必擔心伺服器配置。
開啟終端進入專案資料夾,鍵入以下命令:
npm install --save-dev graphpack
複製程式碼
如果你使用 yarn,應該這樣:
yarn add --dev graphpack
複製程式碼
安裝 Graphpack 之後,轉到 package.json
檔案中的指令碼,並在其中輸入以下程式碼:
"scripts": {
"dev": "graphpack",
"build": "graphpack build"
}
複製程式碼
我們將建立一個名為 src 的資料夾作為整個伺服器中唯一的資料夾,然後在 src 資料夾中建立三個檔案。
譯者注:使用 VSCode 的童鞋可以安裝 `GraphQL for VSCode` 外掛進行語法高亮
首先,我們建立第一個檔案,名叫 schema.graphql
,並在這個檔案中輸入以下程式碼:
type Query {
hello: String
}
複製程式碼
這個 schema.graphql
檔案將是我們的整個 GraphQL 架構,稍後我會解釋它的作用。
接下來,在 src 資料夾中建立第二個檔案 resolvers.js
,並在這個檔案中輸入以下程式碼:
import { users } from "./db"
const resolvers = {
Query: {
hello: () => "Hello World!"
}
}
export default resolvers
複製程式碼
這個 resolvers.js
檔案將是我們提供將 GraphQL 操作轉換為資料的指令的方式。
最後,在src資料夾中建立第三個檔案 db.js
,並在這個檔案中輸入以下程式碼:
export let users = [
{ id: 1, name: "John Doe", email: "[email protected]", age: 22 },
{ id: 2, name: "Jane Doe", email: "[email protected]", age: 23 }
]
複製程式碼
在本教程中,我們沒有使用真實資料庫。所以這個 db.js
檔案將模擬資料庫,僅用於學習目的。
現在我們的src資料夾應如下所示:
src
|--db.js
|--resolvers.js
|--schema.graphql
複製程式碼
現在,如果你執行命令 npm run dev
,或者如果你正在使用yarn,則執行 yarn dev
,應該在終端中看到此輸出:
現在可以用瀏覽器開啟 localhost:4000
,這意味著我們已準備好開始在 GraphQL 中編寫我們的第一個 queries(查詢),mutations(突變)和 subscriptions(訂閱)。
如果感興趣可以看看 GraphQL Playground,這是一個功能強大的 GraphQL IDE,可用於更好的開發工作流程。如果你想了解有關 GraphQL Playground 的更多資訊,請單擊此處。
Schema
GraphQL 有自己的語言型別,用於編寫 Schema(模式)。這是一種人類可讀的模式語法,稱為 Schema Definition Language - 模式定義語言(SDL)。無論使用何種技術,SDL都是相同的 - 你可以將其用於你想要的任何語言或框架。這種模式語言非常有用,因為它會讓你很容易直觀的理解你的 API 將具有哪些型別。
Types
Types(型別)是 GraphQL 最重要的特性之一。Types 是自定義物件,表示 API 的外觀。舉個例子,如果你正在構建社交媒體應用程式,那麼你的 API 可能會有 Posts
、Users
、Likes
、Groups
等 Types。
Types 下有 fields(欄位),這些欄位返回特定型別的資料。例如,我們要建立一個 User 型別,我們應該有 name
、email
和 age
等欄位。欄位可以是任何型別,並始終返回一種資料型別,比如 Int、Float、String、Boolean、ID、物件型別列表或自定義物件型別。
現在編寫我們的第一個 Type,轉到 schema.graphql
檔案並用以下內容替換已存在的 Query
型別:
type User {
id: ID!
name: String!
email: String!
age: Int
}
複製程式碼
每個 User
都將擁有一個 ID
,因此我們為其提供了 ID
型別。User
也會有一個 name
和 email
,所以我們給它們 String
型別,年齡我們給了 Int
型別。很簡單吧?
資料型別後面的 !
表示該欄位非空(non-nullable),這意味著這些帶 !
的欄位必須在每個查詢中返回一些資料。
在 GraphQL 中有三個主要概念:
- 查詢(queries) - 從伺服器獲取資料
- 突變(mutations) - 修改伺服器上的資料並獲取更新資料(建立,更新,刪除)
- 訂閱(subscriptions) - 與伺服器保持實時連線
這三個主要概念我會一一解釋。
Queries
簡單來說,GraphQL 中的查詢就是獲取資料的方式。GraphQL 中的查詢會獲得所需的確切資料。不多也不少。這對我們的 API 產生了巨大的積極影響 - 不再像我們使用 REST API 那樣過度獲取或提取不足資訊。
讓我們來中建立一個查詢型別,首先,在 schema.graphql
中新增一個名為 Query
的新型別:
type Query {
users: [User!]!
}
複製程式碼
users
查詢將返回給我們一個或多個使用者的陣列。它不會返回 null
,因為我們在後面加了 !
,這意味著它是一個不可為空的查詢,應該總是返回一些東西。
既然能返回多個,我們也能返回一個特定使用者,在 Query
型別中新增一個新的查詢 user
:
type Query {
users: [User!]!
+ user(id: ID!): User!
}
複製程式碼
你會發現查詢能夠傳遞引數,查詢特定使用者的時候把使用者的 id
作為引數傳入。
那麼 GraphQL 如何知道去哪獲取到資料返回呢?這就是 resolvers.js
的作用,它會告訴 GraphQL 如何以及在何處獲取資料。
開啟 resolvers.js
檔案,更改一下程式碼:
import { users } from "./db"
const resolvers = {
Query: {
user: (parent, { id }, context, info) => {
return users.find(user => user.id === id)
},
users: (parent, args, context, info) => {
return users
}
}
}
export default resolvers
複製程式碼
解釋一下以上程式碼是如何工作的:
- 每個查詢解析器都有四個引數。在
user
函式中,我們將id
作為引數傳遞,然後返回與傳遞的id
匹配的特定使用者 - 在
users
函式中,我們只是返回已存在的users
陣列,它會返回所有的使用者
現在,我們將測試我們的查詢是否正常工作。瀏覽器開啟 localhost:4000
,在左邊輸入以下程式碼然後點執行按鈕:
query {
users {
id
name
email
age
}
}
複製程式碼
試試返回 id 為 1 的使用者:
query {
user(id: 1) {
id
name
email
age
}
}
複製程式碼
Mutations
在 GraphQL 中,Mutations 是修改伺服器上的資料並獲取更新資料的方式。你可以理解為類似 REST 的CUD(CREATE,UPDATE,DELETE)。
我們來建立一個型別突變,我們所有的突變都將在這種型別中結束。在 schema.graphql
檔案中編寫一個名為 mutation
的新型別:
type Mutation {
createUser(id: ID!, name: String!, email: String!, age: Int): User!
updateUser(id: ID!, name: String, email: String, age: Int): User!
deleteUser(id: ID!): User!
}
複製程式碼
上述程式碼建立了三個 Mutation:
createUser
- 我們傳入的引數id
、name
、email
、age
,應該返回一個新的使用者updateUser
- 傳入id
和新的name
、email
與age
, 應該返回一個更新後的使用者deleteUser
- 傳入id
,應該返回被刪除掉使用者的資訊
現在,我們去 resolvers.js
檔案中,在 Query
物件下方插入一個新的 Mutation
物件。
Mutation: {
createUser: (parent, { id, name, email, age }, context, info) => {
const newUser = { id, name, email, age }
users.push(newUser)
return newUser
},
updateUser: (parent, { id, name, email, age }, context, info) => {
let newUser = users.find(user => user.id === id)
newUser.name = name
newUser.email = email
newUser.age = age
return newUser
},
deleteUser: (parent, { id }, context, info) => {
const userIndex = users.findIndex(user => user.id === id)
if (userIndex === -1) throw new Error("User not found.")
const deletedUsers = users.splice(userIndex, 1)
return deletedUsers[0]
}
}
複製程式碼
該去 localhost:4000
看看我們寫的 Mutations 是否有效了,在頁面上輸入:
mutation {
createUser(id: 3, name: "Robert", email: "[email protected]", age: 21) {
id
name
email
age
}
}
複製程式碼
你也可以嘗試一下其他的 Mutation。
Subscriptions
正如我之前所說,Subscriptions (訂閱)是你與伺服器保持實時連線的方式。這意味著無論何時在伺服器中發生事件,並且每當呼叫該事件時,伺服器都會將相應的資料傳送到客戶端。通過使用訂閱,你可以將應用程式更新為不同使用者之間的最新更改。
最基本的訂閱示例:
subscription {
users {
id
name
email
age
}
}
複製程式碼
你會說它與查詢非常相似,但它的工作方式和查詢不同。當伺服器中的某些內容更新時,伺服器將執行訂閱中指定的 GraphQL 查詢,並將更新的結果傳送到客戶端。我並不打算在這篇文章中使用訂閱,但如果你想了解更多關於它們的資訊,請點選此處。
總結
如你所見,GraphQL 是一項非常強大的新技術。它為我們提供了構建更好和精心設計的 API 的真正能力。這就是為什麼我建議你現在開始學習它。
對我來說,它最終將取代 REST。
感謝閱讀文章,請在下面發表評論!