知識庫 / Web Services RSS 訂閱

GraphQL vs REST

REST,Web Services
HongKong
6
03:42 AM · Dec 06 ,2025

1. 概述

當創建用於支持我們應用程序的 Web 服務時,我們可能會選擇使用 REST 或 GraphQL 作為通信模式。雖然兩者都可能使用 HTTP 上的 JSON,但它們具有不同的優勢和劣勢。

在本教程中,我們將比較 GraphQL 與 REST。我們將創建一個產品數據庫示例,並比較在執行相同客户端操作時,這兩種解決方案之間的差異。

2. 示例服務

我們的示例服務將允許我們:

  • 創建草稿狀態的產品
  • 更新產品詳情
  • 獲取產品列表
  • 獲取單個產品的詳細信息,包括其訂單

讓我們從使用 REST 創建應用程序開始。

3. REST

REST (Representational State Transfer) 是一種用於分佈式超媒體系統的 架構風格。REST 的主要數據元素稱為 資源。在本示例中,資源是 “產品”

3.1. 創建產品

為了創建產品,我們將使用 API 的 POST 方法:

curl --request POST 'http://localhost:8081/product' \
--header 'Content-Type: application/json' \
--data '{
  "name": "Watch",
  "description": "Special Swiss Watch",
  "status": "Draft",
  "currency": "USD",
  "price": null,
  "imageUrls": null,
  "videoUrls": null,
  "stock": null,
  "averageRating": null
}'

因此,系統將創建一個新的產品。

3.2. 更新產品

在 RESTful 架構中,我們通常使用 PUT 方法來更新產品:

curl --request PUT 'http://localhost:8081/product/{product-id}' \
--header 'Content-Type: application/json' \
--data '{
    "name": "Watch",
    "description": "Special Swiss Watch",
    "status": "Draft",
    "currency": "USD",
    "price": 1200.0,
    "imageUrls": [
        "https://graphqlvsrest.com/imageurl/product-id"
    ],
    "videoUrls": [
        "https://graphqlvsrest.com/videourl/product-id"
    ],
    "stock": 10,
    "averageRating": 0.0
}'

因此,對象將會更新。

3.3. 獲取產品列表

列出產品通常是一個 GET 操作,我們可以使用查詢字符串來指定分頁:

curl --request GET 'http://localhost:8081/product?size=10&page=0'

第一個響應對象是:

{
  "id": 1,
  "name": "T-Shirt",
  "description": "Special beach T-Shirt",
  "status": Published,
  "currency": "USD",
  "price": 30.0,
  "imageUrls": ["https://graphqlvsrest.com/imageurl/1"], 
  "videoUrls": ["https://graphqlvsrest.com/videourl/1"], 
  "stock": 10, 
  "averageRating": 3.5 
}

3.4. 獲取包含訂單的單個產品

為了獲取產品及其訂單,我們通常會先通過之前的 API 獲取產品列表,然後通過對 訂單 資源進行調用來查找相關訂單:

curl --request GET 'localhost:8081/order?product-id=1'

第一個響應對象是:

{
  "id": 1,
  "productId": 1,
  "customerId": "de68a771-2fcc-4e6b-a05d-e30a8dd0d756",
  "status": "Delivered",
  "address": "43-F 12th Street",
  "creationDate": "Mon Jan 17 01:00:18 GST 2022"
}

當我們通過產品 ID查詢訂單時,將 ID 作為查詢參數提供給 GET 操作是有意義的。然而,我們也需要注意到,我們需要為我們感興趣的每個產品執行一次此操作,再加上原始操作以檢索所有產品。這與 N + 1 查詢問題相關。

4. GraphQL

GraphQL 是一種用於 API 的查詢語言,它提供了一個框架來使用現有的數據服務來滿足這些查詢。

GraphQL 的基本構建塊是 查詢和變體。查詢負責獲取數據,而變體則用於創建和更新。

查詢和變體都定義一個 模式。模式定義了可能的客户端請求和響應。

讓我們使用 GraphQL 服務器重新實現我們的示例。

4.1. 創建產品

讓我們使用一個變異(mutation)命名為 saveProduct

curl --request POST 'http://localhost:8081/graphql' \
--header 'Content-Type: application/json' \
--data \
'{
  "query": "mutation {saveProduct (
    product: {
      name: \"Bed-Side Lamp\",
      price: 24.0,
      status: \"Draft\",
      currency: \"USD\"
    }){ id name currency price status}
  }"
}'

saveProduct 函數中,括號內的所有內容都是 輸入 類型 模式。 括號之後的大括號描述了服務器返回的 字段

當運行 mutation 時,我們應該期望收到包含所選字段的響應。

