GraphQL 前端請求完整指南:HTTP 傳輸原理與變數(Variables)用法解析
更新日期: 2025 年 6 月 10 日
GraphQL 作為現代 API 設計的代表,不再像傳統 REST API 一樣,每個資源對應一條 endpoint,而是透過一個統一的入口,讓前端自行描述需要的資料結構。
這種靈活性大幅提升了開發效率,但也讓不少初學者在剛上手時產生疑問:
- 「GraphQL 到底是怎麼送出請求的?」
- 「為什麼只有一個 endpoint?」
- 「我看到
variables
,那是什麼?為什麼查詢還要分兩個欄位?」
本文將一步步帶你理解 GraphQL 前端請求的基本原理與實作方式,讓你不再只是「會貼範例碼」,而是真正理解 GraphQL 背後的請求邏輯與變數系統。
GraphQL 是透過 HTTP 發送請求的嗎?你其實早就會用了
如果你之前有寫過 REST API,一定知道怎麼用 fetch()
或 Axios 發送 HTTP 請求:
指定一個 URL,決定是 GET 還是 POST,然後帶上一些資料,最後等後端回應。
GraphQL 也是這樣。真的,一模一樣。
GraphQL 就是用 HTTP,而且幾乎都是 POST
GraphQL 不是什麼神祕的新技術,它只是一種「查資料的語法」,而真正把查詢送出去的方式,跟你用 REST 時一樣,是透過 HTTP 協定。
- 你會看到一個統一的網址(例如
https://api.example.com/graphql
) - 然後前端把想查什麼資料寫成一段查詢語法(例如
query { users { name } }
) - 最後把這段語法包成 JSON,放進 POST 請求的 body 裡送出
簡單說,GraphQL 把「我要什麼資料」這件事交給你用文字寫清楚,就像在寫一段語意完整的資料請求信。
而不是像 REST API 那樣,每個資源寫死在網址裡,前端只管敲指定路由、拿到固定格式的資料。
這種設計上的差異,會直接影響前端開發的方式與資料處理的彈性。
GraphQL 與 REST:從「發送的 HTTP 請求內容」看出核心差異
在實務開發中,我們經常使用 HTTP 請求向後端拿資料。
雖然 REST 和 GraphQL 最終都是透過 HTTP 溝通,但它們在請求的結構、欄位內容與資料組織方式上有本質差異。
這些差異不只影響前端如何撰寫程式,也直接關係到請求的彈性、維護性與資料效率。
📦 請求格式差異:REST vs GraphQL 對照表
項目 | REST API 請求格式 | GraphQL 請求格式 |
---|---|---|
請求方法 | 通常依資源操作選擇 GET、POST、PUT、DELETE | 大多數查詢用 POST(也可 GET),一律發送至 /graphql |
URL 結構 | 一個資源對應一條路徑,如 /users/123 | 所有查詢共用同一 URL,如 /graphql |
參數傳遞方式 | 放在 URL path、query string 或 body | 放在 variables 欄位中 |
查詢內容的位置 | 路徑本身代表資源、資料結構由後端決定 | 資料結構描述寫在 query 欄位,由前端主動定義 |
請求 body 格式 | 通常是 JSON(for POST),欄位固定 | JSON 格式,包含 query 和 variables 兩大欄位 |
🔍 請求內容實例比較
🧭 REST API 請求(查詢 ID 為 123 的使用者)
GET /users/123
Host: api.example.com
REST 把資源的類型與識別寫死在 URL 裡,通常請求不帶 body(除非是 POST)。
🧩 GraphQL 請求(查詢 ID 為 123 的使用者)
POST /graphql
Host: api.example.com
Content-Type: application/json
{
"query": "query GetUser($id: ID!) { user(id: $id) { name email } }",
"variables": {
"id": "123"
}
}
GraphQL 把資料結構與參數分別寫在
query
和variables
裡。前端可以自由控制要哪些欄位,不需要改變 endpoint。
重點總結:GraphQL 請求的「語意」比 URL 更重要
REST 是「路徑導向」的 API 設計,URL 決定你能取得什麼資料,資料格式也由後端定義。
這種方式簡單直觀,但一旦前端需求變動,就必須調整新的路由或欄位格式。
而 GraphQL 則是「語意導向」,請求本體是你在 query
中描述的內容,不管你要查一筆、查多筆、查欄位 A 還是欄位 B,都透過同一個 endpoint 傳送,差別只在你怎麼寫查詢語法。
這不只讓前端開發更有彈性,也讓 API 設計更具一致性與可擴展性。
那 GraphQL 的請求內容長什麼樣子?來看完整結構與實作範例
在 GraphQL 中,無論你是要查一筆資料還是多筆資料,前端傳送給後端的內容其實都很固定——就是一個 JSON 格式的物件,裡面包含兩個最核心的欄位:query
和 variables
。
這個請求會被放在 HTTP POST 的 body 中,然後一起送往後端的 /graphql
端點。
請求結構長這樣:
{
"query": "query { users { id name } }",
"variables": {}
}
看起來是不是比想像中簡單?雖然查詢語法可以很複雜,但傳輸的格式始終保持一致,就是這兩個欄位:
欄位 | 說明 |
---|---|
query | 你撰寫的 GraphQL 查詢語法,是一段字串。內容描述你「要什麼資料、從哪裡拿、要拿哪些欄位」。 |
variables | 用來傳遞查詢所需的變數(參數)。這讓你可以讓查詢更通用、動態,程式邏輯也更容易維護。 |
註:這裡的
query
不是真正執行語法的「執行語句」,而是字串格式的 GraphQL 語法。這也是為什麼你會看到用 ` 字符把它包起來的原因。
前端實作範例:用 JavaScript fetch()
發送查詢
我們來看一個實際範例,用原生 JavaScript 發送 GraphQL 查詢:
fetch("https://api.example.com/graphql", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
query: `
query {
users {
id
name
}
}
`,
variables: {}
})
})
.then(res => res.json())
.then(data => console.log(data));
這段程式碼的幾個關鍵說明如下:
fetch()
:標準的前端 HTTP 請求函式,用來向伺服器發送請求。Content-Type: application/json
:告訴後端「我傳的是 JSON 格式」。body
:這裡把整個 GraphQL 查詢包成 JSON 並傳送出去。
其中,query
是一段「嵌入在字串裡的 GraphQL 語法」,可以描述你要查詢的物件類型(如 users
)、每筆資料要的欄位(如 id
和 name
)等等。
而 variables
雖然這邊是空的 {}
,但等你需要查詢時傳入參數(例如用戶 ID、搜尋條件)時,這個欄位就會變得非常重要——因為它讓你的查詢變成「模板式」,可以重複使用。
初學者常見誤解補充
- 以為
query
是一段程式邏輯
→ 錯,其實它是一段文字字串,是你用 GraphQL 語法寫的查詢描述,不會直接執行,會被後端解析再執行。 - 以為變數一定要填寫
→ 錯,當查詢沒有用到變數時,variables
可以是空物件。但建議仍保留這個欄位,保持格式一致,也方便未來擴充。 - 以為每個資料類型都要一個 endpoint
→ 錯,GraphQL 所有資料都走同一個/graphql
endpoint,查什麼、怎麼查,完全由查詢語法決定。
為什麼大多數 GraphQL 查詢都用 POST?GET 不行嗎?
你在學 REST API 的時候,可能聽過這樣的說法:「查資料用 GET,新增資料用 POST。」
所以當你第一次看到 GraphQL 查詢居然用 POST 發送,可能會想問:
「查資料也要用 POST?這不是違反規則嗎?」
其實不是,GraphQL 這麼做是有原因的。
雖然技術上來說,用 GET 來查資料也可以,但實際開發上,POST 才是比較合適的做法。
我們先來看看為什麼 GET 在 GraphQL 裡不好用。
GET 可以用,但實際上會遇到很多麻煩
雖然 GraphQL 允許你用 GET 發送查詢,不過這樣做會把整段查詢語法、甚至是變數,全部塞進 URL 裡:
GET /graphql?query=query+{+user(id:%22123%22)+{+name+email+}+}
乍看之下好像沒問題,但實際使用時,很快你會發現這種寫法不太好用,原因有三個:
1. 查詢一多就爆字數
GraphQL 的查詢語法可以很長,尤其是要查巢狀資料、用 fragment 或帶複雜條件時,字數輕鬆超過一千。
瀏覽器和伺服器都對 URL 長度有限制,一旦超過,請求就會送不出去。
2. 變數難寫又醜
GET 方式下,你還得把所有變數也塞進 URL,格式又臭又長,還要自己處理編碼,光是讀懂那串 URL 就讓人頭痛,更別說維護了。
3. 資訊全都攤在外面
GET 的內容會直接顯示在網址上,也會被寫進瀏覽器歷史、伺服器紀錄和第三方監控工具裡。
如果你查的是使用者 ID、email,甚至需要權限的資料,這樣很不安全。
那 POST 有什麼好處?
跟 GET 不一樣,POST 是把請求內容放進 HTTP 的 body 裡面送出去,不是寫在網址上。這樣做有幾個大好處:
好處 | 原因說明 |
---|---|
✅ 沒有字數限制 | 你愛查多長就查多長,巢狀、片段、型別定義都沒問題 |
✅ 變數可以好好管理 | variables 是 JSON 結構,清楚、乾淨、好維護 |
✅ 請求內容不會曝光 | 使用者資料、敏感參數不會出現在網址裡,更安全 |
✅ 工具支援度高 | 大部分 GraphQL 工具(像 Apollo Client)預設就用 POST |
也因此,在你實際開發的過程中,不管是查詢、更新資料(mutation),甚至是登入驗證這種操作,幾乎清一色都是用 POST。
就算你不特別指定,很多框架也會默默幫你用 POST。
小結:技術上 GET 可行,實務上 POST 才實用
方法 | 什麼時候適合用 | 我該怎麼選? |
---|---|---|
GET | Demo、測試工具、小型查詢 | 除非查詢超短,否則不建議用 |
POST | 正式查詢、帶變數、查巢狀 | 正式開發請一律用 POST! |
你可以這樣想:
GET 像便利貼:只能寫幾個字就貼出去;POST 像信封:可以把整份報告包好再寄出。
而 GraphQL 的查詢通常是長篇報告,所以選擇 POST 是最穩又最合理的做法。
什麼是 variables?為什麼查詢要拆成兩段?
如果你把參數寫死,會發生什麼事?
先來想像一個最簡單的查詢場景:你要查詢一位使用者的名字,可以直接這樣寫:
query {
user(id: "123") {
name
}
}
這樣當然沒問題,GraphQL 伺服器會回你使用者的名稱。
但假設你現在有個動態網頁,上面有十位使用者資料,每當使用者點某一個人,你就要重新查一次不同 ID 的資料──
你會怎麼做?把這段查詢改成這樣?
query {
user(id: "456") {
name
}
}
然後再來一段:
query {
user(id: "789") {
name
}
}
❌ 這樣下去根本沒完沒了。每換一個人就要重寫一份查詢語法,不但麻煩,也無法重用。
更糟的是,如果這段查詢被塞在 JavaScript 的字串裡(就像前端常做的那樣),這種「把參數硬寫進去」的方式還可能會帶來安全性問題。
像是容易被拼錯、無法防止特殊符號、甚至被惡意注入(如果你是從表單資料組出來的話)。
GraphQL 為什麼要「拆兩段」?這就是 variables 的用處!
GraphQL 的設計本來就考慮到這種需求,所以它支援把參數「抽出來」,使用一種叫作 variables(變數) 的方式。
把查詢語法變得更通用、更安全、更好維護。
你可以把查詢改成這樣:
query GetUser($id: ID!) {
user(id: $id) {
name
}
}
注意 $id
是變數,而 ID!
是型別(!
表示這個參數是必填的)。
然後你在發送請求時,真正的值不是寫在 query 裡,而是放在另一個欄位 variables
:
{
"query": "...上面的查詢語法...",
"variables": {
"id": "123"
}
}
這樣整段查詢的結構就像「模板 + 參數」,前端只要保留一份 query,把變數的值換掉,就可以查不同的資料。
為什麼這樣寫比較好?看幾個具體優點
好處 | 說明 |
---|---|
✅ 查詢語法可以重複使用 | 不需要為每個人或每個商品重寫一份 query,讓程式碼更乾淨 |
✅ 資料與邏輯分離 | 把查詢邏輯寫好、參數抽出來,更清楚地分工「查什麼」與「查誰」 |
✅ 安全性更高 | 避免拼接字串錯誤、參數被直接注入到 query 中,提高資安防護 |
✅ 工具整合更順暢 | 比如 Codegen 工具會根據你定義的 $id: ID! 自動產生對應型別 |
✅ API 設計與使用者互動更自然 | 使用者點選資料、篩選結果、輸入查詢條件時,只需改變變數,查詢語法完全不變 |
🔧 對照:不使用 vs 使用 variables 的差別
查詢方式 | 範例語法 | 缺點 |
---|---|---|
參數寫死 | query { user(id: "123") { name } } | 無法重用、參數易錯、結構死板 |
使用 variables | query GetUser($id: ID!) { user(id: $id) { name } } | 彈性高、結構清晰、安全性佳、可搭配工具使用 |
從前端到後端:GraphQL 請求整體流程長什麼樣?
當你在前端畫面中點下一個按鈕、開啟一個頁面,看到資料瞬間出現在畫面上,其實背後就經歷了一次完整的 GraphQL 請求流程。
這個過程雖然對使用者來說只有一瞬間,但對開發者來說,裡面包含了許多環節:
請求處理流程分解如下:
flowchart TD A["1.使用者在前端發送查詢 (寫好 query 與 variables)"] --> B["2.組成 JSON 請求物件 (放進 POST 請求的 body)"] B --> C["3.發送到後端的 '/graphql' 路徑"] C --> D["4.後端讀取 query 與 variables (解析成對應資料邏輯)"] D --> E["5.查資料、組資料、打包成 JSON"] E --> F["6.回傳給前端,顯示畫面"]
1️⃣ 使用者觸發前端查詢
使用者可能在畫面上點選「查看詳細資料」、「載入更多使用者」這類按鈕,或者頁面初始化時就需要載入一筆資料。
這時前端程式會準備一份 GraphQL 查詢語法 query
,並根據情境傳入相對應的參數 variables
。
範例:
const query = `
query GetUser($id: ID!) {
user(id: $id) {
name
email
}
}
`;
const variables = {
id: "123"
};
2️⃣ 組成 JSON 請求物件
這份查詢資料會被打包成一個 JSON 格式的物件,結構如下:
{
"query": "...查詢語法...",
"variables": { "id": "123" }
}
然後用 JavaScript 的 fetch()
或其他 HTTP 函式(像是 Axios)發出 HTTP POST 請求,把這段資料放進 body
。
3️⃣ 請求送到後端 /graphql
路徑
這個請求會被送到後端伺服器設定好的 endpoint(例如 https://api.example.com/graphql
)。
這裡並不像 REST API 一樣,每種資料類型就有一條 URL,而是全部的查詢都進同一個入口,然後交給 GraphQL 引擎去解析這段語法。
4️⃣ 後端解析 query 與 variables
後端收到請求後,會先解析 query
裡面的 GraphQL 查詢語法,找出你要查的資料是什麼(例如是 user
,並且需要 name
和 email
)。
然後把 variables
套進去查詢語法中,用來補上具體參數(如 id: "123"
)。
這階段會觸發對應的 resolver 函式,也就是後端為每個欄位所設計的「資料取得邏輯」。
5️⃣ 查資料、組資料、打包成 JSON
後端根據查詢指令、資料結構與參數,去資料庫中查資料,查完後根據你指定的欄位,把資料組成一個對應格式的 JSON:
{
"data": {
"user": {
"name": "Alice",
"email": "[email protected]"
}
}
}
這種回應格式會完全依照你的查詢語法來回傳對應結構,不多也不少。
6️⃣ 資料回到前端,顯示在畫面上
最後這段 JSON 回傳給前端,前端程式會根據回傳內容把資料渲染到畫面上,可能是填入使用者卡片、列表、表單、圖表等等。
這整個請求-解析-回傳的過程,對使用者來說只有短短幾百毫秒,但實際上經過了完整的資料請求流程。
實作建議與常見錯誤排查:寫對查詢,比寫多更重要
GraphQL 的查詢語法本身不難,但在實務開發中,很多錯誤都不是因為你寫錯語法,而是因為你忽略了一些結構細節、格式要求,或者變數命名沒對好。
這一節我們來看幾個實作建議與常見錯誤,幫助你少走冤枉路。
✅ 三個實用建議,幫你寫出更乾淨的查詢
查詢內容盡量通用化,能用變數就不要寫死參數
很多初學者會把參數直接寫進 query 字串裡,例如:
query {
product(id: "abc123") {
name
}
}
這樣雖然能跑,但很難維護。每次查不同 ID 就得改 query 字串,不僅重複、還容易拼錯。
正確做法是把參數抽成變數:
query GetProduct($id: ID!) {
product(id: $id) {
name
}
}
並搭配:
"variables": {
"id": "abc123"
}
這樣查詢語法就能重複使用,前端邏輯也更容易撰寫、測試與除錯。
用工具輔助測試你的查詢
在開始寫程式碼前,建議你先用像 Apollo Studio 或 GraphQL Playground 等工具測試 query。
這些工具能幫你:
- 快速驗證查詢語法是否正確
- 幫你補齊可查詢欄位、自動補全變數型別
- 顯示錯誤訊息與提示,更容易定位錯誤
這些工具就像是你寫 SQL 時的 query builder,讓你能在實際發送前就知道查詢有沒有問題,避免在程式裡來回測試浪費時間。
確保變數名稱與查詢中的 $xxx
對應正確
很多錯誤都不是語法錯,而是「變數名稱沒對上」。
例如:
query GetUser($id: ID!) {
user(id: $id) {
name
}
}
但你在傳送的變數寫成這樣:
"variables": {
"userId": "123"
}
這樣執行時 $id
就會是 undefined
,查詢結果可能變成 null,或者直接報錯。
所以記得:variables
中的欄位名稱要一模一樣對應到 query 中的變數名稱,而且大小寫有分!
常見錯誤與排查對照表
錯誤現象 | 可能原因與解法 |
---|---|
❌ 後端回傳錯誤:Missing query | query 欄位沒寫,或拼錯成 qurey、Query 等大小寫錯誤 |
❌ 查不到資料(回傳 null) | 可能沒傳變數,或變數格式錯,例如該是 id: "123" 卻傳成 id: 123 |
❌ $id 是 undefined | variables 裡面沒傳 id,或名稱拼錯,例如誤寫成 userId |
❌ Syntax Error: Unexpected Name | 查詢語法中變數沒定義,例如用了 $id 但沒有 ( $id: ID! ) 宣告 |
❌ 結構正確但資料空(data 為 {}) | 查詢成功但傳入的參數值不對,導致查詢無結果(ex. ID 輸入錯) |
結語:掌握請求結構,是 GraphQL 的第一步
GraphQL 的查詢邏輯看似複雜,其實只要理解「一段查詢語法 + 一份變數參數」的組合邏輯,就能順利發送請求並取得資料。
無論你是寫 React 還是 Vue,只要掌握這一套請求流程,就能有效串接任何支援 GraphQL 的後端。
下一步,你可以試著結合 Apollo Client、Codegen 工具 甚至 TypeScript 型別,一步步建構出更強大、可維護的前端資料層。