【问题标题】:'Best' practice for restful POST response安静的 POST 响应的“最佳”实践
【发布时间】:2013-10-12 13:15:55
【问题描述】:

所以这里没有什么新内容,我只是想澄清一下,似乎在其他帖子中找不到任何内容。

我正在轻松地创建一个新资源,比如说:

/books (POST)

有身体:

{
  title: 'The Lion, the Witch and the Wardrobe',
  author: 'C. S. Lewis'
}

我知道我应该返回一个 201(已创建),并带有新资源的 Location 标头:

Location: /books/12345

我自己似乎无法回答的问题是服务器应该在正文中返回什么。

我经常做这种回应:

{
  id: 12345,
  title: 'The Lion, the Witch and the Wardrobe',
  author: 'C. S. Lewis'
}

我这样做有几个原因:

  1. 我已经为 angularjs 等前端框架编写了 api。在我的 特殊情况我正在使用角度资源,我经常只需要 用于定位它的资源的 ID。如果我没有返回 id 我需要将其从位置解析出来的响应正文 标题。
  2. 在所有书籍的 GET 中,我通常会返回整个对象,而不仅仅是 身份证。从这个意义上说,我的客户端代码不必区分 从哪里获取 id(位置标头或正文)。

现在我知道我真的处于灰色地带,但大多数人都说归还整个资源是“不好的”做法。但是,如果服务器更改/向资源添加信息怎么办。它肯定会添加 id,但也可能会添加其他内容,例如时间戳。在我不返回整个资源的情况下,做一个POST,返回id,然后让客户端执行GET来获取新资源真的更好吗?

【问题讨论】:

  • 我个人更喜欢 POST 响应的空正文。 RESTful Location 标头值不应该是 URI(唯一资源标识符)吗?因此,也许您应该将其用作 ID 而不是解析它以找出服务器内部 ID。 IMO,RESTful API 消费者应该使用提供的超链接而不是构建路径进行导航,猜测特定服务器定位资源的位置......毕竟,客户端不知道它刚刚创建的资源的状态吗?重复它会浪费网络资源。
  • 对于创建/插入,状态 201 - 已创建,标题位置 →localhost:8080/employees/1(参见:here

标签: rest angularjs angularjs-resource


【解决方案1】:

返回新对象符合“统一接口 - 通过表示操作资源”的 REST 原则。完整的对象是所创建对象的新状态的表示。

API 设计有一个非常好的参考,这里:Best Practices for Designing a Pragmatic RESTful API

这里包含对您问题的答案:Updates & creation should return a resource representation

上面写着:

为了防止 API 使用者不得不再次访问 API 更新的表示,让 API 返回更新的(或创建的) 表示作为响应的一部分。

对我来说似乎非常实用,并且符合我上面提到的 REST 原则。

【讨论】:

  • 返回整组相关对象怎么样?这样,可能的排序可以在服务器端完成,并且简化了前端实现
  • 但是这些最佳实践并不是最好的。作者指出,与其他原则一样重要的 HATEOAS 一定不能使用,因为“它还没有准备好”。 HATEOAS 永远不会“准备好”,因为所有 RESTful 原则都只是架构设计原则,而不是具体实现。引用的参考资料是关于作者对 RESTful API 的看法,由于放弃了 HATEOAS,它根本不是 RESTful。这就是为什么这不是最好的参考:)
  • @marcinn - 你会注意到最初的问题在“最佳”周围有引号,我猜是因为在这个领域有很多意见。我指出的参考资料是我发现实用的。如果您有更好的参考,请分享。我总是乐于学习更多。
  • @grahamesd 实现与架构设计原则/模式不同。没有人可以期望 HATEOAS 有一天会准备好,但是有可能有人会创建一个被许多人接受的实现。 Vinay 还写了有关将 http 方法映射到 URL 和特定操作 (CRUD) 的文章,指出通过为 url 添加前缀的版本控制更加实用,并写道通过查询参数进行过滤是一种可行的方法……很好,但这一切都没有什么可做的使用 RESTful 架构。他写了一些合同。这对 HTTP API 来说很好,但不要称之为 RESTful。
  • @grahamesd 以下是一些解释这一点的帖子:-medium.com/@andrea.chiarelli/…-restfulapi.net
【解决方案2】:

在更新时返回整个对象似乎不是很相关,但我很难理解为什么在创建时返回整个对象在正常用例中是一种不好的做法。这至少对于轻松获取 ID 并在相关时获取时间戳很有用。 这实际上是使用 Rails 搭建脚手架时的默认行为。

我真的看不出只返回 ID 并在之后执行 GET 请求以获取您可以通过初始 POST 获得的数据的任何优势。

无论如何,只要您的 API 是一致的,我认为您应该选择最适合您需求的模式。没有任何正确的方法来构建 REST API,imo。

【讨论】:

  • 我知道这已经过时了,但我可以给出一个令人信服的论据,说明在您的 POST 之后使用 GET。在 http/1.1 规范中,任何历史工具都可以忽略从您的 GET 响应传回的缓存设置...因此,如果您的用户在使用 POST 更新后使用浏览器中的后退按钮返回此页面,则它可以使用陈旧的来自原始 GET 的缓存数据。因此,如果您重用 GET,那么您可以更新缓存并更好地了解页面离开时的外观......
  • @Shaded 如果 API 也被设计为应用程序使用,那么您提出两个请求的论点不成立。在那里,您通常通过将模型类型的对象保存在内存中来缓存数据——这通常是通过 POST 请求的响应来完成的。对于浏览器,只要还有一个 GET api 端点,对 POST 请求的响应就不会真正受到伤害。
  • 我订阅了丹尼尔在这里所说的内容。即使你检查像 Spring Data 这样的成熟框架,它们总是在持久化后返回整个对象。我认为这是一个很好的做法,因为在您的客户端中,您将节省服务器往返以获取相同的信息
【解决方案3】:

发完帖子后,我喜欢这样回复:

Response
   .created(URI("/obj/$id"))
   .entity(TheNewObj())
   .build()

状态 201 - 已创建

Header Location - 新对象的位置

实体 - 新对象

【讨论】:

    猜你喜欢
    • 2020-09-30
    • 1970-01-01
    • 2021-05-07
    • 2015-02-07
    • 1970-01-01
    • 1970-01-01
    • 2011-09-16
    • 2012-04-05
    • 2019-04-10
    相关资源
    最近更新 更多