弗朗西斯的答案是一个很好的答案,可能是您正在寻找的。话虽如此,它在技术上并不是 RESTful,因为(正如他在评论中所说)它确实依赖于客户端提供带外信息。由于问题是“什么是宁静的方式”而不是“什么是好方式/最好的方式”,这让我开始思考是否有RESTful解决方案。而且我认为接下来是一个 RESTful 解决方案,尽管我不确定它在实践中是否一定会更好。
首先,正如您已经确定的那样,GET 后跟 POST 是简单而明显的 RESTful 方式,但效率不高。所以我们正在寻找一种优化,如果它感觉比那个解决方案不那么自然,我们不应该太惊讶!
POST + sourceId 解决方案创建了一个特殊的 URL——它不指向资源,而是指向做某事的指令。每当您发现自己创建了类似的特殊 URL 时,都值得考虑是否可以通过简单地定义更多资源来解决这样做的需要。
我们想要复制的能力
resources/10
如果我们想出另一个资源怎么办:
resources/10/copies
...并且此资源的定义只是“作为资源/10 副本的资源的集合”。
定义了这个资源后,我们现在可以用不同的术语重新声明我们的复制操作——而不是说“我希望服务器复制资源/10”,我们可以说“我想向集合中添加一个新事物是资源/10" 的副本。
这听起来很奇怪,但它很自然地适合 REST 语义。例如,假设这个资源当前看起来像这样(我将在这里使用 JSON 表示):
[]
我们可以使用 POST 或 PATCH [1] 来更新它:
POST resources/copies/10
["resources/11"]
请注意,我们发送到服务器的只是关于集合的元数据,因此它非常有效。我们可以假设服务器现在知道从哪里获取要复制的数据,因为这是该资源定义的一部分。我们还可以假设客户端知道这会导致在“resources/11”处创建一个新资源,原因相同。
使用此解决方案,所有内容都被明确定义为资源,并且所有内容都有一个规范的 URL,并且客户端不需要任何带外信息。
归根结底,为了更加 RESTful 而采用这种奇怪的解决方案值得吗?这可能取决于您的个人项目。但是通过创建不同的资源来尝试以不同的方式解决问题总是很有趣的!
[1] 我不知道在“resources/10/copies”上允许 GET 是否有意义。显然,只要原始资源或其副本发生更改,该副本就不再是真正的副本,也不应该出现在此集合中。在实现方面,我不认为让服务器负担跟踪它的意义,所以我认为这应该被视为仅更新资源。