api - 使用具有不完整表示的 PUT 方法

标签 api http rest

具有不完整资源表示的 PUT 的标准行为是什么?

例如,我在 /api/users/1 有一个 User,它由下面的 HAL json 表示:

{'id': 1,
 'username': 'joedoe',
 'email': 'joe@doe.com',
 'password_hash': '9039dmk38f84uf4029i339kf32f0932i',
 'last_visit': '2013-11-04 21:09:01',
 'public': true,
 '_links': {'self': {'href': 'http://foo.bar.com/api/users/1'}}

}

然后,我发出一个 PUT 请求来更改 usernameemail,其中表示缺少其他属性:

PUT /api/users/1

{'username': 'joeydoey',
 'email': 'joey@doey.com'}

到目前为止,我一直认为这应该被视为错误,因为它意味着部分更新,但是 this answer让我开始思考它,说不完整的表示仍然是一个完整的替代是有道理的,它让服务器可以自由地用默认值填充空白。

我在 HTTP 标准上找不到任何与此相关的内容,所以我不得不问,在这种情况下预期的标准化行为是什么?

  1. 它应该会导致错误,因为它意味着部分更新。 PUT 有效负载的架构应与使用 GET 检索到相同资源和媒体类型的架构相同。

  2. 它应该会成功,因为服务器可以自由地使用该媒体类型的默认值填充空白。在这种情况下,它将密码重置为空白或默认密码并相应地刷新哈希,并将 last_visit 和 public 值设置为默认值。当您考虑 HATEOAS 时,此选项更有意义,如果客户端正在提交服务器返回的相同媒体类型,因为它无法预测超媒体控件将如何更改,每次客户端时表示都必然不完整' 发送所有超链接,服务器必须相应地重置它们。

  3. 1 和 2 都是有效的,因为没有标准化的行为,媒体类型决定如何处理它。这感觉不对,因为 PUT 不从属于资源本身,而是取代它。

请记住,我不是在问什么感觉对或什么有意义。我想问的是哪一个有标准支持。

最佳答案

只要 PUT 的结果完全替换了客户端对资源的理解(即,那些未传递的属性的先前值不会影响它们在 PUT 之后的值),它应该会成功。但是,它看起来确实有点令人困惑,因为很多人倾向于将 PUT 的这种使用与字段级更新语义(而不是完全替换)模棱两可。

虽然从技术上讲这里没有违反 REST 约束,但传递所有值而不诉诸服务器默认值可能是更好的主意,因为这将有助于保持向前兼容性。默认值会随着时间而改变,因此通常应避免使用它们。

但是,您的链接示例并不是指不传递默认值,因此它不是“不完整表示”的好示例。相反,链接不是客户端向服务器表示的资源的一部分。我认为您在这里混合了另一个概念:从服务器返回到客户端的属性。这就是我在引发这篇文章的另一个话题上所说的内容。

我所说的并不是不完整的表示;这是一种不同的表现形式。您实际上是在处理描述同一资源的两种不同媒体类型(即表示形式)。一个来自客户端(我们称之为 application/vnd.example.api.client),另一个来自服务器(application/vnd.example.api.server)。它们可能没有明确地被标记为这样,但至少隐含地是正在发生的事情。因此,由于它们是两种不同的媒体类型,它们表达了关于相同资源的不同内容。

既然您提到了 HAL,请考虑客户端通常不会向服务器发送媒体类型 application/hal+json 的消息。看看the signup rel from HALTalk举个例子。预期的内容类型是 application/json,而不是 application/hal+json。而且,如果您查看示例帖子,就会发现它没有任何 HAL 风格。没有链接,没有嵌入式对象等。但是...如果您随后获取从此 POST 返回的 Location header 返回的 URL,假设您的客户端通过 JSON 接受 HAL,它将返回 application/hal+json 类型的响应(即,具有链接的用户)。两种不同的媒体类型,同一资源的两种不同表示。

所以让我用 Accept 和 Content-Type header 修饰您的示例来说明我的观点。

请求

PUT /api/users/1 HTTP/1.1
Content-Type: application/vnd.example.api.client+json

{'username': 'joeydoey',
 'email': 'joey@doey.com'}

响应

200 OK
Content-Type: application/hal+json;profile=application/vnd.example.api.server

{'id': 1,
 'username': 'joeydoey',
 'email': 'joey@doey.com',
 'password_hash': '9039dmk38f84uf4029i339kf32f0932i',
 '_links': {'self': {'href': 'http://foo.bar.com/api/users/1'}}
}

大多数系统不会如此详细地描述它们的媒体类型。通常它只是以更通用的类型构建(例如 application/json 或只有一种自定义媒体类型)。然而,这并没有改变一个事实,即虽然它是相同的底层资源,但它们是两种不同的表示形式。有道理吗?

关于api - 使用具有不完整表示的 PUT 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19825870/

相关文章:

json - 为多对多关系构建 RESTful API

python - Tweepy:AttributeError: 'tuple'对象没有属性 'followed_by'

java - 针对 Java 兼容性的 Scala API 设计

python - 如何处理原始 Python 套接字中的 ssl 连接?

ruby-on-rails - Ruby 文件复制生成不同的文件

Java Spring Rest API。返回引用的对象或对象的 id?

php - 构建 REST api 时如何处理查询字符串中参数的动态数量?

python - 如何在 Python 中使用 Win32 API?

c - 从套接字 C HTTP 读取

android - 如何修改来自 Android 应用程序的 HTTP 请求 header ?