问题描述
我只想喜欢一个引文,或者不喜欢我已经喜欢的引文。所以首先我找到报价,然后我检查我是否已经喜欢这个报价,如果不是那么我喜欢,否则我不喜欢。
router.put('/:quoteId',isAuth,quotesController.likeQuote);
likeQuote 方法如下
module.exports.likeQuote = (req,res,next) => {
const quoteId = req.params.quoteId;
const userId = req.userId;
Quote.findById(quoteId)
.then((quote) => {
if (quote.likes.indexOf(userId) == -1) {
quote.likes.push(userId);
} else {
quote.likes.pull(userId);
}
return quote.save();
})
.then((updatedQuote) => {
res.status(201).json({ message: 'You liked the post!' });
})
.catch((err) => {
err.statusCode = 500;
next(err);
});
但我的问题是,我只想知道 PUT 和 PATCH 是如何工作的?我认为我们应该发送 PUT 中的所有字段,而不是 PATCH 方法中的所有字段,但在我的情况下,我什至不发送任何字段,并且两者都可以正常工作。这是怎么发生的?
解决方法
实际的 REST API 方法(PUT
、PATCH
、...)没有任何限制。您选择编写的逻辑定义了这一点。现在您正在询问“最佳实践”,每当您询问时,您都会得到许多不同的答案。我会解释我的观点。
PUT
,所以 PUT
的本质是完全替换现有对象,这就是为什么人们告诉你发送整个对象,因为当你使用 PUT
时,预期的是完全交换。
PATCH
,PATCH
的本质是更新现有资源。这就是您要查找的内容,在这种情况下,您只需发送更新所需的必填字段。
现在,如果您将 PUT
写为更新而不是完整的交换是错误的吗?我认为它不是。只要您在整个应用中保持一致的逻辑,您就可以构建适合您需求的“最佳实践”。
现在您确实将此问题标记为与 Mongo
相关,因此我想向您介绍 piplined updates(适用于 Mongo v4.2+)的概念,您可以在其中一次更新执行您的逻辑.
我只想知道 PUT 和 PATCH 是如何工作的?
要理解的一个重要区别是,我们没有关于 PUT 和 PATCH 工作方式的标准;这是一个实现细节,故意隐藏在“统一接口”后面。
我们所拥有的是标准化的语义,即关于 PUT 和 PATCH 含义的协议。
(由于人们不熟悉该标准,这进一步复杂化,因此对含义的误解很常见。)
如果请求处理程序的实现与请求的语义不匹配,那没关系……但如果结果出现代价高昂的错误,那就是实现的错。
PUT 和 PATCH 都是方法令牌,表明我们正在尝试修改由 target-uri 标识的资源。特别是,当我们试图使服务器对资源的表示与客户端上的表示相匹配时,我们会使用这些方法标记。
例如,想象一下编辑网页。我们GET /home.html
,更改副本中的 TITLE 元素,并且我们希望将更改保存到服务器。我们如何在 HTTP 中做到这一点?
一个答案是我们将 home.html 的副本(带有我们的更改)发送回服务器,以便服务器可以保存它。就是这样。
另一个答案是我们比较我们的副本和服务器的副本,然后向服务器发送一个补丁文档,描述服务器应该对其副本进行的更改。那是补丁。
router.put('/:quoteId',isAuth,quotesController.likeQuote);
此调用正在配置框架,以便将具有 PUT 方法令牌和与“/:quoteId”匹配的目标 uri 的请求委托给 likeQuote 方法。
在这个级别,框架假设您知道自己在做什么 - 没有尝试验证“likeQuote”是否实现了 PUT 语义。为了确保实现和请求语义匹配,您需要做一些工作(检查代码、测试等)。
在我的情况下,我什至不发送任何字段,两者都可以正常工作。
正确 - 因为框架假设您知道自己在做什么,并且您当前的实现不会尝试访问或解释 HTTP 请求的正文。
注意:这是一个很大的暗示,请求处理程序实际上没有实现 PUT/PATCH 语义(如果服务器不查看客户端提供的信息,它怎么可能使它的引用副本看起来像客户端的)?
It is okay to use POST;假设您的实现是正确的,您不应该使用具有远程创作语义的方法,因为这不是您正在做的。附加到 POST 路由的相同实现将很好。
事实上,事情已经坏了 - 请求语义和处理程序实现之间存在不匹配。在受控条件下,您可能会侥幸逃脱。您完全有可能只在受控条件下调用此代码。