【问题标题】:REST API design: different granularity for receiving and updating resourcesREST API 设计:接收和更新资源的不同粒度
【发布时间】:2015-11-18 00:42:22
【问题描述】:

我正在创建一个 REST API。其中,有一个名为company 的资源类型,它有很多属性/字段。

处理company资源时的两个常见用例是:

  • 通过一个请求加载整个公司及其所有属性
  • 更新公司的一组(相对较小的)属性,但不会同时更新所有属性

关于 API 的设计,我提出了两种不同的方法,需要从中选择一种(也许还有更好的方法,请随时发表评论):


1.使用子资源进行细粒度更新

由于可以将公司的属性分组(例如街道、城市和州代表地址...电话、邮件和传真代表联系信息等...),一种方法可以是使用以下路线:

/company/id:可以使用GET获取整个公司

/company/id/address:可用于更新地址信息(街道、城市...),使用PUT

/company/id/contact:可用于更新联系信息(电话、邮件...),使用PUT

等等。

但是:在像/company/id/address 这样的子资源上使用GET 永远不会发生。同样,更新/company/id 本身也永远不会发生(参见上面的用例)。我不确定这种方法是否遵循 REST 的想法,因为我使用不同的 URL 加载和操作相同的数据。

2。使用 HTTP PATCH 进行细粒度更新

在这种方法中,部分更新没有额外的路径。相反,只有一个端点:

/company/id:可用于使用GET 获取整个公司,同时使用PATCH 更新资源子集(地址、联系信息等)。


从技术角度来看,我很确定这两种方法都可以正常工作。但是,我不想以不应该使用的方式使用 REST。您更喜欢哪种方法?

【问题讨论】:

    标签: web-services api rest http web


    【解决方案1】:

    在这种特殊情况下,我会使用PATCH 而不是子资源方法。首先,这不是一个真正的子资源。它只是为了消除更新整个大实体(资源)的问题而引入的虚假抽象。而PATCH 是一种与 REST 兼容、成熟且通用的方法。

    而且(IMO ultima ratio),假设您需要以某种方式扩展公司(通过添加杂志、场地、CTO 等等)。您是否会添加一个新端点以使客户端能够更新资源的这个新添加部分?它是如何完成的?具有无人理解的多个端点。有了PATCH,您的 API 就可以为公司的新元素做好准备了。

    【讨论】:

      【解决方案2】:

      您是否真的一直在处理 GET 响应中包含的每个字段?如果没有,那么为地址和联系人创建自己的资源不仅仅是很好。也许您稍后会发现更多的用例,您可以在其中重用这些资源。

      此外,您还可以在资源中嵌入其他资源。 JSON HAL () f.e.明确地提供了一个 _embedded 属性,您可以在其中嵌入 f.e. 的当前状态。子资源。具有嵌入式资源的虚构公司资源的简化的类似 HAL 的 JSON 表示可能如下所示:

      {
          "name":"Test Company",
          "businessType":"PLC",
          "foundingYear": 2010,
          "founders": [
              {
                  "name": "Tim Test",
                  "_links": {
                      "self": {
                          "href": "http://example.org/persons/1234"
                      }
                  }
              }
          ],
          ...
          "_embedded": {
              "address": {
                  "street": "Main Street 1",
                  "city": "Big Town",
                  "zipCode": "12345",
                  "country": "Neverland"
                  "_links": {
                      "self": {
                          "href": "http://example.org/companies/someCompanyId/address/1"
                      },
                      "googleMaps": {
                          "href": "http://maps.google.com/?ll=39.774769,-74.86084"
                      }
                  }
              },
              "contacts":  {
                  "CEO": {
                      "name": "Maria Sample",
                      ...
                      "_links": {
                          "self": {
                              "href": "http://example.org/persons/1235"
                          }
                      }
                  },
                  ...
              }
          }
      }
      

      因此,通过向特定资源的封闭 URI 发送 PUT 请求来更新嵌入式资源是直接的。由于GET 请求我被缓存,您可能需要提供更细粒度的缓存设置(例如,带有条件 GET 请求,又名If-Modified-Since 或 ETAG 标头字段)以在更新后检索实际状态。这些标头应考虑整个资源(包括嵌入一次)以返回更新后的状态。

      关于 PUTPATCH 的“部分更新”:

      虽然PUT 的语义相当清晰,但PATCH 经常与仅将某些属性的新状态发送给服务的部分更新混淆。 This article 但是描述了 PATCH 真正应该做什么。

      简而言之,对于PATCH 请求,客户端负责比较资源的当前状态并计算将当前资源转换为所需状态的必要步骤。在计算步骤之后,请求将必须包含服务器必须理解的指令才能执行这些指令并因此生成更新版本。此外,PATCH 请求是原子的 - 所有指令都成功或不成功。这为此请求增加了一些事务要求。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-12-09
        • 1970-01-01
        • 2011-09-24
        • 1970-01-01
        • 1970-01-01
        • 2021-09-02
        • 2020-10-19
        • 2014-11-10
        相关资源
        最近更新 更多