具有不完整资源表示的 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 请求来更改 username
和 email
,其中表示缺少其他属性:
PUT /api/users/1
{'username': 'joeydoey',
'email': 'joey@doey.com'}
到目前为止,我一直认为这应该被视为错误,因为它意味着部分更新,但是 this answer让我开始思考它,说不完整的表示仍然是一个完整的替代是有道理的,它让服务器可以自由地用默认值填充空白。
我在 HTTP 标准上找不到任何与此相关的内容,所以我不得不问,在这种情况下预期的标准化行为是什么?
它应该会导致错误,因为它意味着部分更新。 PUT 有效负载的架构应与使用 GET 检索到相同资源和媒体类型的架构相同。
它应该会成功,因为服务器可以自由地使用该媒体类型的默认值填充空白。在这种情况下,它将密码重置为空白或默认密码并相应地刷新哈希,并将 last_visit 和 public 值设置为默认值。当您考虑 HATEOAS 时,此选项更有意义,如果客户端正在提交服务器返回的相同媒体类型,因为它无法预测超媒体控件将如何更改,每次客户端时表示都必然不完整' 发送所有超链接,服务器必须相应地重置它们。
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/