假设我有一个旅行计划应用程序,每次旅行都由“路径”资源(例如,表示要驱动的路线)组成一系列点。我可以使用像这样的请求来CRUD这些资源(只是一个例子):
POST /trips/1234/paths
<Path>
<Point>32,32</Point>
<Point>32,34</Point>
<Point>34,34</Point>
</Path>
DELETE /trips/1234/paths/3
现在考虑我希望能够将Path拆分为两个路径。在aobve示例中,我可能想要选择要分割的点(32,34),这将导致两个路径 - 一个在该点结束,一个从该点开始。这意味着单个操作会创建两个新资源,同时删除另一个(已拆分的路径)。
因此,如果上面示例中的路径是系统中唯一的路径,并且我通过一次调用将其拆分,则系统现在将包含两个新路径,原始路径将消失。例如:
<Path>
<Point>32,32</Point>
<Point>32,34</Point>
</Path>
<Path>
<Point>32,34</Point>
<Point>34,34</Point>
</Path>
我正在努力解决这个问题。如何处理导致创建/修改/删除多个资源并将其传达给调用者的调用?
我绝对可以通过多次调用来解决这个问题(创建新路径的两个POST和删除原始路径的DELETE),但我希望这是一次调用。
答案 0 :(得分:2)
这不是很漂亮,但可以通过“处理资源”解决这个问题
POST /PathSplitter?SplitAt=(32,34)
Content-Type: application/vnd.acme.path+xml
<Path>
<Point>32,32</Point>
<Point>32,34</Point>
<Point>34,34</Point>
</Path>
=>
200 OK
Content-Type: application/vnd.acme.pathlist+xml
<Paths>
<Path href="/trips/1234/paths/4"/>
<Path href="/trips/1234/paths/5"/>
</Path>
答案 1 :(得分:1)
简短的回答是,只需一次通话就不是真的RESTful;除非你重新构建你的表示,我对REST和HATEOAS的理解是这种过程试图将动词注入服务器端表示,这是一个很大的禁忌。这并不是说你想要做的事情不能完成RESTful,但我认为它涉及你的表示树的一些重构。
然后就是“为什么”你想要这个单一电话的问题;从交易的角度来看,我可以理解为什么它是有意义的。这似乎意味着将事务REST表示暴露给客户端,因此客户端可以正确地管理事务。我不是说这很简单,但是......
答案 2 :(得分:1)
我会尝试像@Darrel Miller's回答那样实现它,但要使其少一些RPCish。 我们的想法是创建一个PathSplit资源,引导客户端完成事务的每一步。通过这种方式,客户端可以知道每个步骤的结果,并且知道如果在此过程中出现错误则需要退出。
这样的事情应该可以解决问题。
POST /pathsplit HTTP/1.1
Content-Type: application/vnd.acme.pathsplit+xml
<pathsplit xmlns="http://schema.acme.com">
<path>
<id>123</id>
</path>
<splitpoint>
<point>32,34</point>
</splitpoint>
</pathsplit>
=>
HTTP/1.1 201 Created
Content-Type: application/vnd.acme.pathsplit+xml
Location:
http://acme.com/pathsplit/11
<pathsplit xmlns="http://schema.acme.com">
<path>
<id>123</id>
</path>
<splitpoint>
<point>32,34</point>
</splitpoint>
<newpaths>
<Path>
<Point>32,32</Point>
<Point>32,34</Point>
</Path>
<Path>
<Point>32,34</Point>
<Point>34,34</Point>
</Path>
<createuri>http://acme.org/trips/paths</createuri>
</newpaths>
<oldpath>
<uri>http://acme.org/trips/paths/123</uri>
</oldpath>
<status>in-progress</status>
<pathscreated>0</pathscreated>
</pathsplit>
通过这样的方式,客户端始终可以GET
pathsplit资源来查看要采取的操作。在此示例中,它会在paths
链接后创建新的createuri
,并为POST
中的每个新path
发送newpaths
请求。服务器在创建每个新资源时更新状态。
状态为pathscreated
为2后,客户端可以按照uri并发送path
动词删除旧的DELETE
。最后,它会删除pathsplit资源,从而表明一切都成功了。
在整个过程中的每一步,如果出现错误,或者在网络中断的常见情况下,客户端始终知道服务器处于什么状态以及事务处于什么状态。
只要事务尚未完成,pathsplit资源仍然可用。 客户还可以选择还原尚未完成的事务。同样,由于它知道哪些操作已成功完成,哪些操作没有成功,因此可以随时退出事务。
答案 3 :(得分:0)
对我来说,具有严格CRUD操作的解决方案似乎没什么用处。但是,对资源的操作不一定需要是CRUD操作。许多人甚至认为这是设计REST界面的一种糟糕方式(只需google for rest + crud)。
因此,我认为将拆分操作定义为一个REST调用时完全没问题。当您仅在一个资源(原始路径)上应用此操作时,您可以直接在其上定义此操作。无需在多个资源上定义它。