想象一个网络应用程序存储一些数据资源,其中一些id存储每个数据的三个附件(例如pdf)。
网址方案是
data/{id}/attachment1
data/{id}/attachment2
data/{id}/attachment3
存在用于在服务器端实现CRUD操作的GET / PUT / DELETE操作的附件的RESTful API。
让id为123,我想执行
操作GET
file/123/attachment1
返回新附件)GET file/123/attachment2
返回404)更新应该是原子的 - 完整更新由服务器执行或根本不执行。
应用简单的PUT file/123/attachment1
和DELETE file/123/attachment2
不是原子的,因为客户端可能在PUT之后崩溃,并且服务器没有提示他应该在这种情况下进行回滚。
那么如何以RESTful方式实现操作呢?
我想过两个解决方案,但它们似乎都不是100%RESTful:
虽然这确保了原子性,但我怀疑这是RESTful,因为我使用不同的参数列表重载PATCH方法,这违反了统一接口约束。
DELETE transaction/data/123/attachment2
)并进行通信
通过PUT将此版本的资源提交给服务器
交易/数据/ 123。这确保了必要时的原子性
实现额外的服务器端逻辑来处理多个客户端
更改相同的资源并崩溃从未提交的客户端。虽然这似乎与REST一致但似乎违反了无国籍的约束。事务资源的状态不是服务状态而是应用程序状态,因为每个事务资源都与单个客户端相关联。
我有点被困在这里,所以任何想法都会有所帮助,谢谢!
答案 0 :(得分:16)
您想使用第二个选项,即交易选项。
您缺少的是创建交易:
POST /transaction
HTTP/1.1 301 Moved Permanently
Location: /transaction/1234
现在您拥有一个一等公民的交易资源。您可以添加它,从中删除,查询以查看其当前内容,然后最终提交或删除(即回滚)事务。
当交易正在进行时,它只是另一种资源。这里没有客户状态。任何人都可以添加到此交易中。
完成所有操作后,服务器会使用一些超出范围的内部事务机制一次性应用所有更改。
您可以在事务子操作中捕获Etags和if-modified标头之类的内容,这样当它们全部应用时,您就会知道背后的某些内容没有发生变化。
答案 1 :(得分:5)
非常有趣的问题。卢加诺大学(瑞士)的C.S.教授写了一些关于这种情况的幻灯片:
http://www.slideshare.net/cesare.pautasso/atomic-transactions-for-the-rest-of-us
但是我不确定他提供的解决方案是完全REST的,因为它在服务器端似乎没有真正的无状态。
老实说,由于交易本身是由多个州组成的,我不认为这个问题可以有一个完全RESTful的解决方案。
答案 2 :(得分:0)
假设您的URI是分层的:
PUT data/{id}
[attachment2,attachment3]
你的部分问题是attachment1 / 2/3是一个糟糕的标识符。索引永远不应该是您的URI的一部分。
答案 3 :(得分:0)
我没有经验,但我有一个解决方案的想法,因为我在开发过程中遇到了这个问题。
首先,我使用我(客户端)的类比向房子(带资源的服务器)中的Fred1发送消息,我希望他关闭电灯开关(更改部分资源的状态)并打开水壶(改变资源另一部分的状态)。不幸的是,在关掉电灯开关后弗雷德心脏病发作了。
现在我从弗雷德那里得到的一切都没有说他是否做了我的要求。 Fred被另一个Fred取代。我发来的消息没有得到答复。我唯一能做的就是问Fred2,如果电灯开关关闭,水壶开启(资源处于我要求他为我做的事情之后的状态)。这是一个不幸的事态(错误),并增加了我的工作量,但我现在可以继续我知道Fred1在心脏病发作前做了什么。我可以回到绘图板(告知用户出现了问题,我们需要重新进行操作)或者进行更改以完成我的请求(如果仍然相关)(打开水壶)。
这是我如何做的开始,显然有关于重新范围,但如果我已经定义了我的范围(我只对灯开关和水壶感兴趣)那么我应该有足够的信息(知道灯开关和水壶的状态)给Fred2一个新的命令而不返回给用户进行指令。
听起来怎么样?