如何在同一时间RESTful创建和删除?

时间:2011-06-30 16:17:22

标签: rest

假设我有一个旅行计划应用程序,每次旅行都由“路径”资源(例如,表示要驱动的路线)组成一系列点。我可以使用像这样的请求来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),但我希望这是一次调用。

4 个答案:

答案 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调用时完全没问题。当您仅在一个资源(原始路径)上应用此操作时,您可以直接在其上定义此操作。无需在多个资源上定义它。