API 的進化之路:從 XML 到 GraphQL,打造跨系統的共同語言
更新日期: 2025 年 3 月 4 日
本文為 Web 架構進化史 系列文,第 3 篇:
當程式也需要「共同語言」
想像一個跨國會議:來自不同國家的人們,必須用同一種語言溝通才能達成共識。
在軟體世界中,API(應用程式介面)就是這樣的「共同語言」,它讓前端、後端、手機 App、甚至 IoT 設備能互相理解。
本文將揭開 API 設計的基礎面紗,從資料格式的演變(XML → JSON)到三大主流風格(RPC、REST、GraphQL),帶你掌握選擇溝通方式的關鍵思維。
資料格式演變:從 XML 到 JSON 的進化史
XML:結構嚴謹的「正式公文」
在 1990 年代末至 2000 年代初,XML 是資料交換的主要格式。
它的誕生是為了解決不同系統間的數據傳輸問題,並廣泛應用於企業級應用、政府系統與標準化文件處理。
XML 的特性
- 使用 標籤(Tag) 來定義資料結構,類似於 HTML,但更具描述性與自定義能力。
- 強調結構的嚴謹性,通常需要搭配 XSD(XML Schema Definition) 或 DTD(Document Type Definition) 來定義格式,確保資料的一致性與正確性。
- 支援巢狀結構,適合處理層級較深、關係複雜的數據。
- 跨平台支援良好,被許多企業級應用與 Web 服務(如 SOAP)採用。
XML 的範例
以下是一個透過 XML 傳遞商品資訊的例子:
<product>
<id>123</id>
<name>無線鍵盤</name>
<price>1990</price>
<stock>true</stock>
</product>
XML 的優缺點
✅ 優點:
- 適合 複雜資料結構,能夠清楚地描述資料層級與關聯性。
- 提供 良好的擴展性,可以透過命名空間(Namespace)避免標籤名稱衝突。
- 適用於 企業級系統,特別是金融、政府、醫療等領域。
❌ 缺點:
- 資料冗長:標籤占據較大比例,導致文件大小較大。
- 解析速度較慢:需要透過 DOM 或 SAX 解析器來處理,耗費較多效能。
- 對 JavaScript 不友好:瀏覽器端處理 XML 需要額外的解析步驟,相較於 JSON 來說不夠直覺。
JSON:輕量化的「便利貼」
隨著 Web 2.0、AJAX(Asynchronous JavaScript and XML)技術的普及,以及 JavaScript 在前端開發中的主導地位,JSON 漸漸取代 XML 成為 Web API 的主要資料格式。
JSON 的特性
- 語法源自 JavaScript 物件,可以直接被 JavaScript 解析與使用。
- 結構 簡潔明瞭,不需要額外的標籤來描述數據,僅使用大括號
{}
和方括號[]
來組織資料。 - 解析速度快,能夠直接轉換為 JavaScript 物件,無需額外的解析步驟。
- 天然適合 Web 開發,廣泛應用於 RESTful API、前端與後端數據交換、行動應用 等領域。
JSON 的範例
與 XML 相同的商品資訊,若使用 JSON 表達則如下所示:
{
"product": {
"id": 123,
"name": "無線鍵盤",
"price": 1990,
"inStock": true
}
}
JSON 的優缺點
✅ 優點:
- 輕量簡潔,去除了多餘的標籤,資料體積小,適合網路傳輸。
- 解析速度快,可直接轉換為 JavaScript 物件,減少處理時間。
- 對 JavaScript 友好,不需要額外的解析工具即可使用,適合現代 Web 開發。
❌ 缺點:
- 缺乏嚴格的格式驗證,不像 XML 具有 XSD 或 DTD,容易導致格式錯誤。
- 不適合高度結構化的數據,例如需要描述複雜關聯的企業級系統。
- 安全性問題,若未妥善處理 JSON,可能會受到 XSS(跨站腳本攻擊)影響。
資料格式對比表
特性 | XML | JSON |
---|---|---|
資料類型 | 需額外定義(XSD) | 原生支援字串、數字、布林值 |
檔案大小 | 較大(標籤重複) | 較小(無冗餘標籤) |
解析速度 | 慢(需透過 DOM 解析) | 快(可直接轉換為 JS 物件) |
可讀性 | 可讀性較低,標籤冗長 | 可讀性較高,結構簡潔 |
適用場景 | 企業系統、標準化文件(如銀行、醫療) | Web API、行動應用、前後端數據交換 |
XML 與 JSON 的轉變:關鍵影響因素
XML 曾經是 Web 開發中的主要資料格式,但隨著技術環境的變遷,JSON 逐漸成為主流,這背後有幾個重要的關鍵影響因素:
- 行動網路時代的來臨:
- XML 的冗長結構使其在行動環境下不夠高效,而 JSON 的輕量特性更適合節省頻寬的需求。
- AJAX 與 Web 2.0 的崛起:
- AJAX 允許前端與伺服器進行非同步數據交換,而 JSON 由於與 JavaScript 的高兼容性,成為 AJAX 開發的最佳選擇。
- REST API 的流行:
- 相較於傳統的 SOAP(Simple Object Access Protocol)API,RESTful API 更簡單、易讀,而 JSON 作為 REST API 的主要數據格式,推動了它的普及。
- 瀏覽器與後端技術的支援:
- 現代瀏覽器與後端框架(如 Node.js、Python Flask、Ruby on Rails)皆內建 JSON 解析功能,使其成為 Web 開發的標準格式。
延伸閱讀:JSON 的故事:Douglas Crockford 的訪談
API 風格大亂鬥:RPC、REST、GraphQL 的設計哲學
在現代軟體開發中,API(Application Programming Interface)扮演著關鍵角色,它是不同系統、服務之間溝通的橋樑。
隨著需求的多樣化,開發者設計出了 RPC(Remote Procedure Call)、REST(Representational State Transfer)、GraphQL 三種主流 API 風格。
這三種 API 各有其核心理念與適用場景,選擇合適的設計模式能夠提升系統效能、可維護性與開發效率。
以下將深入剖析它們的設計哲學、優缺點與應用場景。
RPC(遠程過程調用):像打電話下指令
核心理念
RPC 的設計目標,是讓呼叫遠端 API 像執行本地函數一樣簡單,不需要關心底層通訊細節,只需提供方法名稱與參數即可執行動作。
這種風格適合內部系統,特別是需要頻繁調用遠端方法的場景,例如微服務架構中的服務間通訊。
RPC 的特性
- 方法導向:API 的主要概念是「動作」,而非「資源」。
- 通常透過 HTTP POST 發送請求,但也可以使用其他協議(如 gRPC 基於 HTTP/2)。
- 方法名稱與參數封裝在請求體內,而不是像 REST API 那樣依賴 URL 路徑。
RPC API 呼叫範例
POST /api
Content-Type: application/json
{
"method": "getProduct",
"params": { "id": 123 }
}
優缺點
✅ 優點:
- 直覺易用:開發者只需關心「調用什麼方法」,不必設計 API 資源模型。
- 適合內部微服務:可以讓服務之間進行高效能的函數級調用,如 gRPC(Google RPC)。
❌ 缺點:
- 缺乏統一標準:不同系統可能有不同的 API 格式,導致維護成本增加。
- 擴展性較差:當 API 方法數量增加時,命名與管理變得困難,例如
getProductV1
、getProductV2
可能會讓 API 混亂。 - 難以符合 RESTful 風格的標準化設計,如 HTTP 狀態碼、快取等特性。
REST:以資源為中心的「寫信溝通」
核心理念
REST 的設計哲學是 將所有事物視為「資源」(Resource),並透過 HTTP 方法來進行操作,符合 Web 既有的標準。
這種風格使 API 易於理解、維護,並具有高度的可擴展性。
REST 的特性
- 以「資源」為核心,而非函數調用。
- 使用標準 HTTP 方法:
GET
:取得資源POST
:新增資源PUT
:更新資源DELETE
:刪除資源
- 無狀態(Stateless):每次請求都是獨立的,不依賴伺服器端的會話狀態。
- 統一介面(Uniform Interface):API 使用標準化的 HTTP 狀態碼(如 200、404、500)來回應客戶端請求。
RESTful API 呼叫範例
GET /products/123 # 取得商品 123
POST /products # 新增商品
PUT /products/123 # 更新商品 123
DELETE /products/123 # 刪除商品 123
優缺點
✅ 優點:
- 標準化:符合 HTTP 規範,易於理解與使用。
- 可快取:GET 請求可利用瀏覽器或 CDN 快取,提高效能。
- 適合公開 API:如社群網站、電商平台等開放給開發者使用的 API。
❌ 缺點:
- 過度或不足取得資料(Over-fetching / Under-fetching):客戶端可能會獲取過多或過少的數據,例如需要
name
和price
,卻只能獲得整個product
物件。 - 難以處理複雜關聯查詢:當客戶端需要一次性獲取多個相關資源時,可能需要多次請求或額外的
/products?include=reviews
這類參數。
補充:REST vs RPC:關鍵差異與設計哲學
REST 和 RPC 的主要差異在於 它們如何組織 API,以及 它們如何讓客戶端與伺服器溝通。
📌 RPC(Remote Procedure Call):像打電話執行函數
RPC 的設計哲學
RPC 把 API 設計成「遠端函數調用」,就像在本地執行一個函數一樣。
當客戶端想要執行某個動作時,只需要呼叫對應的方法名稱並傳入參數,伺服器就會執行該方法並回傳結果。
RPC 的 API 請求格式
客戶端的請求通常是 一個方法名稱 + 參數,例如:
POST /api Content-Type: application/json { "method": "getProduct", "params": { "id": 123 } }
🔹 這就像是在「打電話給客服」,直接告訴對方你想要做什麼,例如:「請幫我查詢商品 123!」
RPC 的特性
- 以「動作」(Action)為核心:API 的請求本質上就是呼叫某個函數,如
getProduct()
、calculateShipping()
。- 不關心「資源」的概念,只在乎執行什麼動作。
- 方法名稱是 API 的核心,不像 REST 會使用 URL 來描述資源。
📌 REST(Representational State Transfer):像寫信請求資源
REST 的設計哲學
REST 的核心理念是 「萬物皆資源」(Everything is a Resource)。
在 REST API 中,每個 API 端點代表一種「資源」(Resource),例如 商品、使用者、訂單 等,而不是函數或方法。客戶端透過 HTTP 方法(GET、POST、PUT、DELETE)來對這些資源進行操作。
REST 的 API 請求格式
如果我們要查詢商品 123,REST API 會這樣設計:
GET /products/123
🔹 這就像是「寫信給某個部門」,請求獲取某個資源,例如:「請寄給我商品 123 的資訊!」
REST 的特性
- 以「資源」(Resource)為核心,而非函數調用。
- 使用標準 HTTP 方法來操作資源:
GET /products/123
→ 取得商品 123 的資訊POST /products
→ 新增一個商品PUT /products/123
→ 更新商品 123 的資訊DELETE /products/123
→ 刪除商品 123- 無狀態(Stateless):每次請求都是獨立的,伺服器不會記住客戶端的狀態。
- 統一介面(Uniform Interface):使用標準的 HTTP 方法與狀態碼(如 200、404、500)。
📌 RPC vs REST:具體對比
特色 RPC REST 核心概念 呼叫函數(動作導向) 存取資源(資源導向) 請求方式 透過 POST,傳送方法名稱和參數 透過標準 HTTP 方法(GET、POST、PUT、DELETE) URL 設計 通常是 /api,方法名稱放在請求體內 URL 直接表示資源,如 /products/123 擴展性 方法越多,API 變得越複雜(需管理大量函數) 結構化設計,適合長期擴展 適用場景 內部系統、微服務架構 公開 API、標準化服務 📌 簡單比喻:打電話 vs 寫信
RPC REST 像是 打電話給客服,下指令:「幫我查詢商品 123!」 寫信給公司請求資訊:「請提供商品 123 的詳細資料。」 請求方式 直接告訴伺服器要執行哪個函數 透過 URL 表示資源,請求對該資源的操作 擴展性 API 變大時會變得混亂 API 變大時仍然有結構
📌 什麼時候選擇 RPC?什麼時候選擇 REST?
✅ 選 RPC 當:
- 內部系統,如微服務之間的通訊。
- 需要高效能、低延遲的 API(例如 gRPC)。
- 主要在做函數級的操作,而非管理資源。
✅ 選 REST 當:
- 需要設計 標準化、可公開的 API(例如社群平台、電商 API)。
- 需要 API 易於理解、可擴展,並與 HTTP 標準相容。
- 希望透過 URL 直覺地表示資源(例如
/users/123/orders
代表查詢某用戶的訂單)。
GraphQL:自助餐式的「精準查詢」
核心理念
GraphQL 由 Facebook 於 2015 年開源,其核心理念是讓客戶端自行定義所需的數據結構,避免過度獲取(Over-fetching)或不足獲取(Under-fetching)問題。
GraphQL 的特性
- 單一入口(Single Endpoint):所有請求都透過
/graphql
端點發送。 - 客戶端決定請求內容,避免獲取不必要的數據。
- 強型別系統:需要定義
Schema
來描述 API 結構,確保請求與回應的一致性。 - 支援即時更新(Subscription),適合即時應用,如聊天系統或動態消息。
GraphQL API 查詢範例
query {
product(id: 123) {
name
price
}
}
GraphQL 回應範例
{
"data": {
"product": {
"name": "無線鍵盤",
"price": 1990
}
}
}
優缺點
✅ 優點:
- 精準查詢:客戶端只獲取所需的數據,減少不必要的數據傳輸。
- 適合複雜關聯數據:可一次請求獲取多個相關資源,減少多次 API 呼叫的負擔。
- 靈活性高:適用於不同裝置(如手機、平板、桌機)需要不同數據的場景。
❌ 缺點:
- 學習曲線較高:相較於 REST,開發者需要學習 GraphQL 語法與 Schema 定義。
- 快取較難:由於所有請求都發送到
/graphql
,不如 REST API 容易利用瀏覽器與 CDN 快取。
補充:REST vs GraphQL:關鍵差異與設計哲學
REST 和 GraphQL 都是 API 設計的方式,但它們的核心理念與數據請求方式截然不同。
REST 強調資源導向,透過固定的 API 端點(Endpoint)取得數據,而 GraphQL 則是查詢導向,允許客戶端自由定義所需的數據格式。
📌 REST(Representational State Transfer):以資源為中心的 API 設計
REST 的設計哲學
REST 把 API 視為一組資源(Resource),每個資源都有一個固定的 URL,並透過 HTTP 方法(GET、POST、PUT、DELETE)來操作它們。
REST 的 API 設計範例
假設我們要查詢商品(Product)的資訊,在 REST API 中,請求方式如下:
GET /products/123
如果我們同時想獲取商品的評論(Reviews),可能需要額外的 API 請求:
GET /products/123/reviews
🔹 REST 會根據資源類型提供不同的端點,每個端點回傳的資料格式是固定的,開發者無法選擇回傳哪些欄位。
REST 的特性
- 以「資源」(Resource)為核心,每個 API 端點對應一個資源類型。
- 使用固定的 HTTP 方法(GET、POST、PUT、DELETE)來操作資源。
- 無狀態(Stateless):每次請求都是獨立的,不依賴伺服器的會話狀態。
- 統一介面(Uniform Interface):不同的 API 遵循一致的設計原則,例如使用
GET
來取得資料,而不是POST
。📌 GraphQL:以查詢為中心的 API 設計
GraphQL 的設計哲學
GraphQL 由 Facebook 在 2015 年開源,它的核心理念是讓客戶端可以精確查詢所需的資料,避免獲取過多或過少的數據。
GraphQL 的 API 設計範例
在 GraphQL 中,客戶端可以用 一個查詢請求(Query) 取得所需的商品資訊和評論:
query { product(id: 123) { name price reviews { rating comment } } }
GraphQL 伺服器只會回傳客戶端要求的欄位,例如:
{ "data": { "product": { "name": "無線鍵盤", "price": 1990, "reviews": [ { "rating": 5, "comment": "超好用!" }, { "rating": 4, "comment": "不錯,但有點貴。" } ] } } }
🔹 GraphQL 允許客戶端自由選擇需要的欄位,不會像 REST 一樣回傳固定的資料格式。
GraphQL 的特性
- 以「查詢」(Query)為核心,客戶端可以指定所需的資料欄位。
- 單一端點(Single Endpoint):所有請求都發送到
/graphql
,而不是像 REST 一樣使用多個端點(如/products
、/users
)。- 避免過度或不足取得資料(Over-fetching / Under-fetching):客戶端可以精準控制回傳的欄位內容,減少不必要的數據傳輸。
- 支援關聯查詢(Nested Queries):可以一次請求獲取多個相關資源的數據,而不需要發送多個 API 請求。
- 強型別系統(Schema):需要先定義 API 的數據結構(Schema),確保請求與回應的數據格式一致。
📌 REST vs GraphQL:具體對比
特性 REST GraphQL 核心概念 以「資源」(Resource)為中心 以「查詢」(Query)為中心 端點設計 多個端點(如 /products/123、/users/456) 單一端點 /graphql 請求方式 GET /products/123 取得商品資訊 query { product(id: 123) { name price } } 數據回傳 固定的欄位,可能包含不需要的數據 客戶端指定所需的欄位,精準回傳 關聯數據查詢 需要多個 API 請求(如 /products/123/reviews) 可在單一查詢中獲取關聯數據 快取機制 瀏覽器和 CDN 可透過 URL 快取 GET 請求 由於使用 POST,無法直接快取 適用場景 標準化 API(如電商 API、社群平台 API) 需要高度靈活性(如行動裝置、多端應用) 📌 簡單比喻:固定菜單 vs 自助餐
REST GraphQL 像是 固定菜單的餐廳:菜單上有固定的菜色(API 回傳固定的欄位)。 自助餐:客戶可以自由選擇自己想吃的東西(客戶端決定回傳哪些欄位)。 請求方式 每個資源都有獨立的端點,如 /products/123、/users/456 只有一個 /graphql 端點,客戶端決定查詢內容 數據回傳 伺服器回傳完整的資料,即使客戶端只需要其中一部分 客戶端只獲取自己想要的欄位,避免浪費帶寬 關聯數據 可能需要多次請求(如 /products/123/reviews) 可以一次獲取所有關聯數據 適合場景 標準化 API,易於快取與管理 需要靈活查詢的應用,如儀表板、行動應用
📌 什麼時候選擇 REST?什麼時候選擇 GraphQL?
✅ 選 REST 當:
- API 需要標準化,並且對不同的客戶端回傳相同的資料格式。
- 快取(Caching)是重點,例如新聞網站、靜態內容等。
- 系統簡單,數據關聯性不強,例如電商 API、社群網站 API。
✅ 選 GraphQL 當:
- 客戶端需求多變,例如不同裝置(手機、平板、桌機)需要不同的欄位。
- 數據關聯性高,需要一次查詢獲取多個相關資源(如 Facebook 動態消息)。
- 需要減少 API 請求數量,提升效能(如行動應用)。
API 設計選擇指南
特性 | RPC | REST | GraphQL |
---|---|---|---|
核心概念 | 動作(Action) | 資源(Resource) | 查詢(Query) |
請求方法 | 多數用 POST | 符合 HTTP 方法 | 只用 POST 或 GET |
適用場景 | 內部系統、微服務 | 公開 API、標準化系統 | 需要精準查詢、關聯數據 |
如何選擇?
✅ 選 RPC → 內部微服務、高效能函數調用
✅ 選 REST → 標準化 API、可快取的系統
✅ 選 GraphQL → 客戶端需求多變、複雜數據查詢
實戰範例:用 Python 體驗三種風格
RPC 風格實作(Flask 框架)
from flask import Flask, jsonify, request
app = Flask(__name__)
@app.route('/api', methods=['POST'])
def handle_rpc():
data = request.json
if data['method'] == 'get_product':
return jsonify({"result": {"id": 123, "name": "鍵盤"}})
else:
return jsonify({"error": "方法不存在"})
REST 風格實作(FastAPI 框架)
from fastapi import FastAPI
app = FastAPI()
products = {123: {"name": "鍵盤", "price": 1990}}
@app.get("/products/{product_id}")
def get_product(product_id: int):
return products.get(product_id)
GraphQL 風格實作(Ariadne 套件)
from ariadne import QueryType, make_executable_schema
from ariadne.asgi import GraphQL
type_defs = """
type Query {
product(id: ID!): Product
}
type Product {
id: ID!
name: String!
price: Int!
}
"""
query = QueryType()
@query.field("product")
def resolve_product(*_, id):
return {"id": id, "name": "鍵盤", "price": 1990}
schema = make_executable_schema(type_defs, query)
app = GraphQL(schema)
總結:沒有最佳解,只有最合適的解
從 XML 到 JSON,從 RPC 到 GraphQL,API 設計的演變反映了軟體開發的核心需求:在結構與彈性之間取得平衡。
作為新手,不必追求「最新潮」的技術,而應:
- 理解每種風格的適用場景
- 根據團隊規模與專案需求選擇
- 保持介面設計的一致性