GraphQL 從請求到回應的完整流程:前端、後端、資料庫誰負責什麼?

Published July 22, 2025 by 徐培鈞
Web API

當你在學 GraphQL 時,可能會有這樣的疑問:

  • 「GraphQL Query 是怎麼從前端送到資料庫,最後再返回結果的?」
  • 「前端、後端、資料庫,各自負責哪一段?」

如果你是初學者,對這些過程的印象可能只有一句話:「前端送 Query,後端回傳 JSON」。

但實際上,這中間經歷了好幾個步驟,每個層面(前端 / 後端 / 資料庫)都扮演著不同角色。

準備階段:Schema 與執行引擎的建立

這個階段是 GraphQL 服務啟動前的「基礎建設」,目的是讓後端伺服器先準備好「能理解請求、能對應資料、能正常執行」的環境。

說明設計 Query、Mutation、Type 等,描述「能查什麼資料、怎麼操作」。
負責層面後端(由工程師手動撰寫或工具自動生成)
說明從文字 Schema 轉成型別物件,提供「型別驗證」的依據。
負責層面後端(在 GraphQL Server 啟動時完成)
說明每個欄位都需要綁定一個取得資料的方法(Resolver)。例如 user.name 需要對應一個函式告訴後端去哪抓名字。
負責層面後端
說明啟動 GraphQL Server,將 Schema 與 Resolver 整合。
負責層面後端

時間點:

通常發生在 專案啟動或部署時前端與資料庫幾乎不參與

核心觀念:

把它想像成 「設計一個大型問答系統」

  • Schema 就是「問題清單」:告訴使用者「你可以問什麼問題」。
  • Resolver 就是「回答邏輯」:當有人問問題時,你要去哪查答案。
  • 執行引擎 就是「主持人」:負責接收問題、轉交給對的人回答。

定義 Schema:設計「能問什麼、能操作什麼」

🔹 是什麼?