{
  "data": {
    "saveProduct": {
      "id": "12",
      "name": "Bed-Side Lamp",
      "currency": "USD",
      "price": 24.0,
      "status": "Draft"
    }
  }
}

此請求與我們使用 REST 版本時所做的 POST 請求非常相似,但現在我們可以稍微自定義響應。

4.2. 更新產品

同樣,我們還可以使用另一個變異(mutation)updateProduct 來修改產品:

curl --request POST 'http://localhost:8081/graphql' \
--header 'Content-Type: application/json' \
--data \
'{"query": "mutation {updateProduct(
    id: 11
    product: {
      price: 14.0,
      status: \"Publish\"
    }){ id name currency price status }  
  }","variables":{}}'

我們接收到選定的字段在響應中:

{
  "data": {
    "updateProduct": {
      "id": "12",
      "name": "Bed-Side Lamp",
      "currency": "USD",
      "price": 14.0,
      "status": "Published"
    }
  }
}

如我們所見,GraphQL 提供了對響應格式的靈活性

4.3. 獲取產品列表

為了從服務器獲取數據,我們將使用一個查詢:

curl --request POST 'http://localhost:8081/graphql' \
--header 'Content-Type: application/json' \
--data \
'{
    "query": "query {products(size:10,page:0){id name status}}"
}'

在這裏,我們還描述了我們希望看到的搜索結果頁面:

{
  "data": {
    "products": [
      {
        "id": "1",
        "name": "T-Shirt",
        "status": "Published"
      },
      ...
    ]
  }
}

4.4. 通過 GraphQL 獲取單個產品及其訂單

使用 GraphQL,我們可以請求 GraphQL 服務器將產品和訂單合併在一起:

curl --request POST 'http://localhost:8081/graphql' \
--header 'Content-Type: application/json' \
--data \
'{
    "query": "query {product(id:1){ id name orders{customerId address status creationDate}}}"
}'

在本次查詢中,我們檢索具有<em>id</em>值為 1 的產品及其訂單。這使我們能夠在單個操作中發出請求。讓我們查看響應:

{
  "data": {
    "product": {
      "id": "1",
      "name": "T-Shirt",
      "orders": [
        {
          "customerId": "de68a771-2fcc-4e6b-a05d-e30a8dd0d756",
          "status": "Delivered",
          "address": "43-F 12th Street",
          "creationDate": "Mon Jan 17 01:00:18 GST 2022"
        }, 
        ...
      ]
    }
  }
}

如我們所見,響應中包含產品的詳細信息及其對應的訂單。

為了通過 REST 方式實現這一點,我們需要發送多條請求——首先是獲取產品的信息,然後是獲取其對應的訂單。

5. 比較

這些示例展示了使用 GraphQL 如何減少客户端與服務器之間的流量,並允許客户端為響應提供一些格式規則。

需要注意的是,這些 API 的後端數據源仍然可能需要執行相同的操作來修改或檢索數據,但客户端與服務器之間接口的豐富性允許客户端使用 GraphQL 完成更少的工作。

讓我們進一步比較這兩種方法。

5.1. 靈活和動態

GraphQL 允許靈活和動態的查詢:

  • 客户端應用程序可以僅請求所需字段
  • 可以使用 別名 來請求具有自定義鍵的字段
  • 客户端可以使用查詢來管理結果排序
  • 客户端可以更好地與 API 中的任何更改解耦,因為沒有單一響應對象結構的響應對象需要遵循

5.2. 成本較低的操作

每個服務器請求都有往返時間及數據包大小的成本。

在 RESTful 架構中,為了實現所需功能,我們可能需要發送多個請求。這些多個請求會產生較高的成本。 響應數據包也可能包含不必要的數據,這些數據可能並非客户端應用程序所需要。

GraphQL 傾向於避免這些高成本的操作。 我們通常可以使用 GraphQL 在單個請求中獲取所需的所有數據

5.3. 何時使用 REST?

GraphQL 不是 REST 的替代品。兩者甚至可以在同一個應用程序中共存。託管 GraphQL 端點的複雜性可能會根據用例而有所不同,值得考慮。

我們可能更喜歡 REST 的情況是:

  • 我們的應用程序本質上是資源驅動型的,操作與單個資源實體直接且完全相關
  • 需要 Web 緩存,因為 GraphQL 本身不支持它
  • 我們需要文件上傳,因為 GraphQL 本身不支持它

6. 結論

在本文中,我們通過一個實際示例比較了 REST 和 GraphQL。

我們瞭解到如何通常使用每種方法。

然後,我們討論了兩種方法都沒有明顯的優勢。我們的需求將成為選擇它們之間的驅動力。偶爾,兩者也可以共存。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.