GraphQL 變數用法完整指南:從入門到實作
更新日期: 2025 年 6 月 10 日
在學習 GraphQL 的初期,我們常常會直接把參數值寫在查詢語法中,例如:
query {
getUser(id: "123") {
name
email
}
}
這樣雖然可以正確執行,但隨著專案變大,這種寫法會出現以下問題:
- ❌ 查詢語法與參數綁死,無法重複利用
- ❌ 每次參數不同就得改語法,不利測試與快取
- ❌ 不利於與前端框架整合,像 React、Vue
✅ GraphQL 變數系統就是為了解決這些問題而設計的!
它讓你可以將查詢邏輯與參數拆開,讓查詢語法更彈性、更乾淨、也更容易管理。
GraphQL 查詢語法的三個組成部分
當我們在 GraphQL 中使用變數時,整體的查詢邏輯會被分成三個主要部分,這三個部分各司其職,搭配起來才能正確執行查詢:
Operation 定義區塊(Operation Definition)
這個區塊是 GraphQL 查詢的開頭,用來定義這次的操作類型(如 query 或 mutation)、操作名稱(Operation Name),以及你要用到的變數。
query GetUser($id: ID!)
這行的意思是:
query
:代表這是一個讀取資料的查詢(還有mutation
與subscription
)GetUser
:這是這段查詢的名稱(Operation Name)($id: ID!)
:宣告了一個名為$id
的變數,它的型別是ID
,且是「必填」的(因為有!
)
✅ 重點:變數一定要在 Operation 區塊「先宣告」,才能在後面使用!
在 GraphQL 中,變數是一種外部傳入的資料,不像 JavaScript 可以直接在程式中宣告變數再使用。
GraphQL 查詢是一種嚴謹的語言,它必須在「查詢開頭的 Operation 區塊」明確宣告你要使用哪些變數、每個變數的名稱是什麼、型別是什麼、是否必填,這樣執行引擎才會知道如何處理。
🔧 如果你沒有先宣告會發生什麼事?
假設你寫了這段查詢:
query {
getUser(id: $id) {
name
}
}
但沒有宣告 $id
,系統會回傳類似以下錯誤:
"Variable \"$id\" is not defined."
也就是說,GraphQL 無法處理一個沒被宣告的變數,因為它不知道 $id
是什麼型別、是否必填、該怎麼驗證。
📘 正確的做法:在 Operation 定義中宣告變數
query GetUser($id: ID!) {
getUser(id: $id) {
name
}
}
在這裡,我們宣告了:
$id
是變數名稱ID
是變數的型別(通常是識別碼)!
表示這個變數是必填的,不能傳null
或不傳
一旦這樣宣告,後面的查詢主體就能安全地使用 $id
,而 GraphQL 執行引擎也能幫你自動做類型檢查與驗證。
❓補充:要使用變數就一定要定義 Operation Name 嗎?
不是一定要!但有強烈建議。
✅ 不一定需要 Operation Name
以下這樣也是合法語法,可以執行:
query ($id: ID!) {
getUser(id: $id) {
name
email
}
}
這樣的寫法「省略了 Operation Name」,仍可正常使用變數,但查詢沒有名字。
⚠️ 為什麼建議加上 Operation Name?
加上 Operation Name 有以下幾個好處:
- 📦 方便除錯與追蹤:伺服器錯誤時會告訴你是哪個 operation 出錯
- 🔁 支援多個查詢或 Mutation 並存時,可以指定要執行哪一個
- 📋 提高可讀性與維護性,讓查詢的意圖更清楚
因此在實務開發中,尤其是多人協作或大型專案,幾乎都會加上 Operation Name。
查詢主體區塊(Query Body):查詢的核心執行內容
查詢主體區塊是 GraphQL 語法中最關鍵的部分,這裡定義了你到底要從伺服器拿哪些資料、要哪些欄位,以及查詢時要用什麼參數來篩選。
這部分是 GraphQL 的靈魂,也是與 REST 最大不同的地方 —— 你可以精確選擇資料欄位,而不是整包回傳。
✅ 查詢主體的範例
{
getUser(id: $id) {
name
email
}
}
這段語法代表:
- 執行
getUser
查詢(這是一個由後端 Schema 定義的查詢) - 透過參數
id
,傳入一個變數$id
(這個$id
是在 Operation 區塊定義好的變數) - 回傳的資料只包含
name
和email
這兩個欄位(可以自由決定欄位,不必拿整包)
為什麼這裡要用變數?
你也可以直接這樣寫:
{
getUser(id: "123") {
name
email
}
}
這樣雖然查得出來資料,但:
寫法 | 問題點 |
---|---|
id: "123" | 寫死在查詢中,無法動態修改資料 |
$id | 可以從外部傳入,讓查詢具有彈性與重複性 |
所以使用 $id
變數可以將查詢語法模板化、標準化、易於重用與測試。
變數傳入區塊(Variables Payload):執行查詢時注入參數
這一區塊雖然不寫在 GraphQL 語法裡,但卻是讓變數生效的關鍵橋梁。
它是在實際執行查詢時,傳入變數對應的值。
✅ 傳入變數的格式(JSON)
{
"id": "123"
}
這代表:
- 在查詢語法中宣告了
$id
,這裡把它實際設定為字串"123"
- GraphQL 執行引擎會在處理查詢時,自動把
$id
替換成"123"
🛠 常見使用情境
工具/框架 | 傳入方式 |
---|---|
GraphQL Playground | 下方的 Query Variables 區塊 |
Apollo Client | 透過 variables 屬性傳入 |
Postman | 在 body 的 variables 欄位傳入 |
fetch/Axios | 以 JSON 傳入 variables 欄位 |
常見資料型別與寫法
在使用 GraphQL 撰寫查詢與 mutation 時,變數是不可或缺的一環。
而這些變數都需要明確指定型別(type),這是 GraphQL 的一大特性:型別強制且嚴謹。
為什麼 GraphQL 要指定型別?
- ✅ 強型別幫助你在查詢前就發現錯誤(例如傳錯型別)
- ✅ API 自動產生文件(Schema)更清楚
- ✅ 編輯器有 IntelliSense,自動補全更方便
- ✅ 能與 TypeScript 等靜態型別系統無縫整合
常見內建型別與用法
型別 | 說明與使用情境 | 範例變數傳入值 |
---|---|---|
String | 一般文字、使用者名稱、電子信箱、備註內容等 | "[email protected]" |
Int | 整數數字,例如:年齡、頁數、數量等 | 28 |
Float | 浮點數,例如:價格、小數比例、評分等 | 3.14 |
Boolean | 布林值,用於開關、是否啟用、是否為管理員等二元邏輯判斷 | true 或 false |
ID | 唯一識別碼,通常用於資料庫主鍵、使用者 ID、文章 ID 等(實際上是 String) | "user_8237" |
[String] | 字串陣列,例如搜尋多個關鍵字、標籤清單、輸入多個 Email 等 | ["foo", "bar", "baz"] |
複合型別:自定義輸入物件(Input Type)
除了上面內建型別外,GraphQL 也支援自定義輸入物件(Custom Input Object),常用於 mutation 中一次傳入多個欄位。
✅ 宣告方式(後端)
input CreateUserInput {
name: String!
email: String!
age: Int
}
✅ 使用方式(前端)
查詢語法:
mutation CreateUser($input: CreateUserInput!) {
createUser(input: $input) {
id
name
}
}
變數傳入值:
{
"input": {
"name": "小明",
"email": "[email protected]",
"age": 18
}
}
這種方式非常適合表單資料送出,讓 mutation 更簡潔、易維護。
❗什麼是 !
?為什麼要加在型別後面?
在 GraphQL 中,每個變數型別都可以加上或不加 !
,這會決定該變數是否為必填欄位。
寫法 | 意義 | 可否傳 null 或不傳 |
---|---|---|
String! | 必填欄位,一定要傳值且不可為 null | ❌ 不可省略或為 null |
String | 選填欄位,可以傳 null 或不傳入 | ✅ 可以省略或傳 null |
🔍 延伸補充:
[String!]!
是什麼意思?
- 外層的
!
:陣列本身不能是null
- 內層的
!
:陣列中的每一個元素都不能是null
✅ 這樣可以確保傳進來的是一個「完整且沒有空值」的清單
前端如何傳遞變數?(以 React + Apollo Client 為例)
在前端專案中,我們通常不會手動組裝 GraphQL 字串和變數,因為這樣容易出錯又難維護。
這時候可以使用 Apollo Client 這類專門的 GraphQL 前端工具,它幫我們:
- 📦 自動管理變數注入
- 🚀 發送請求到後端 GraphQL Server
- ✅ 處理回傳資料與錯誤
讓我們先看一段基本範例:
const GET_USER = gql`
query GetUser($id: ID!) {
getUser(id: $id) {
name
email
}
}
`;
const { data, loading, error } = useQuery(GET_USER, {
variables: { id: "123" }
});
這段程式碼可分為兩大部分:
gql
標記的 GraphQL 查詢語法
const GET_USER = gql`
query GetUser($id: ID!) {
getUser(id: $id) {
name
email
}
}
`;
這裡用 gql
函式標記了一段查詢語法,它是 Apollo 提供的函數,用來讓 JavaScript 理解這段字串是 GraphQL 查詢。
GetUser
是查詢的名稱(方便除錯與追蹤)$id
是查詢中要使用的變數getUser(id: $id)
是實際執行查詢並插入變數的地方
📌 這段查詢語法就像是一個「待執行的模板」,變數還沒真正填進去。
使用 useQuery()
傳入變數並執行查詢
useQuery(GET_USER, {
variables: { id: "123" }
});
這裡是查詢的實際執行點:
GET_USER
:剛剛定義好的查詢語法模板variables
:是一個物件,裡面定義了每個變數名稱與對應值- 在這裡就是傳入
id: "123"
,讓$id
變數有值可以使用
可視化理解:就像呼叫一個函數
你可以把整個過程想像成下面這樣:
function getUserData(id) {
return getUser(id);
}
// 呼叫函數時傳入參數
getUserData("123");
在 GraphQL 的世界中:
- 查詢語法是函數定義(有變數)
useQuery()
是呼叫函數(傳入變數)
延伸:變數可以是多個欄位嗎?
const GET_USERS = gql`
query GetUsers($ids: [ID!]!) {
users(ids: $ids) {
id
name
}
}
`;
useQuery(GET_USERS, {
variables: { ids: ["123", "456", "789"] }
});
只要你在查詢語法裡有宣告變數(無論是單一值還是陣列、自訂輸入物件),都可以用 variables
一次性傳入。
結語:養成「變數優先」的查詢習慣
在初學 GraphQL 時,直接寫死參數是正常的起步方式,但隨著功能變多、畫面變複雜,學會使用變數能大幅提升你的查詢彈性與維護性。
現在就試著把你手上的查詢改寫成使用變數的方式,體驗乾淨、簡潔又強大的 GraphQL 查詢流程吧!