Schema 就像是 API 的契約,明確定義:

  • 有哪些 Query 可以查詢資料?(例如 user(id: ID)
  • 有哪些 Mutation 可以修改資料?(例如 createPost(title: String)
  • 每個欄位長什麼樣?有什麼型別?(例如 user.nameStringuser.ageInt

🔹 為什麼要這麼做?

  • 前端能清楚知道「可以問什麼問題」。
  • 後端能依 Schema 檢查「問題合不合法」。
  • Schema 也能作為團隊內的溝通語言(尤其是前後端協作)。

🔹 誰負責?

後端工程師(手動撰寫 Schema)
✅ 或 自動化工具(例如 Hasura、Prisma 會自動根據資料庫結構生成 Schema)

🔹 舉例:

type User {
  id: ID
  name: String
  age: Int
}

type Query {
  user(id: ID): User
}

這段 Schema 告訴前端:「你可以問 user,他會回傳一個 User 型別,裡面有 idnameage 三個欄位」。

建立型別系統(Type System):讓伺服器「看得懂」Schema

🔹 是什麼?

在 GraphQL 中,Schema 只是「一份文件」,用類似文字描述的語法寫成,看起來像這樣:

type User {
  id: ID
  name: String
  age: Int
}

這份 Schema 是給人看的,讓前端或其他工程師知道「可以問什麼問題」。

但伺服器本身看不懂這種文字結構,它需要一個「程式能理解的結構化資料」,才能:

  1. 在收到 Query 時進行驗證(例如 user.age 是不是 Int?有沒有這個欄位?)
  2. 在執行時知道要如何比對資料結構

👉 這就是 型別系統(Type System) 的角色。

它會把文字 Schema「翻譯」成一組 JavaScript/其他語言的物件結構,就像這樣:

// 以 JavaScript 為例(簡化)
const UserType = new GraphQLObjectType({
  name: 'User',
  fields: {
    id: { type: GraphQLID },
    name: { type: GraphQLString },
    age: { type: GraphQLInt }
  }
})

這個「型別物件」才是伺服器執行時真正使用的資料結構。

🔹為什麼要這麼做?

  1. 讓伺服器能「懂」這些欄位是什麼
  • Schema 是「人類語言」,Type System 是「程式語言」。
  • 沒有型別系統,伺服器收到 Query 時,無法理解 user.age 是一個數字還是一段文字。
  1. 執行前就能擋掉錯誤(提高安全性)

例如前端不小心傳了這個 Query:

{
  user {
    age
    hobby
  }
}

User 型別根本沒定義 hobby型別系統會在「執行前」就丟錯,避免浪費資源去查資料庫。

  1. 讓工具可以做自動補全、文件生成
  • 開發時你在 VS Code 打 user. 時,IDE 能自動跳出 name、age 等欄位,就是因為型別系統有明確的型別定義。
  1. 為執行階段做準備
  • 執行階段的「驗證(Validation)」與「執行計畫(Execution Planning)」都依賴型別系統,沒有型別系統,這些步驟無法進行。

🔹 什麼時候發生?

GraphQL Server 啟動時自動完成,一次建立好就不會在每次請求時重新生成。

🔹 誰負責?

後端(伺服器層處理)

綁定 Resolver(資料獲取邏輯):告訴後端去哪查答案

🔹 是什麼?

Resolver 是真正負責「取資料」的函式,每個 Schema 欄位都需要對應一個 Resolver。

例如:

  • user.name → 可能要查資料庫中的 users
  • user.posts → 可能要呼叫另一個 API

🔹 為什麼要這麼做?

  • Schema 只定義「你可以問什麼」,Resolver 才負責「怎麼回答」。
  • 沒有 Resolver,即使 Schema 定義再完整,也沒辦法真正拿到資料。

🔹 誰負責?

後端工程師撰寫,有些工具(Hasura、Prisma)也會幫你生成預設的 Resolver。

🔹 簡單舉例:

const resolvers = {
  Query: {
    user: (_, args, context) => {
      return db.users.findById(args.id)
    }
  }
}

當前端問 user(id: 1) 時,這個 Resolver 就會查資料庫中的 users 表。

初始化執行引擎:讓伺服器開始運作

🔹 是什麼?

SchemaResolver 整合到 GraphQL 執行引擎,讓伺服器能接收 Query、解析、執行。

🔹 為什麼要這麼做?

  • 如果沒有執行引擎,前端送來的 Query 根本沒地方跑。
  • 執行引擎是後端的「大腦」,負責後面所有查詢請求的解析、驗證、執行。

🔹 誰負責?

後端

通常是後端框架(Apollo Server、Yoga、Hasura)幫忙完成。

🔹 簡單理解:

可以把它想像成「把廚房開起來,讓廚師(Resolver)可以開始接單做菜」。

關鍵觀念總結

  • 前端:此階段完全不參與,因為前端只負責「問問題」,不管「問題怎麼設計」。
  • 資料庫:只要「資料結構存在」即可,並不直接參與這些後端準備工作。

執行階段:每次查詢請求的完整流程

這是 前端發送一個 Query 後,從送出到收到結果的完整過程

它是 前端 → 後端 → 資料庫 串聯合作的結果。

可以把它想像成:

前端是「顧客」後端是「餐廳廚房」資料庫是「食材倉庫」,從點餐、備餐到送餐回來,每一步都有它的工作流程。

整體流程步驟

說明前端發送 GraphQL Query(通常是 HTTP POST),後端接收。
背後發生了什麼✅ 前端通常使用 Apollo Client、Relay 或 Fetch 送出請求。✅ 後端接收到一個「純文字 Query」字串,還不理解它的結構。
負責層面前端 → 後端
說明將 Query 字串轉成 AST(抽象語法樹)。
背後發生了什麼✅ 後端會用內建的 GraphQL Parser,將文字 Query 解析成「物件化結構」。✅ AST 是一個「樹狀結構」,每個節點代表 Query 的一部分(例如欄位、引數)。✅ 如果文字本身有語法錯誤(少了括號、拼錯欄位),這一步就會報錯。
負責層面後端
說明確認 Query 是否符合 Schema 與型別系統。
背後發生了什麼✅ 解析完後,後端會拿 AST 去跟型別系統比對:‣ 查詢的欄位是否存在?‣ 傳入的引數型別對不對?✅ 這一步是在「執行前」攔截錯誤,避免浪費資料庫資源。
負責層面後端
說明決定呼叫哪些 Resolver、順序及依賴關係。
背後發生了什麼✅ GraphQL 的執行引擎會分析:‣ 先執行哪些欄位?哪些欄位可以平行查詢?‣ 需要先取得什麼值再執行後續查詢(例如 user.id 再查 posts)。✅ 這步有點像「擬定工作排程」。
負責層面後端
說明呼叫對應的 Resolver,Resolver 會向資料庫或其他服務請求資料。
背後發生了什麼✅ 每個欄位都會被分配給對應的 Resolver。✅ Resolver 可以:‣ 查資料庫(最常見)‣ 呼叫外部 API‣ 執行商業邏輯(例如資料轉換)
負責層面後端 → 資料庫
說明將 Resolver 返回的資料,依 Query 結構組成 JSON。
背後發生了什麼✅ 後端會按照 Query 的「樹狀結構」組裝回應資料。✅ 例如 Query 問了 user.name 和 user.posts.title,回應就會對應成相同層次的 JSON。
負責層面後端
說明將 JSON 結果回傳給前端,前端渲染畫面。
背後發生了什麼✅ 後端會用 HTTP Response 回傳 JSON。✅ 前端接到後會更新畫面,可能用 React/Vue 等框架渲染資料。
負責層面後端 → 前端

假設前端送出這個 Query:

query {
  user(id: 1) {
    name
    posts {
      title
    }
  }
}

這個 Query 想要的資料是:

👉 id=1 的使用者 (user)
👉 他的名字 (name)
👉 他的文章標題 (posts.title)

整個過程就像一個 「顧客點餐 → 餐廳廚房作業 → 倉庫取貨 → 廚房擺盤 → 送餐 → 顧客用餐」的故事。

以下每一步都會同時講劇情(比喻)與真實發生的技術行為

前端:顧客點餐(提出需求)

劇情版:

你是餐廳裡的顧客,你把你想吃的東西寫在一張「購物清單」上,交給廚房:

👉「我要 id=1 的使用者,他的名字,還有他發表過的文章標題。」

技術版:

  • 前端(React、Vue 等框架)組裝這段 Query,並用 Apollo Client、Relay 或 fetch 透過 HTTP POST 傳送給後端的 GraphQL 伺服器。
  • 在這個階段,後端接收到的只是一個「純文字 Query」。

注意:前端 不需要也不會知道這些資料怎麼查,它只要「提出需求」並等回應。

後端:廚房備餐(理解訂單、決定流程)

後端就是整個流程的「總指揮」,像餐廳裡的廚房,負責看懂訂單、安排怎麼做、然後去拿食材。

檢查訂單格式(Parsing + Validation)

劇情版:

廚師接到訂單後,第一件事是「檢查訂單寫得對不對」:

  • 你寫的菜名(欄位名)有沒有拼錯?
  • 你要求的數量(參數型別)合不合理?

如果你點了「菜單上沒有的菜」(例如 user.hobby),廚師會直接退回訂單,連做菜都不會開始。

技術版:

  • Parsing(解析): 後端先把 Query 轉成 AST(抽象語法樹),讓 Query 從「文字」變成「結構化資料」。
  • AST 例子:user 是一個節點,posts 是它的子節點。
  • Validation(驗證): 後端用 AST 比對型別系統,確認:
    • user 是否存在於 Schema?
    • id 的型別是不是 Int?
    • posts 是否真的屬於 user

如果在這一步出錯,後端直接回傳錯誤 JSON,不會進入後續階段。

安排做菜順序(Execution Planning)

劇情版:

廚師接著開始「規劃怎麼煮」:

  • 先煮湯(先查 user
  • 等湯煮好拿到 user.id,再煮附餐(查 posts

技術版:

  • GraphQL 執行引擎會分析欄位之間的依賴關係
  • user 必須先查出來 → 因為 posts 的查詢需要 user.id
  • 但如果 Query 有其他獨立欄位(例如 comments),它們可以平行查詢以提升效能。

做菜取食材(Execution)

劇情版:

廚房開始行動,每道菜都由一個專門的廚師負責。

  • 負責主菜的廚師跑去倉庫(資料庫)拿到使用者資訊。
  • 再由另一個廚師拿著 user.id 去倉庫拿這個使用者發表過的文章。

技術版:

  • GraphQL 會呼叫對應的 Resolver(資料獲取函式)
    • user 的 Resolver 可能執行 SQL 查詢:SELECT * FROM users WHERE id=1
    • posts 的 Resolver 再用 user.id 查:SELECT title FROM posts WHERE user_id=1
  • Resolver 不只查資料庫,也可以呼叫其他 API 或執行商業邏輯。

資料庫:倉庫出貨(只提供原料)

劇情版:

倉庫只負責把食材搬給廚房,不會幫忙煮菜或擺盤

  • 廚師說「幫我拿 id=1 的雞肉(user)」 → 倉庫就搬來
  • 廚師說「幫我拿雞肉的附餐食材(posts)」 → 倉庫再搬來

技術版:

  • 資料庫只根據 SQL 查詢回傳原始資料,並不知道最終的 JSON 結構。
  • 例如:
    • users 表 → {id:1, name:"Tom"}
    • posts 表 → [{title:"Hello World"}]

後端:組裝餐點並上桌(Result Assembly + Return)

劇情版:

廚師收到倉庫的食材後,把它們擺盤成你原本訂的樣子:

  • 把「主菜(user)」放在盤子中央
  • 把「附餐(posts.title)」放在旁邊

技術版:

  • 後端按照 Query 的樹狀結構組裝資料。
  • 這是 GraphQL 與 REST API 最大的不同之一:
    回傳結果的結構會完全依照你 Query 的寫法。

最終回傳給前端的 JSON 會長這樣:

{
  "data": {
    "user": {
      "name": "Tom",
      "posts": [
        { "title": "Hello World" }
      ]
    }
  }
}

前端:顧客吃到餐點(更新畫面)

劇情版:
顧客(前端)接到廚房送來的餐點後,擺在桌上,開始享用。

技術版:

  • 前端接到 JSON 後,更新畫面。
  • 如果用 Apollo Client,它會自動把結果寫入快取,並觸發畫面重新渲染,讓頁面顯示「Tom」的名字與文章標題。

關鍵觀念總結(重新強化記憶)

  1. 前端顧客
    只管「提出需求」與「更新畫面」,完全不關心資料怎麼取得。
  2. 後端廚房
    是整個流程的「大腦」與「指揮者」,負責檢查、規劃、拿資料、組裝結果。
  3. 資料庫倉庫
    只提供「原料」;它不理解 Query,也不負責組裝 JSON。

責任分工一覽表

這張表格告訴你 「前端、後端、資料庫」各自的工作範圍

但為了讓你不只是死背表格,下面我會逐步說明 每一階段、每一個步驟為什麼這樣分工,以及背後實際發生的事。

完整責任分工表

步驟定義 Schema
前端
後端✅(撰寫或自動生成 Schema)
資料庫❌(只要確保資料結構存在即可)
步驟建立型別系統
前端
後端✅(把文字 Schema 轉成程式能理解的型別物件)
資料庫
步驟綁定 Resolver
前端
後端✅(撰寫 Resolver,定義怎麼取得資料)
資料庫
步驟初始化執行引擎
前端
後端✅(啟動 GraphQL 伺服器,結合 Schema 和 Resolver)
資料庫
步驟接收查詢請求
前端✅(發送 Query)
後端✅(接收並準備處理)
資料庫
步驟Parsing
前端
後端✅(將 Query 文字轉成 AST)
資料庫
步驟Validation
前端
後端✅(比對 Schema,確認欄位與型別正確)
資料庫
步驟Execution Planning
前端
後端✅(決定 Resolver 執行順序和平行或依賴關係)
資料庫
步驟Execution
前端
後端✅(呼叫 Resolver)
資料庫✅(執行 SQL 查詢或讀取原始資料)
步驟組裝結果
前端
後端✅(按照 Query 結構組合 JSON)
資料庫
步驟回應前端
前端✅(接收結果、更新畫面)
後端✅(回傳 JSON 結果)
資料庫

為什麼要這樣分工?

準備階段(後端主導)

這個階段完全是「後端的世界」,前端和資料庫幾乎不參與。

  1. 定義 Schema → 為什麼是後端負責?
  • Schema 是「API 的菜單」,只有後端知道「有哪些資料可以查」。
  • 前端只會依 Schema 查資料,沒資格改菜單;資料庫只要有相應的欄位就好。
  1. 建立型別系統 → 為什麼前端不需要?
  • 型別系統是「伺服器內部的驗證機制」。
  • 前端並不直接參與伺服器內部的邏輯,只是消費者。
  1. 綁定 Resolver → 為什麼資料庫不參與?
  • Resolver 是一段「後端邏輯」,它可能呼叫資料庫,也可能呼叫其他 API。
  • 資料庫只是個原始倉庫,它不會決定「查什麼」。
  1. 初始化執行引擎 → 為什麼全是後端?
  • GraphQL 伺服器是後端的核心運行引擎,前端只是使用者,資料庫只是被動供應商。

執行階段(前端、後端、資料庫串聯)

這個階段就是一次真實的 Query 從送出到返回結果的全過程。

  1. 接收查詢請求 → 前端和後端共同參與
  • 前端負責組裝 Query 並發送
  • 後端負責接收並準備處理
  1. Parsing、Validation、Execution Planning → 為什麼只有後端?
  • 這些屬於伺服器內部的工作:
    Parsing:把文字 Query 轉成 AST
    Validation:用型別系統驗證欄位
    Execution Planning:決定執行順序
  • 前端只是顧客,資料庫只是被動供應商,兩者都不需要參與。
  1. Execution → 為什麼後端和資料庫都要參與?
  • 後端(Resolver)像「中間人」,它決定該怎麼查資料。
  • 資料庫負責真正去讀取資料(SQL 查詢)。
  • 前端在這一步完全不參與,因為它根本不會直接操作資料庫。
  1. 組裝結果 → 為什麼只有後端?
  • GraphQL 最大的特色就是「根據 Query 的結構返回資料」。
  • 這需要後端自己組裝 JSON,資料庫只提供原始資料,不會組裝成前端要的結構。
  1. 回應前端 → 前端和後端共同參與
  • 後端:將結果打包成 JSON 回傳
  • 前端:接收到結果後,更新畫面(例如 React 重新渲染組件)。

初學者快速記憶法

一句話記住三層分工:

  • 前端:只負責 「問問題」與「更新畫面」
  • 後端:是 「大腦 + 執行者」,負責檢查、決策、拿資料、組裝
  • 資料庫:只是一個 「原料倉庫」,負責按照需求提供原始資料

口訣版:

「前端提問、後端思考、資料庫供應」

各階段常用工具對應表

在實際專案中,準備階段執行階段通常會使用許多現成工具或框架,幫助你快速生成 Schema、簡化請求流程、管理快取,甚至自動生成型別。

下面整理了一份 「每個步驟 → 對應工具 → 用途」的詳細清單。

準備階段(Schema 與執行引擎的建立)

常用工具✅ Hasura
用途與優點自動根據資料庫結構生成 GraphQL Schema,快速搭建 API,適合不想手動寫 Schema 的專案。
常用工具✅ Prisma
用途與優點基於資料庫模型自動生成 GraphQL Schema,並附帶 ORM 功能,適合需要控制資料庫操作的專案。
常用工具✅ Apollo Server
用途與優點適合手動撰寫 Schema 的專案,可靈活定義 Query、Mutation、Type。
常用工具✅ GraphQL.js
用途與優點GraphQL 官方底層實作,會自動將文字 Schema 轉換成型別物件(Type System)。大多數框架(Apollo、Yoga)也基於此。
常用工具✅ Nexus
用途與優點透過程式碼生成型別系統,比直接寫 SDL(Schema Definition Language)更有型別安全,適合 TypeScript 專案。
常用工具✅ Apollo Server
用途與優點提供簡單的方式撰寫 Resolver 並綁定到 Schema。
常用工具✅ Hasura
用途與優點自動生成 Resolver;若需要自訂,也可透過 Remote Schema 或 Action 實現。
常用工具✅ Prisma + Nexus
用途與優點Prisma 幫助快速查資料庫,Nexus 提供型別安全的 Resolver 撰寫方式。
常用工具✅ Apollo Server
用途與優點最常見的 GraphQL Server 框架,整合 Schema、Resolver、型別系統,社群資源豐富。
常用工具✅ Yoga GraphQL
用途與優點輕量化的 GraphQL Server,快速上手,適合小型專案或初學者。
常用工具✅ Hasura
用途與優點自動化 GraphQL Server,開箱即用,幾乎不需要額外撰寫後端程式碼。

執行階段(從請求到回應的完整流程)

常用工具✅ Apollo Client(前端)
用途與優點提供 gql 標記函式,支援撰寫 Query / Mutation,並結合型別提示。
常用工具✅ GraphQL Code Generator(前端)
用途與優點自動生成對應型別與 Hook,避免手動維護查詢結果型別。
常用工具✅ Apollo Client(前端)
用途與優點自動打包 Query、變數,並透過 HTTP / WebSocket 發送請求。
常用工具✅ Relay(前端)
用途與優點Facebook 出品,適合大型專案,強化查詢與快取優化。
常用工具✅ Urql(前端)
用途與優點輕量化 GraphQL 前端客戶端,適合中小型專案。
常用工具✅ Apollo Client / Relay(前端)
用途與優點負責發送 HTTP POST 或 WebSocket(即時訂閱)。
常用工具✅ fetch / Axios(前端)
用途與優點若不需要完整快取管理,可直接用這些低階 API 發送請求。
常用工具✅ Apollo Server(後端)
用途與優點監聽 HTTP 請求並接收 Query,是最常見的 GraphQL 伺服器框架。
常用工具✅ Hasura(後端)
用途與優點自動接收 Query,無需手動配置路由。
常用工具✅ GraphQL.js(後端)
用途與優點將 Query 文字轉換成 AST(抽象語法樹),大多數伺服器底層都用這個。
常用工具✅ GraphQL.js(後端)
用途與優點比對 Schema 與型別系統,提前攔截 Query 錯誤。
常用工具✅ Apollo Server / Hasura(後端內建)
用途與優點自動決定 Resolver 的執行順序(例如先查 user 再查 posts)。
常用工具✅ Prisma(後端)
用途與優點作為 ORM,幫助 Resolver 快速查資料庫。
常用工具✅ Hasura(後端)
用途與優點自動執行 SQL 查詢,直接從資料庫取資料。
常用工具✅ Axios / Fetch(後端)
用途與優點如果 Resolver 需要呼叫外部 REST API,可用這些工具。
常用工具✅ GraphQL 執行引擎(後端內建)
用途與優點自動根據 Query 的樹狀結構組裝 JSON,開發者通常不需要手動處理。
常用工具✅ Apollo Server / Hasura(後端)
用途與優點將組裝好的 JSON 以 HTTP 回傳前端。
常用工具✅ Apollo Client(前端)
用途與優點自動將結果寫入快取,並支援快取同步更新畫面。
常用工具✅ Relay(前端)
用途與優點高度優化快取與狀態管理,適合大型專案。
常用工具✅ React / Vue(前端)
用途與優點前端框架會根據快取或結果資料,重新渲染對應元件。

初學者快速選擇建議

如果你是 初學者,可以直接採用以下組合:

  1. 全自動快速搭建(低代碼)
    Hasura + Apollo Client
    ✅ Hasura 幫你自動處理 Schema、Resolver、執行引擎;前端只需用 Apollo Client 查資料。
  2. 靈活手動控制(適合學習原理)
    Apollo Server + Apollo Client
    ✅ 後端手動撰寫 Schema、Resolver;前端同樣用 Apollo Client 發送查詢並管理快取。
  3. 強型別 + 適合中大型專案
    Prisma + Nexus + Apollo Server(後端) + Apollo Client(前端)
    ✅ 適合需要高度型別安全與靈活控制的專案。