跳至主要内容

[note] GraphQL

Query

GraphQL Playground

Fields

要透過 graphQL API 查詢的欄位名稱,稱作 "Fields",例如下面的 idcompleted

{
todo(id: 3) {
id
completed
}
}

Arguments

todos(<arguments>) 中的參數稱作 arguments:

{
todos(options: { slice: { limit: 5 } }) {
data {
id
title
}
}
}

Operation Name

一般單純的 query 可以直接使用 {},但這算是簡寫,在 production App's 中,一般會包含 operation typeoperation name

以下面的例子來說,query 這個 keyword 就是 operation type;GetTodoById 就是 operation name:

query GetTodoById {
todo(id: 3) {
id
completed
}
}
operation type

Operation type 除了 query 之外,還包含 mutationsubscription 等用來描述操作意圖的關鍵字。

operation name

Operation name 就類似 function name,它可以方便我們後續 debug 或 log 使用。

Variables

未來避免 client-side 需要在 runtime 時,根據使用者提供的資料來動態改變 query string,並轉換成 GraphQL 的格式,在 GraphQL 中提供動態 query 的方式,稱作 variables,如此也可以明確知道在 query 中的哪些 arguments 會是動態變化的。

使用 $ 當作 prefix 可以定義變數,並把定義好的變數,帶入 query 中:

query getUserById($id: ID!) {
user(id: $id) {
id
username
email
company {
name
}
}
}

如此,在 client-side 使用時,只需要帶入不同的變數,而不需要重新組出一個完整的 query:

{
"id": "2"
}

另外,有需要的話,也可以提供預設值給 variables,例如這裡的 $id: ID! = 2,使用時如果沒有指定 id 的話,就會使用預設值:

query getUserById($id: ID! = 2) {
user(id: $id) {
id
username
email
}
}

Fragments

Fragments 指的是可以被重複使用的 query,語法是 fragment [fragment_name] on [type]

query getUsers {
users(options: { slice: { limit: 5 } }) {
data {
# 在 query 中使用定義好的 fragment
...UserFields
}
}
}

# 先定義好 fragment
fragment UserFields on User {
name
username
email
}

Directives

在 GraphQL 中目前提供 @include(if: Boolean)@skip(if: Boolean) directives 來動態「帶入」或「略過」特定的 Fields 或 Fragments:

query GetUsers($limit: Int = 10, $withCompany: Boolean = false) {
users(options: { slice: { limit: $limit } }) {
data {
id
name
# 當 $withCompany 是 true 是才多 query company 這個欄位
company @include(if: $withCompany) {
name
}
}
}
}

使用 Variables:

{
"limit": 5,
"withCompany": true
}

需要的話,也可以在 Fragments 中使用 Directives:

query GetUsers($limit: Int = 10, $withCompany: Boolean = false) {
users(options: { slice: { limit: $limit } }) {
data {
...UserFields
}
}
}

fragment UserFields on User {
id
name
# 當 $withCompany 是 true 是才多 query company 這個欄位
company @include(if: $withCompany) {
name
}
}

Mutation

使用 mutation 來做會改變(mutate)資料的操作:

mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) {
id
title
body
}
}

Schema First vs. Code First

和開發 Restful API 時一樣,開發 GraphQL 也會遇到應該要「先定義好 API 格式」再來開始實作,或是「先實作程式邏輯」再根據實作的程式產出 Open API Schema。

採用 Schema First:

  • 先定義好 GraphQL 的 SDL(Schema Definition Language)後才進入開發
  • 優點:先把要做的事情、規劃想清楚,而不是邊做邊想
  • 優點:先訂好 schema 的話,可以讓其他團隊(例如 FE)提早開始根據這份 schema 來開發
  • 缺點:有可能最終實作的程式邏輯和這份訂好的 schema 不一致,也就是未來有可能發生「程式改了,但文件忘了改」的情況

採用 Code First:

  • 直接進入程式開發,Schema 則是根據寫好的程式一併產出
  • 優點:程式和文件能一直保持一致,不會有忘了更新文件的問題
  • 優點:較容易定義更複雜的關聯
  • 缺點:可能會 block 到其他團隊的開發,因為要等 BE 實作完後,才能拿到 schema