[note] GraphQL
Query
- GraphQLZero:website、playground
- Queries and Mutations @ graphQL
Fields
要透過 graphQL API 查詢的欄位名稱,稱作 "Fields",例如下面的 id
、completed
:
{
todo(id: 3) {
id
completed
}
}
Arguments
在 todos(<arguments>)
中的參數稱作 arguments:
{
todos(options: { slice: { limit: 5 } }) {
data {
id
title
}
}
}
Operation Name
一般單純的 query 可以直接使用 {}
,但這算是簡寫,在 production App's 中,一般會包含 operation type
和 operation name
。
以下面的例子來說,query
這個 keyword 就是 operation type;GetTodoById
就是 operation name:
query GetTodoById {
todo(id: 3) {
id
completed
}
}
Operation type 除了 query
之外,還包含 mutation
、subscription
等用來描述操作意圖的關鍵字。
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