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 把資料結構與參數分別寫在 queryvariables 裡。前端可以自由控制要哪些欄位,不需要改變 endpoint。

重點總結:GraphQL 請求的「語意」比 URL 更重要

REST 是「路徑導向」的 API 設計,URL 決定你能取得什麼資料,資料格式也由後端定義。

這種方式簡單直觀,但一旦前端需求變動,就必須調整新的路由或欄位格式。

而 GraphQL 則是「語意導向」,請求本體是你在 query 中描述的內容,不管你要查一筆、查多筆、查欄位 A 還是欄位 B,都透過同一個 endpoint 傳送,差別只在你怎麼寫查詢語法

這不只讓前端開發更有彈性,也讓 API 設計更具一致性與可擴展性。

那 GraphQL 的請求內容長什麼樣子?來看完整結構與實作範例

在 GraphQL 中,無論你是要查一筆資料還是多筆資料,前端傳送給後端的內容其實都很固定——就是一個 JSON 格式的物件,裡面包含兩個最核心的欄位:queryvariables

這個請求會被放在 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)、每筆資料要的欄位(如 idname)等等。

variables 雖然這邊是空的 {},但等你需要查詢時傳入參數(例如用戶 ID、搜尋條件)時,這個欄位就會變得非常重要——因為它讓你的查詢變成「模板式」,可以重複使用。

初學者常見誤解補充

  1. 以為 query 是一段程式邏輯
    → 錯,其實它是一段文字字串,是你用 GraphQL 語法寫的查詢描述,不會直接執行,會被後端解析再執行。
  2. 以為變數一定要填寫
    → 錯,當查詢沒有用到變數時,variables 可以是空物件。但建議仍保留這個欄位,保持格式一致,也方便未來擴充。
  3. 以為每個資料類型都要一個 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 才實用

方法什麼時候適合用我該怎麼選?
GETDemo、測試工具、小型查詢除非查詢超短,否則不建議用
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 } }無法重用、參數易錯、結構死板
使用 variablesquery 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,並且需要 nameemail)。

然後把 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 StudioGraphQL Playground 等工具測試 query。

這些工具能幫你:

  • 快速驗證查詢語法是否正確
  • 幫你補齊可查詢欄位、自動補全變數型別
  • 顯示錯誤訊息與提示,更容易定位錯誤

這些工具就像是你寫 SQL 時的 query builder,讓你能在實際發送前就知道查詢有沒有問題,避免在程式裡來回測試浪費時間。

確保變數名稱與查詢中的 $xxx 對應正確

很多錯誤都不是語法錯,而是「變數名稱沒對上」。

例如:

query GetUser($id: ID!) {
  user(id: $id) {
    name
  }
}

但你在傳送的變數寫成這樣:

"variables": {
  "userId": "123"
}

這樣執行時 $id 就會是 undefined,查詢結果可能變成 null,或者直接報錯。

所以記得:variables 中的欄位名稱要一模一樣對應到 query 中的變數名稱,而且大小寫有分!

常見錯誤與排查對照表

錯誤現象可能原因與解法
❌ 後端回傳錯誤:Missing queryquery 欄位沒寫,或拼錯成 qurey、Query 等大小寫錯誤
❌ 查不到資料(回傳 null)可能沒傳變數,或變數格式錯,例如該是 id: "123" 卻傳成 id: 123
❌ $id 是 undefinedvariables 裡面沒傳 id,或名稱拼錯,例如誤寫成 userId
❌ Syntax Error: Unexpected Name查詢語法中變數沒定義,例如用了 $id 但沒有 ( $id: ID! ) 宣告
❌ 結構正確但資料空(data 為 {})查詢成功但傳入的參數值不對,導致查詢無結果(ex. ID 輸入錯)

結語:掌握請求結構,是 GraphQL 的第一步

GraphQL 的查詢邏輯看似複雜,其實只要理解「一段查詢語法 + 一份變數參數」的組合邏輯,就能順利發送請求並取得資料。

無論你是寫 React 還是 Vue,只要掌握這一套請求流程,就能有效串接任何支援 GraphQL 的後端。

下一步,你可以試著結合 Apollo ClientCodegen 工具 甚至 TypeScript 型別,一步步建構出更強大、可維護的前端資料層。

Similar Posts