GraphQL 是什麼?為什麼它比 REST 更靈活?
更新日期: 2025 年 4 月 28 日
隨著前端技術的快速發展,資料需求的複雜度也越來越高。
傳統的 REST API 雖然穩定可靠,但在某些情境下卻顯得不夠靈活、容易過載,甚至帶來開發效率低下的問題。
因此,一種新的資料溝通方式——GraphQL,迅速崛起,成為現代前後端溝通的新寵。
本篇文章將用最白話的方式帶你了解:
- GraphQL 是什麼?
- 它和 REST 的差異在哪?
- GraphQL 的三種操作(Query、Mutation、Subscription)
- 為什麼現代開發越來越愛用 GraphQL?
API 與 SQL 的關係與差異
在現代應用開發中,「前端」和「後端」經常需要打 API 拿資料,但資料最根本是存在哪裡呢?
答案是:資料通常存放在資料庫,而操作資料庫的語言,就是 SQL。
所以,可以簡單理解成:
🔗 API 是「跟後端要資料」的橋樑,SQL 是「後端去資料庫取資料」的工具。
API 和 SQL 是不同層次的東西,但在一個完整的資料流中,它們是互相串起來的。
API 是「對外」的
- API(Application Programming Interface)
是後端開放給前端或其他系統使用的介面。 - 它負責接收請求,例如:
- 我要某個使用者資料
- 我要新增一筆訂單
- 後端收到 API 請求後,自己內部用 SQL 跟資料庫溝通,拿到資料後,再回傳給前端。
📦 可以把 API 想像成餐廳的「點餐窗口」:
- 客人(前端)來點餐(請求)
- 餐廳內部(後端)自己去廚房(資料庫)拿食材
- 再把做好的餐(資料)送回給客人
SQL 是「對內」的
- SQL(Structured Query Language)
是一種專門操作資料庫的語言,主要用來: - 查資料 (
SELECT
) - 新增資料 (
INSERT
) - 更新資料 (
UPDATE
) - 刪除資料 (
DELETE
) - 只有後端工程師(或資料庫管理員)直接操作 SQL。
- 前端看不到 SQL,通常只看到 API 回傳的資料結果。
📦 把 SQL 想像成「廚房內部的指令」:
- 廚師(後端)根據訂單(API)去廚房(資料庫)拿東西
- 用不同的指令(SQL)拿出食材、調整分量、做出成品
簡單流程圖
這是最常見的資料流順序:
flowchart LR Frontend["前端"] API["API 請求"] Backend["後端"] SQL["SQL 查詢"] Database["資料庫"] Frontend --> API API --> Backend Backend --> SQL SQL --> Database Database -->|回傳資料| Backend Backend -->|回傳資料| Frontend
用一個例子說明:
- 使用者打開 App,想查詢自己的訂單
- App 送出 API 請求:
GET /orders?userId=123
- 後端接收到後,用 SQL 查資料:
SELECT * FROM orders WHERE user_id = 123;
- 資料庫把訂單資料回傳給後端
- 後端包成 JSON 格式,回傳給 App
- App 顯示訂單資訊給使用者
什麼是 GraphQL?
GraphQL 是由 Facebook 在 2012 年提出,並於 2015 年開源的一種API 資料查詢語言(Query Language for APIs)。
它讓前端可以用一種直覺、靈活的方式向後端請資料,只拿到自己需要的資料,不多也不少。
簡單來說,GraphQL 像是:
🍱 點餐一樣,自己決定想要哪些菜色,不需要整份套餐打包。
相較於 REST 那種「一個 URL 對應一種資料格式」的設計,GraphQL 讓前端可以自訂資料內容,而不是被動接受後端給的全部資料。
GraphQL vs REST API:差在哪?
比較項目 | REST API | GraphQL |
---|---|---|
資料取得方式 | 一個 endpoint = 一種資料格式 | 一個 endpoint(通常是 /graphql)可以根據請求取得不同資料 |
資料冗餘問題 | 常常拿到不需要的資料 | 自己指定要哪些欄位 |
多筆資料請求 | 可能需要多次 HTTP Request | 一次請求拿到所有需要的資料 |
文件與型別檢查 | 需靠 API 文件或 Swagger 手動對照 | Schema 自帶型別與文件化,直接對照 |
資料更新 | 用 POST/PUT/PATCH | 用 Mutation 指令完成更新 |
在傳統 REST API 中,我們通常需要針對不同資料設計不同的路由,例如:
/users/1
查詢使用者資訊/posts/123
查詢文章內容
每一種資料對應一條特定的路由,路由的結構與資料緊密綁定。
而在 GraphQL 中,設計方式完全不同:
GraphQL 不是前端自己定義「路由」,而是前端自己定義「要什麼資料」。
在 GraphQL 的架構裡:
- 後端只需要提供一個固定的端點(通常是
/graphql
) - 前端無需知道有多少路由存在
- 取而代之的是,前端在送出請求時,直接附上一段 查詢指令(Query),
精確描述自己想要的資料內容和欄位結構
這段 Query 會隨著請求一同送到 /graphql
,由伺服器解析後,動態產生對應的資料查詢。
舉個例子
傳統 REST 可能這樣請求:
GET /users/1
而在 GraphQL 中,無論是查詢哪個使用者,都會送到同一個 /graphql
,只是在內容中這樣描述:
query {
user(id: 1) {
name
email
posts {
title
}
}
}
這樣的設計,帶來了極高的靈活性:
- 前端可以自由選擇需要哪些欄位
- 減少了後端為每個不同需求設計獨立 API 路由的負擔
- 同一個端點即可支援各種不同資料的讀取、更新,甚至訂閱
✅ 這種「一個端點 + 動態查詢」的方式,是 GraphQL 相較於傳統 REST 更加彈性與高效的重要特點之一。
GraphQL 的三大核心操作
在 GraphQL 中,所有資料的互動,無論是查詢、更新,還是即時通訊,
都可以歸納成這三種基本操作型態:
- Query(讀資料)
- Mutation(改資料)
- Subscription(即時資料)
了解這三種操作,是掌握 GraphQL 使用方法的基礎。
Query:讀取資料
✨ 什麼是 Query?
Query 就是讀取資料的動作。
你可以把它想成:
📚 「問資料庫問題,請它回你一個答案。」
- 你可以指定想要哪一筆資料
- 你可以選擇只拿需要的欄位
- Server 根據你的 Query,回傳對應的資料
✅ 重點是:Query 不會改變後端的資料,只是拿資料回來。
📖 小範例:查詢使用者的基本資訊
query {
user(id: "1") {
name
email
}
}
這段 Query 的意思是:
- 我要找 ID 是
1
的使用者 - 但我只要他的
name
和email
- 其他欄位(像是
createdAt
、password
)一概不要
Server 回傳的資料會是這樣:
{
"data": {
"user": {
"name": "Alice",
"email": "[email protected]"
}
}
}
✅ 乾淨、精簡,剛好符合需求,不多也不少。
Mutation:修改資料
✨ 什麼是 Mutation?
Mutation 是用來改變資料的操作。
你可以把它想成:
✏️ 「提交新的資料,或修改、刪除現有的資料。」
常見的情境包括:
- 新增一筆資料(例如新增一則留言)
- 更新一筆資料(例如修改使用者的 email)
- 刪除一筆資料(例如刪除一篇文章)
✅ 只要資料會改變,就一定要用 Mutation,而不是 Query。
📖 小範例:新增一則留言(Comment)
mutation {
createComment(input: { text: "好文章!", postId: "123" }) {
id
text
createdAt
}
}
這段 Mutation 的意思是:
- 呼叫
createComment
這個 Mutation API - 傳入一個
input
物件,包括: text
: 留言內容postId
: 這篇留言屬於哪一篇文章- 期待回傳新建立的留言的
id
、text
、createdAt
伺服器回傳的資料可能是:
{
"data": {
"createComment": {
"id": "789",
"text": "好文章!",
"createdAt": "2024-01-01T00:00:00Z"
}
}
}
✅
Mutation 不僅會改變資料,而且可以像 Query 一樣指定回傳哪些欄位,
不必回傳一整筆資料,這也是 GraphQL 的彈性之一。
Subscription:即時資料推播
✨ 什麼是 Subscription?
Subscription 是用來即時監聽資料變化的一種特殊操作。
你可以把它想成:
🔔 「訂閱某個事件,一有變化就即時通知我。」
適合的使用情境包括:
- 聊天室新訊息推播
- 股票報價即時更新
- 遊戲進行中的玩家狀態變化
- 訂單出貨狀態變更通知
✅ Subscription 會建立一條持續的連線(通常是 WebSocket)。
伺服器一有新資料,就主動推送到前端,不需要前端重複拉資料。
📖 小範例:訂閱新的訊息
subscription {
newMessage {
id
content
sender
}
}
這段 Subscription 的意思是:
- 監聽伺服器上的
newMessage
事件 - 每當有新訊息產生,就即時收到推送
- 只需要
id
、content
、sender
這三個欄位
當後端有新訊息時,前端會即時收到這樣的資料:
{
"data": {
"newMessage": {
"id": "555",
"content": "嗨,早安!",
"sender": "Alice"
}
}
}
✅ 不需要前端主動發起查詢,資料會自動「推」過來,非常適合即時互動的場景。
GraphQL 是如何運作的?從 Schema 開始說起
在 GraphQL 中,有一個非常重要的核心觀念:
所有能做的事情,都必須先在後端定義好 Schema,前端才能使用。
這種設計方式,稱為 Schema-First。
也就是說:
不論是查詢(Query)、修改(Mutation)、即時訂閱(Subscription),全部都必須事先在 Schema 中定義,才能讓前端呼叫。
這點和傳統 REST API 很不一樣。
在 REST 中,後端只要開好一條 API 路徑,前端就能去呼叫。
但在 GraphQL,Schema 就像是一份契約,明確列出:
- 可以查哪些資料
- 每個資料有哪些欄位
- 可以進行哪些操作(新增、修改、刪除、訂閱)
- 每個操作需要哪些參數,回傳什麼資料
如果 Schema 裡沒有定義,那麼即使前端寫了對應的 Query,也無法執行,伺服器會直接回傳錯誤。
具體例子:如果後端沒定義,會發生什麼事?
假設後端工程師沒有定義 createComment
這個 Mutation,但前端卻寫了這樣一段指令:
mutation {
createComment(input: { text: "好文章!", postId: "123" }) {
id
text
}
}
當這段請求送到 GraphQL Server 時,伺服器會發現:
在目前的 Schema 裡,根本不存在 createComment
這個操作。
結果伺服器會直接拒絕,並回傳錯誤訊息,像這樣:
{
"errors": [
{
"message": "Cannot query field 'createComment' on type 'Mutation'.",
"locations": [{ "line": 2, "column": 3 }]
}
]
}
✅ 這就是 GraphQL 的運作規則:
前端能發送的指令,永遠必須依照後端 Schema 的定義來寫。
那麼,Schema 在整個 GraphQL 系統中扮演什麼角色?
可以這樣理解:
角色 | 功能 |
---|---|
Schema | 是整個系統的「資料目錄表」,列出所有可用的資料型別、操作方法、參數要求 |
GraphQL Server | 根據 Schema,驗證每個請求是否合法,並自動導向正確的 Resolver 執行 |
前端工程師 | 必須根據 Schema,正確撰寫查詢(Query)或修改(Mutation)指令 |
✅ 可以說,Schema 就是前後端共同遵守的 API 契約。
沒有 Schema,GraphQL 系統根本無法運作。
更直覺的比喻:GraphQL 就像點餐系統
如果把 GraphQL 開發比喻成餐廳:
- Schema 就是菜單 ➔ 告訴你這間餐廳有什麼可以點。
- 前端寫的 Query/Mutation 就是客人的點單 ➔ 告訴廚房想吃什麼。
- GraphQL Server 是負責收單、檢查單、安排出餐的服務員。
- Resolver 則是後台真正煮菜的廚師。
如果菜單上根本沒有「龍蝦義大利麵」這道菜, 就算客人在點單上寫了,也會被服務員直接打回來。
因為廚房不支援這個品項。
✅ 這就是為什麼,在 GraphQL 世界裡,Schema 永遠是第一位的。
GraphQL 為什麼越來越流行?
GraphQL 出現後,越來越多前後端團隊開始採用它來取代傳統的 REST API。
原因並不是因為 REST 不好,而是現代前端應用的需求變了,而 GraphQL 剛好很好地解決了這些新需求。
以下是 GraphQL 流行的四大主因:
資料自由選取 ➔ 減少過度請求
問題:REST API 資料量常常「不是太多,就是太少」
在傳統 REST API 設計中:
- 一個 endpoint 回傳一整個固定格式的資料包
- 常常有這些情況:
- 資料太多:只想要用戶名稱,卻拿回整份用戶資料(包含密碼加密、地址、生日等用不到的欄位)
- 資料太少:只拿到用戶基本資料,卻又要另外打一個 API 才能拿到該用戶的訂單紀錄
這樣會導致:
- 浪費流量
- 增加伺服器負載
- 增加前端開發難度(要自己拼接多個 API 回來的資料)
GraphQL 的做法:前端自由挑選要的欄位
在 GraphQL 中,前端可以精確指定需要哪些欄位, 而後端只回傳這些欄位的資料。
✅ 好處:
- 減少傳輸的資料量 ➔ 流量更小
- 加速資料載入 ➔ 使用者體驗更順
- 節省網路與伺服器資源
API 維護更靈活 ➔ 快速迭代
問題:REST API 維護麻煩
傳統 REST 的方式是:
- 一個資料一條 endpoint
- 每新增一個功能,常常就要開一條新的 API
- 前端需求變動時(例如要多顯示一個新欄位),後端也要修改原本的 API 或新增新 API
這種做法在專案成長到一定規模後會非常痛苦:
- API 數量暴增
- 維護困難
- 後端常常被迫跟著前端小改動小更新
GraphQL 的做法:一個端點,資料由前端自由選
GraphQL 通常只有一個統一的 endpoint(例如 /graphql
),
前端自己在 Query 中描述要什麼資料和欄位。
✅ 好處:
- 後端 Schema 定義好資料型別就好,不用為每個需求開新 API
- 前端可以靈活應對需求變化
- API 維護工作量大幅減少
- 能更快開發新功能、快速上線(快速迭代)
自帶文件、型別系統 ➔ 提高開發效率
問題:傳統 REST API 文件很容易不同步
- API 文件通常是「額外寫的」(例如 Swagger、Notion)
- API 一更新,文件沒跟上,前端就踩雷
- 沒有強制型別檢查,常常發生傳錯資料格式的錯誤
GraphQL 的做法:Schema 本身就是 API 文件
GraphQL 天生具備:
- Schema 定義型別:每個資料欄位的型別(String、Int、Object)都明確定義
- 自動產生互動式 API 文件:像是 GraphiQL、Apollo Studio 可以直接看、直接測試 API
- 強型別驗證:查詢不符合型別、缺少必填欄位,伺服器在開發階段就能即時報錯
✅ 好處:
- 減少前後端溝通誤會
- 開發時就能及早發現問題
- 整個開發流程更順、更快
最適合複雜前端應用(像是 SPA、App)
問題:複雜畫面要打好多個 REST API
舉例來說:
- App 的首頁同時要載入:
- 熱門文章列表
- 使用者個人資料
- 通知中心未讀數
- 商品頁要載入:
- 商品細節
- 商品庫存
- 商品評論
- 推薦商品列表
如果用傳統 REST API:
- 要打 3~5 個以上的 HTTP 請求
- 要等全部資料回來才能渲染頁面 ➔ 用戶覺得慢
GraphQL 的做法:一次請求,拿到全部資料
在 GraphQL 中,可以在一個 Query 裡面,同時查詢多種資料,像這樣:
query {
me {
name
email
}
hotPosts {
title
likes
}
notifications {
message
read
}
}
✅ 好處:
- 只打一個 HTTP 請求,減少延遲
- 一次拿回需要的所有資料
- 頁面可以更快完整顯示出來
- 使用者體感流暢度大幅提升
什麼時候該考慮用 GraphQL?
你可以考慮採用 GraphQL,特別是當你的專案符合以下情況時:
適用情境 | 說明 |
---|---|
資料結構複雜、多層巢狀 | 需要一次拿多種類型資料,避免打太多 API |
前端需求變動快 | 想要前端能自己靈活決定資料格式,不每次都改 API |
想減少多次 HTTP 請求 | 提升效能,減少等待時間 |
想要提升開發效率 | 自帶 API 文件、強型別檢查 |
需要即時資料推播 | 像聊天室、通知中心等場景適合用 Subscription |
✅
如果你的應用越來越接近這些情境,GraphQL 幾乎可以說是必備技術了!
總結一句話
GraphQL 解決了現代前端應用資料量大、需求多變、即時性高的問題,因此在 SPA、App、微服務架構中越來越受到青睞。