【问题标题】:RESTful resource - accepts a list of objectsRESTful 资源 - 接受对象列表
【发布时间】:2010-07-07 21:47:30
【问题描述】:

我正在构建一个 RESTful 资源集合,其工作方式如下:(我将使用“人”作为示例):

获取/人/{key} - 返回一个人对象(JSON) GET /people?first_name=鲍勃 - 返回“first_name”为“Bob”的人员对象列表(JSON) 放/人/{键} - 期望有效负载 (JSON) 中的人员对象,更新人员 具有在 URL 参数中找到的 {key} 的数据存储以匹配有效负载。 如果是新对象,客户端指定新对象的键。

到目前为止,我对设计感到非常满意(尽管欢迎任何意见/批评)。

我还希望能够列出人员列表,但是我对我的设计的 RESTfulness 没有信心。这就是我的想法:

放/人 - 期望 JSON 形式的对象列表,其中包含对象中的键 (“键”:“32948”)。更新数据存储中的所有相应对象。

这个操作是幂等的,所以我想使用“PUT”。但是它违反了规则,因为对同一资源的 GET 请求不会返回与客户端刚刚 PUT 的等效内容,而是会返回所有“人”对象(因为查询中没有过滤器)。我怀疑这里还有一些其他规则可能被打破。

有人在我之前的一个问题中提到了“PATCH”请求的使用:REST resource with a List property

“PATCH”听起来很棒,但我不想使用它,因为它还没有被广泛使用,并且还不能与很多程序和 API 兼容。

我不想使用 POST,因为 POST 意味着请求不是幂等的。

有没有人有任何cmets/建议?

跟进:::

虽然我犹豫是否使用 POST,因为它似乎是 RESTful 操作的最小公分母,并且可以说更多关于此操作(特别是它是幂等的),但不能使用 PUT,因为它的要求太窄了。具体来说:资源没有被完全重写,等效资源没有从 GET 请求发送回相同的资源。当应用程序、api 和/或程序员尝试使用资源并遇到来自资源的意外行为时,使用具有超出其规范的属性的 PUT 可能会导致问题。

除了接受的答案之外,Darrel Miller 有一个很好的建议,如果操作绝对必须是 PUT,那就是将 UUID 附加到资源路径的末尾,这样等效的 GET 请求将返回等效的资源。

【问题讨论】:

    标签: rest


    【解决方案1】:

    POST 表示除GETPUTDELETE(通用哈希表操作)之外的通用操作。由于通用哈希表操作不合适,请使用POSTPOST 的语义由实体所在的资源确定POSTed。这与众所周知的通用哈希表方法的语义不同。

    POST /people/add-many HTTP/1.1
    Host: example.com
    Content-Type: application/json
    
    [
      { "name": "Bob" },
      { "name": "Robert" }
    ]
    

    【讨论】:

    • 感谢您的回复。我理解为什么 PUT 在技术上不正确,但这解释了为什么我不应该违反这个特定规则。
    【解决方案2】:

    在这种情况下,使用 PUT 绝对是错误的动词。 POST 旨在完全按照您的要求进行操作。来自HTTP specification

    POST 和 PUT 请求的根本区别在于 Request-URI 的不同含义。 POST 请求中的 URI 标识将处理封闭实体的资源。该资源可能是一个数据接受进程,一个通往其他协议的网关,或者一个接受注释的单独实体。相反,PUT 请求中的 URI 标识了请求中包含的实体——用户代理知道 URI 的意图,服务器不得尝试将请求应用于其他资源...

    因此,如果您想在一次调用中更新多个资源,您必须使用 POST。

    只是因为 PUT 必须是幂等的,而 POST 不是,并不意味着 POST 不能是幂等的。您对 HTTP 动词的选择不应基于此,而应基于请求的资源和所作用的资源之间的关系。如果您的应用程序直接处理请求的资源,请使用 PUT。如果它作用于其他资源(或资源,如您的情况),请使用 POST。

    【讨论】:

      【解决方案3】:

      我真的没有看到任何简单的方法可以使用 PUT 来创建任意一组人。除非,您准备让客户端生成 GUID 并执行类似的操作,

      PUT /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
      

      在服务器端,您可以从列表中取出人员并将他们添加到 /People 资源中。

      这种方法的一个细微变化是让服务器包含一个链接,例如

      <link rel="AddList" href="/PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}"/>
      

      在人员资源中。客户需要知道它需要将人员列表放入AddList 链接。服务器需要确保每次呈现 /People 资源时都会为 AddList 链接创建一个新的 url。

      【讨论】:

      • 这是一个非常有趣的想法。
      【解决方案4】:

      关于 Darren Miller 关于使用 PUT 到 GUID 的建议(我无法评论...),使用 PUT 的目的是实现操作的幂等性。检验幂等性是否是客户端和服务器之间的对话的试金石:

      1. PUT /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
      2. 204 NO CONTENT(表示一切顺利)
      3. 客户端失去连接并且看不到204
      4. 客户端自动重试
      5. PUT /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}

      服务器如何区分这两者?如果 GUID 可以这么说是“用完”,那么服务器将不得不响应 404410。这会在服务器上引入一点点会话状态,以记住所有已使用的 GUID。

      我猜两个客户端经常会看到相同的结果,因为缓存或只是保留了陈旧的响应。

      我认为一个聪明的解决方案是使用 POST 为您可以 PUT 的资源创建一个(最初是空的、短暂的)保存区域,即客户端需要 POST 来创建 GUID 资源,而不是通过链接发现它:

      1. POST /PeopleList/CreateHoldingArea
      2. 201 CREATEDLocation: /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
      3. PUT /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}

      这意味着失去的幂等性不会导致太多开销;如果客户没有看到最初的 201 CREATED 响应,他们只需创建新的 GUID(通过 POST)。 “微小的对话状态”现在只是已创建但尚未使用的保持区域。

      理想的解决方案当然不需要服务器上的任何会话状态,但它让我望而却步。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-22
        • 2012-07-30
        • 2011-10-14
        • 1970-01-01
        • 2020-03-23
        • 2014-04-06
        相关资源
        最近更新 更多