GraphQL vs REST

REST,Web Services
Remote
1
06:10 AM · Dec 01 ,2025

1. 概述

在為我們的應用程序創建 Web 服務時,我們可能會選擇使用 REST 或 GraphQL 作為通信模式。雖然兩者都可能使用 JSON 配合 HTTP,但它們在優勢和劣勢上存在差異。

在本教程中,我們將比較 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. 更新產品

在 REST 中,我們通常使用 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
}'

作為結果,對象 {product-id} 將會更新。

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. 獲取單個產品與訂單

要獲取產品及其訂單,我們可能需要獲取所有產品列表,然後調用 order 資源來查找相關訂單:

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"
}

由於我們正在查詢按 product-id 進行的訂單,因此為 GET 操作提供 id 作為查詢參數是很合理的。然而,我們需要注意,對於每個我們感興趣的產品,我們都需要執行此操作一次,再加上獲取所有產品的原始操作。這與 N + 1 Select Problem 相關。

4. GraphQL

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

GraphQL 的構建塊是 查詢和修改。查詢負責獲取數據,而修改用於創建和更新。

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

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

4.1. 創建產品

讓我們使用名為 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 函數中,括號內的所有內容都是 輸入 類型 模式。花括號內的內容描述了服務器返回的 字段

當我們運行修改時,我們應該期望收到選擇的字段響應:

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

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

4.2. 更新產品

同樣,我們可以使用另一個名為 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 服務器將產品和訂單合併:

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}}}"
}'

在該查詢中,我們檢索具有 ID 為 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"
        }, 
        ...
      ]
    }
  }
}

正如我們所看到的,響應包含產品的詳細信息及其各自的訂單。

要實現這一點,我們必須發送兩個請求 - 第一個獲取產品,第二個獲取相應的訂單。

5. 比較

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

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

讓我們更詳細地比較這兩種方法。

5.1. 靈活且動態

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

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

5.2. 成本更低的運算

每個服務器請求都有往返時間、payload 大小的代價。

在 REST 中,我們可能會發送多個請求才能實現所需的功能。 這些多個請求將是一個昂貴的運算。 響應 payload 可能會包含客户端應用程序不需要的數據。

GraphQL 傾向於避免昂貴的運算。 我們通常可以使用單個請求從 GraphQL 中獲取我們所需的所有數據。

5.3. 何時使用 REST?

GraphQL 不是 REST 的替代品。 兩個甚至可以在同一個應用程序中共存。 託管 GraphQL 端點的增加複雜性可能取決於用例而值得,取決於用例。

我們可能更喜歡 REST 時:

  • 我們的應用程序是自然資源驅動的,其中操作與單個資源實體密切相關
  • 需要 web 緩存,因為 GraphQL 沒有原生支持它
  • 我們需要文件上傳,因為 GraphQL 沒有原生支持它

6. 結論

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

我們看到了如何可能採用所學到的每種方法。

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

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

發佈 評論

Some HTML is okay.