初學者入門:認識 GraphQL Schema

更新日期: 2025 年 4 月 30 日

如果你正在學習 GraphQL, 一定會很快遇到一個超級重要的關鍵字:Schema(綱要、結構)

Schema 是 GraphQL 的骨架。

它定義了:

  • 後端有哪些資料可以提供?
  • 這些資料是什麼型別?
  • 前端可以發送哪些查詢、變更請求?
  • 每個操作需要帶哪些參數、會回傳什麼?

簡單來說,沒有 Schema,就沒有 GraphQL!

Schema 是前後端溝通的「共同語言」,也是 GraphQL 能做到高效、嚴謹開發的核心原因。

接下來,我們會一步步帶你了解:

  • 什麼是 GraphQL Schema?
  • Schema 裡面有哪些基本型別?
  • Schema 是如何幫助我們查資料、改資料?

GraphQL Schema 是由兩大系統組成的

當我們說 GraphQL 是「Schema 驅動」的,其實指的是整個系統的運作邏輯,是由兩大核心系統共同構成的。

這兩大系統分別是:

系統名稱功能定位常見項目
🧭 操作系統定義前端可以對系統做哪些事Query、Mutation、Subscription
🧱 型別系統定義系統中資料長什麼樣子(結構與型別)Object、Scalar、Input、Enum、Interface 等

這兩者缺一不可。

一個是「可以做什麼事」,一個是「這些事會用到什麼資料格式」,共同構成完整的 GraphQL 生態。

操作系統:告訴前端「可以做哪些操作」

這部分是 Schema 的「功能層」,它定義了前端可以發起哪些請求。

你可以這樣理解:

  • Query ➜ 查資料(像是查一篇文章)
  • Mutation ➜ 改資料(像是新增留言)
  • Subscription ➜ 即時訂閱資料(像是聊天室新訊息)

這些操作就像是你走進一間餐廳時,菜單上列出的動作

「我可以點餐」、「我可以取消訂單」、「我可以訂閱外送進度」

Schema 就是那份菜單,而操作系統就是讓前端知道這些服務有哪些「入口點」可以呼叫。

型別系統:告訴大家「資料長什麼樣子」

而型別系統才是真正的「資料說明書」,它負責定義所有資料的格式與結構。

讓操作系統能正確驗證每一筆請求該怎麼傳資料、該回傳什麼資料。

包括:

型別功能說明
Object Type定義一筆資料物件有哪些欄位
Scalar Type最基本的資料型別(字串、整數、布林等)
Input Type專門用來傳入參數(例如:表單送出格式)
Enum Type固定選項的欄位限制(例如角色只能是 ADMIN/USER)

你可以把這些型別想像成餐廳裡的「菜品內容」:

「這道菜需要哪些材料?食材是什麼型態?有沒有選項可選?」

換句話說,操作系統是告訴你「你可以點菜」,型別系統則是告訴你「每道菜怎麼做、包含什麼內容」

綜合比喻:GraphQL 就像一間餐廳

角色對應系統解釋
菜單(服務流程)操作系統前端可以點哪些服務(查資料、改資料、追蹤)
每道菜的配方型別系統每筆資料的欄位格式、型別與限制
廚房(資料來源)Resolver + DB根據操作與型別,把資料組出來回傳前端

你不能只有菜單而不知道菜怎麼做,也不能只知道食材卻不知道能點什麼。這兩個系統要一起協作,前端請求才會成立、後端才能正確回應。

三大核心操作類型:Query、Mutation、Subscription

在 GraphQL 中,一切的操作都要明確地在 Schema 中定義出來

不論你是要查資料、改資料、還是接收即時更新,都需要透過三種核心操作類型(Operation Types)來進行:

類型功能說明常見用途
Query讀取資料查詢使用者資料、取得文章清單、檢視商品資訊
Mutation修改資料(新增、刪除、更新)建立留言、更新個人設定、刪除商品
Subscription訂閱即時資料變化新留言通知、聊天室訊息、訂單出貨狀態變更

Query:查資料的主力工具

Query 是最常用的操作類型,主要用途是「讀取」資料,也就是從後端系統(或資料庫)取出現有的資訊給前端使用。

範例:

query {
  getUser(id: "123") {
    id
    name
    email
  }
}

這段代表查詢 ID 為 123 的使用者,並要求回傳其 idnameemail

✅ 特點與設計哲學:

  • 不會改變後端資料:單純讀取,不會有任何副作用。
  • 可多次重複發送:你可以一直查詢同一筆資料,不需要擔心資料狀態改變。
  • 對應 REST 中的 GET 請求

🧠 初學者常見誤解:

❌「Query 好像也可以改資料吧?」
➜ 錯,GraphQL 嚴格區分讀寫操作。所有改資料的行為都必須使用 Mutation,即使只是切換一個布林值也不例外。

Mutation:改資料就靠它

Mutation 是用來執行「改變系統內部狀態」的操作,包括新增、刪除、修改資料。

和 Query 不同,Mutation 通常具有副作用(side effect),會真正地改變資料庫中的內容。

範例:

mutation {
  createPost(input: { title: "新文章", content: "內容" }) {
    id
    title
  }
}

這段代表新增一篇文章,並回傳它的 idtitle

✅ 特點與設計哲學:

  • 每個 Mutation 通常只處理一個「動作」(例如:createPostupdateUser
  • 可以定義輸入與回傳的資料格式(透過 input type 與回傳的 type
  • 對應 REST 中的 POST、PUT、DELETE 請求

🧠 初學者常見誤解:

❌「Mutation 一定只能處理單筆嗎?」
➜ 不一定,一個 Mutation 也可以操作多筆資料,或同時觸發多個邏輯(但要注意設計清晰、資料一致性)

Subscription:實現即時互動體驗

Subscription 是一種即時通訊機制,允許前端訂閱某個事件,只要後端有新資料更新,就會主動推送結果給前端。

範例:

subscription {
  messageAdded {
    id
    content
    sender
  }
}

這段代表:前端訂閱聊天室中新的訊息,一旦有人發送新訊息,後端就會自動通知前端。

✅ 特點與設計哲學:

  • 基於 WebSocket 建立持續連線(不像 Query/Mutation 是單次請求)
  • 非常適合做聊天室、通知系統、直播互動、狀態追蹤
  • 前端不需要輪詢,也不需要自己刷新畫面

🧠 初學者常見誤解:

❌「Subscription 就是 Mutation + WebSocket 嗎?」
➜ 錯,Subscription 不會主動改資料,它只是監聽資料變化或後端事件,由後端根據觸發條件主動推送。

實務設計補充:這三種操作可以怎麼搭配?

以「留言系統」為例,三種操作會這樣合作:

功能操作類型說明
查詢所有留言Query取得目前留言清單
新增留言Mutation將一筆新留言寫入資料庫
即時推播留言Subscription當其他人留言時,前端自動收到更新資訊

🧱 每一個 Schema 至少要有一個 Query

根據 GraphQL 的設計規範:

  • 每個 Schema 一定要有一個根層級的 Query,否則你就什麼資料都查不到。
  • MutationSubscription 則是選配的,只有當你要「改資料」或「做即時互動」時才會定義。

✅ 如果你只是查靜態資料(例如部落格文章、FAQ 清單),可以只寫 Query 就夠用了。

小結:三種操作是 Schema 的核心骨架

類型操作性質功能範圍是否改資料使用頻率
Query讀取查資料❌ 否🟢 非常頻繁
Mutation寫入增刪改資料✅ 是🟡 常見但慎用
Subscription被動接收即時互動❌ 否🔵 有需求才用

GraphQL 的設計哲學非常清楚:

❝ 把讀與寫分開、把即時互動也分出來,讓前端能清楚表達需求,後端能穩定回應處理。❞

Schema 型別與資料庫的關係

在設計 GraphQL Schema 時,我們會用各種型別來描述資料的結構。

這些型別不只讓前端知道可以查什麼資料,也幫助後端正確處理請求。

接下來,我們會一一介紹這些型別,並說明它們跟資料庫之間的關係。

Object Type(物件型別) ➜ 對應到「資料表裡的一筆資料」

Object Type 是 Schema 裡最基本的單位,代表一種「資料的形狀」。

例如,定義一個 User 型別:

type User {
  id: ID!
  name: String!
  email: String!
}

這表示:

  • User 是一種物件,裡面有 idnameemail 三個欄位。
  • 每個欄位都指定了型別,例如 ID! 表示這是必填的 ID。
  • 前端查詢時,只能取得這裡定義過的欄位。

💡 那它和資料庫有什麼關係?

雖然 GraphQL 並不直接操作資料庫。

但在大多數應用中,User 這個型別會對應到資料庫中的一個 users 資料表。

而一筆筆的 User 資料,就對應到 users 表裡的一行(row)。

GraphQL Type資料庫概念
type Userusers 資料表的結構
一個 Userusers 表中的一筆資料

✅ 你可以這樣記:Object Type 是「描述資料的外觀」,資料表是「實際儲存資料的地方」。

Scalar Type(標量型別) ➜ 對應到「欄位的資料型別」

Scalar Type 就是最基本的資料型別,用來描述欄位的內容是什麼類型。

GraphQL 提供了以下幾種標準型別:

型別說明常見資料庫對應類型
Int整數(例如:1, 100)INTEGER、BIGINT
Float浮點數(例如:3.14)FLOAT、DECIMAL
String字串(例如:”hello”)VARCHAR、TEXT
Boolean布林值(true 或 false)BOOLEAN、TINYINT(1)
ID唯一識別碼(通常是字串或數字)UUID、INT、VARCHAR

✅ GraphQL 的 Scalar Type 有點像是「欄位型別」,幫助我們控制每個欄位該放什麼資料。

Input Type(輸入型別) ➜ 對應到「送進資料庫的參數格式」

當你想要新增或修改一筆資料時(例如送出表單)。

就會需要一個清楚定義好的「輸入格式」,這就是 Input Type 的功能。

範例:

input CreatePostInput {
  title: String!
  content: String!
}

然後在 Mutation 中這樣使用:

type Mutation {
  createPost(input: CreatePostInput!): Post
}

💡 那它和資料庫有什麼關係?

這些 input 欄位,其實就是未來準備寫入資料庫時的資料格式

例如 CreatePostInput 可能會對應到資料表 posts 中的 titlecontent 欄位。

你可以這樣比喻:

GraphQL Input Type資料庫操作
CreatePostInput建立一筆新文章資料的欄位輸入格式

✅ Input Type 幫你提前驗證輸入資料,確保送進後端的資料是正確、格式一致的。

Enum Type(列舉型別) ➜ 對應到「固定值欄位的限制」

當你有一個欄位,只能接受幾個固定值時,就可以使用 enum 來強制限制。

範例:

enum Role {
  ADMIN
  USER
  GUEST
}

當你在 User 裡定義這樣的欄位:

type User {
  id: ID!
  name: String!
  role: Role!
}

就代表:這個使用者的角色只能是 ADMINUSER、或 GUEST

💡 那它和資料庫有什麼關係?

在資料庫中,我們常會用:

  • ENUM 欄位(如果資料庫支援),或
  • VARCHAR 加上後端檢查

來實作這種「只允許特定值」的欄位。

GraphQL Enum Type資料庫對應方式
enum RoleENUM 型別或 VARCHAR 搭配驗證機制

✅ Enum Type 可以讓前端查資料時更有信心,也讓後端驗證資料更嚴謹。

GraphQL 四大型別 (Type) 的關聯

我們可以用一個比喻來理解:

✅ 把 GraphQL Schema 想像成一間「餐廳系統」
每種 Type 都扮演不同角色,但彼此合作完成一筆資料的查詢/變更流程

角色總覽表

種類用來描述…主要出現在哪裡?用途說明
Object Type真正的資料物件Query / Mutation 的回傳值描述「資料的長相」
Scalar Type欄位的基本型別Object / Input 裡面的欄位定義欄位的「資料型別」
Input Type輸入參數的格式Mutation 或查詢參數用來「包裝一組參數」
Enum Type固定選項的清單Object / Input 裡面的欄位強制欄位只能使用特定值

彼此的關係(具體圖解)

我們可以這樣畫出一個邏輯流程:

flowchart TD
    subgraph "Object Type"
        User["User (Object Type)"]
        User --> UserID["id: ID!"]
        User --> UserName["name: String!"]
        User --> UserRole["role: Role!"]
    end

    subgraph "Scalar Type"
        ID["ID!"]
        String["String!"]
    end

    subgraph "Enum Type"
        Role["Role!"]
    end

    subgraph "Input Type: CreateUserInput"
        CreateUserInput["CreateUserInput"]
        CreateUserInput --> InputName["name: String!"]
        CreateUserInput --> InputRole["role: Role!"]
    end

    subgraph "Mutation"
        createUser["Mutation: createUser(input: CreateUserInput!) → User"]
    end

    UserID -.-> ID
    UserName -.-> String
    UserRole -.-> Role
    InputName -.-> String
    InputRole -.-> Role
    createUser --> User
    createUser --> CreateUserInput

🔍 解釋這段結構:

  1. User 是你要查的資料物件(Object Type)。
  2. User 的每個欄位(像是 name)都需要有一個型別 ➜ 這些型別大多是 Scalar Type(如 String)。
  3. role 欄位不想讓人亂填 ➜ 所以你使用 Enum Type 來限制只允許 ADMIN / USER / GUEST
  4. 當你要「新增一個使用者」時,要送一組參數 ➜ 這時你定義 CreateUserInput(Input Type)。
  5. CreateUserInput 的欄位結構,也一樣會用到 Scalar 和 Enum Type。

實際對照範例

enum Role {
  ADMIN
  USER
  GUEST
}

input CreateUserInput {
  name: String!
  role: Role!
}

type User {
  id: ID!
  name: String!
  role: Role!
}

type Mutation {
  createUser(input: CreateUserInput!): User
}

這段 Schema 裡:

  • User 是一個「結果型別」,通常來自資料庫
  • CreateUserInput 是一個「參數型別」,用來傳入前端資料
  • StringID 是基本型別(Scalar)
  • Role 是列舉型別(Enum),可用於 UserCreateUserInput

總結:它們如何合作?

你可以這樣記:

🔁 Scalar + Enum 是基本「材料」
📦 Input Type 是前端提供的「料理包」
🧾 Object Type 是後端回給前端的「餐點結果」

在一次 GraphQL 操作中,它們會這樣分工:

階段使用的 Type說明
前端送參數Input Type + Scalar/Enum前端整理好資料、送給後端
後端驗證參數Input Type確保資料格式正確
後端查詢資料庫不一定直接使用 Type,但會參考欄位結構
後端回傳資料Object Type + Scalar/Enum把查到的資料回傳給前端

從 Schema 到實際查詢的流程:一筆資料如何從資料庫到畫面?

GraphQL 的強大之處,不只是能自由查資料,而是它建立了一套結構清楚、流程明確的查詢機制

這個流程從 Schema 開始,貫穿前端、後端、資料庫,直到資料回到使用者手上。

以下是一個簡單又完整的查詢流程範例,帶你理解每一步背後的運作邏輯:

後端定義 Schema(建立介面契約)

首先,後端要定義一份 Schema,讓前端知道「你可以查什麼資料、怎麼查」。

範例:

type Query {
  getUser(id: ID!): User
}

type User {
  id: ID!
  name: String!
  email: String!
}

這段 Schema 表示:

  • 你可以查詢一個叫做 getUser 的 Query
  • 它需要傳入一個參數 id(類型為 ID 且必填)
  • 回傳的結果會是 User 這個資料型別,包含三個欄位

✅ 這就像是一張 API 菜單,列出前端可以點的服務與回應內容

前端根據 Schema 發送請求(撰寫查詢指令)

一旦 Schema 被定義好,前端就可以直接根據它寫查詢語法。

例如,要查 ID 為 "123" 的使用者資料,可以寫這樣的 GraphQL 查詢:

query {
  getUser(id: "123") {
    id
    name
    email
  }
}

這裡前端表達的是:

  • 我要使用 getUser 這個 API
  • 傳入參數 id: "123"
  • 並且只需要回傳 idnameemail 這三個欄位資料(不需要其他欄位)

✅ 這是 GraphQL 查詢最大的特色:前端精確決定要什麼欄位,不多不少

後端驗證請求是否合法(Schema 驗證)

GraphQL Server 收到請求後,不會立刻查資料,而是會先根據 Schema 驗證這個請求的正確性:

  • getUser 是否存在於定義好的 Query 裡?
  • id 是否有被傳進來?
  • id 的型別是否為 ID
  • 要求的欄位(idnameemail)是否真的在 User 裡面有定義?

這些檢查全部通過之後,才會執行查詢邏輯。

✅ 這步驟就是 GraphQL 天生的「防呆」機制,幫助你在第一關就擋掉錯誤。

後端執行 Resolver,查詢資料來源(通常是資料庫)

經過驗證後,後端會執行對應的 resolver function,把資料撈出來。

範例(JavaScript):

const resolvers = {
  Query: {
    getUser: async (_, { id }) => {
      return db.user.findById(id); // 使用 ORM 或 SQL 查資料庫
    }
  }
};

這裡的邏輯可能會:

  • 呼叫資料庫的 users 資料表
  • 撈出 id 為 "123" 的那一筆資料
  • 將資料組成一個符合 User 型別格式的物件

✅ Resolver 就是 GraphQL 的「資料搬運工」,幫你把對的資料搬回來。

GraphQL Server 根據欄位需求,組裝回傳結果

GraphQL Server 拿到資料之後,會依照查詢指令中所列的欄位(field)進行資料挑選:

前端只要求了這三個欄位:

{
  id
  name
  email
}

後端就只會回傳這三個欄位的資料,而不會多給像是密碼、建立時間、角色之類的資料。

範例回傳 JSON:

{
  "data": {
    "getUser": {
      "id": "123",
      "name": "小明",
      "email": "[email protected]"
    }
  }
}

✅ GraphQL 最大的特點就是:回傳資料剛剛好,只給你需要的內容。

小總結:從 Schema 到畫面,完整流程如下:

flowchart LR
    A[Schema 定義] --> B[前端查詢]
    B --> C[請求驗證]
    C --> D[Resolver 查資料]
    D --> E[回傳結果]
    
    style A fill:#f9d5e5,stroke:#333,stroke-width:2px
    style B fill:#eeeeee,stroke:#333,stroke-width:2px
    style C fill:#e3f0f9,stroke:#333,stroke-width:2px
    style D fill:#d5f5e3,stroke:#333,stroke-width:2px
    style E fill:#fdebd0,stroke:#333,stroke-width:2px

對照流程圖:

  1. 後端 Schema 設計 ← 提供操作與欄位定義
  2. 前端寫查詢語法 ← 根據 schema 指定需要的欄位
  3. Server 驗證指令合法性
  4. 後端 Resolver 去資料庫查資料
  5. Server 將結果包成 JSON 回傳給前端

✅ 這個流程是所有 GraphQL 查詢的核心運作模式。
一旦你理解這整條鏈路,使用 GraphQL 查資料就變得自然又高效!

為什麼學會 Schema 這麼重要?

GraphQL 的核心理念就是:Schema 為中心(Schema-first)

一旦你掌握了 Schema,就等於掌握了這個系統的語言、邊界、規則與能力範圍

以下是學會 Schema 帶來的三大核心好處,並搭配實際開發場景說明:

讓開發更快:Schema 就是最完整的 API 說明書

在傳統 REST API 的開發中,前端常常會有這些困擾:

  • 「這個欄位要傳什麼?有沒有格式限制?」
  • 「我打這個 API 會回傳什麼資料?會不會漏欄位?」
  • 「後端完成了嗎?為什麼找不到文件?」

而 GraphQL Schema 的出現,直接取代了 API 文件的角色。

因為它會明確定義每一個查詢、每一筆資料、每個欄位的格式與類型。

✅ 實際開發優勢:

  • 前端只要開啟一個 GraphQL playground(例如 Apollo Studio、GraphiQL),就可以即時查到可以查什麼、傳什麼、會回什麼。
  • 開發過程中不用等後端寫文件,也不需要來回問「這個 API 是什麼意思?」
  • 還能搭配 IntelliSense,自動補齊指令與欄位名稱,大幅減少錯打錯拼。

🟢 學會 Schema = 能自己探索 API,快速開發,不靠人解釋。

讓資料更安全:Schema 是資料的驗證機制

在 GraphQL 中,每一個欄位都必須在 Schema 裡明確指定型別與規則

例如:

type Post {
  id: ID!
  title: String!
  content: String
}

這代表:

  • idtitle必填欄位(不能為 null)
  • content可選欄位(可以為 null)
  • 三個欄位的資料型別都受到嚴格限制(不能亂傳數字給 String)

這種 Schema 驅動的驗證機制,會在前端請求送出之前後端解析資料之前就攔下錯誤,避免:

  • 傳錯格式的資料(例如把布林值傳成字串)
  • 漏傳必填欄位(例如漏了 title
  • 企圖存取不該出現的欄位(例如亂猜一個 authorEmail

✅ 實際開發優勢:

  • 不需要額外寫很多「驗證邏輯」就能確保資料正確
  • 減少錯誤請求進入後端系統,提升穩定性與可預測性
  • 如果你是後端開發者,也不用怕資料被寫壞或結構亂掉

🛡️ 學會 Schema = 系統自帶防呆機制,資料安全又乾淨。

讓團隊更有共識:Schema 是前後端的共同合約

GraphQL 的設計理念是:「一份 Schema,整個團隊通用」。

這份 Schema 不只是程式碼,還是整個團隊的協作規範與共識文件

  • 後端根據 Schema 開發 Resolver,提供資料來源
  • 前端根據 Schema 撰寫查詢,選擇自己要的欄位
  • 文件自動生成、型別自動對齊,雙方都清楚「資料長什麼樣子」

比起 REST API 常見的「前端亂猜後端會給什麼、後端不知道前端會怎麼用」。

GraphQL 的 Schema 為整個團隊建立了明確且同步的介面契約

✅ 實際團隊合作優勢:

  • 每個人都可以打開同一份 Schema,馬上理解整體資料模型與使用方式
  • 新人加入團隊,只要讀 Schema 就能上手
  • 即使後端還沒實作資料源,前端也可以用 mock schema 模擬開發流程(Mock Server)

🤝 學會 Schema = 擁有一份團隊溝通的「單一真相來源」(single source of truth)

總結:掌握 Schema,就是掌握 GraphQL 的核心力量

不論你是前端、後端、全端,甚至產品經理,只要你要和資料打交道,GraphQL Schema 就是你最該理解、最該信任的一份地圖。

  • 想開發快 ➜ 看 Schema 就知道怎麼查資料
  • 想寫資料準 ➜ Schema 幫你防呆
  • 想合作順 ➜ Schema 是大家共通語言

📌 Schema-first 的思維,是你進入現代前後端協作世界的入場券。

Similar Posts