多资源的RESTful原子更新?

多资源的RESTful原子更新?,rest,transactions,crud,atomic,multipartform-data,Rest,Transactions,Crud,Atomic,Multipartform Data,假设一个web应用程序存储了一些带有id的数据资源,每个数据存储三个附件(例如pdf) URL方案是 data/{id}/attachment1 data/{id}/attachment2 data/{id}/attachment3 对于提供在服务器端实现CRUD操作的GET/PUT/DELETE操作的附件,存在RESTful API 让id为123,我想执行一个操作,其中 attachment1被一个新的附件替换(例如GET 文件/123/attachment1返回新附件) 附件2被删除(

假设一个web应用程序存储了一些带有id的数据资源,每个数据存储三个附件(例如pdf)

URL方案是

data/{id}/attachment1
data/{id}/attachment2
data/{id}/attachment3
对于提供在服务器端实现CRUD操作的GET/PUT/DELETE操作的附件,存在RESTful API

让id为123,我想执行一个操作,其中

  • attachment1被一个新的附件替换(例如
    GET
    文件/123/attachment1
    返回新附件)
  • 附件2被删除(这样
    GET file/123/attachment2
    返回404)
  • 附件3保持不变
更新应该是原子的-完全更新由服务器执行,或者根本不执行

应用简单的
PUT file/123/attachment1
DELETE file/123/attachment2
不是原子的,因为客户端可能在PUT之后崩溃,并且服务器没有提示他在这种情况下应该执行回滚

那么,如何以RESTful方式实现操作呢

我想到了两种解决方案,但它们似乎都不是100%的宁静:

  • 使用PATCH(可以放置,但PATCH更好地反映了 部分更新)使用data/123上的多部分/表单数据: 多部分/表单数据是由一个新的 与字段“attachment1”关联的“application/pdf”,以及 表示一个空值以表示删除的东西 附件2
虽然这确保了原子性,但我怀疑这是RESTful的,因为我使用不同的参数列表重载了PATCH方法,这违反了统一接口约束

  • 使用表示事务的资源。我可以发布数据id 123 指向将创建事务资源的事务URL 表示存储的数据资源当前状态的副本 在服务器上,例如事务/数据/123。现在我可以叫PUT和 删除此临时资源的附件(例如,
    DELETE transaction/data/123/attachment2
    )并进行通信 通过PUT on将此版本的资源提交到服务器 事务/数据/123。这确保了原子性,同时也确保了 实现额外的服务器端逻辑以处理多个客户端 更改同一资源并使从未提交的客户端崩溃
虽然这似乎与REST一致,但似乎违反了无国籍状态的限制。事务性资源的状态不是服务状态,而是应用程序状态,因为每个事务性资源都与单个客户机关联


我有点困在这里了,所以任何想法都会有帮助,谢谢

非常有趣的问题。卢加诺大学(瑞士)的一位教授写了一些关于这种情况的幻灯片:

但是,我不确定他提供的解决方案是否完全是RESTful的,因为它在服务器端看起来并不是真正无状态的


老实说,由于事务本身是由多个状态组成的,因此我认为这个问题不可能有一个完全RESTful的解决方案。

假设您的URI是分层的:

PUT data/{id}
[attachment2,attachment3]

部分问题在于attachment1/2/3是一个糟糕的标识符。索引不应成为URI的一部分。

您希望使用第二个选项,即事务选项

您缺少的是事务的创建:

POST /transaction

HTTP/1.1 301 Moved Permanently
Location: /transaction/1234
现在您有了一个事务资源,它是一等公民。您可以向其添加、删除、查询以查看其当前内容,然后最终提交或删除(即回滚)事务

当事务正在进行时,它只是另一种资源。这里没有客户端状态。任何人都可以添加到此事务

完成所有操作后,服务器会使用一些超出范围的内部事务机制一次性应用所有更改


您可以在事务子操作中捕获诸如ETag和if-modified头之类的内容,这样当它们都被应用时,您就知道背后没有什么变化。

我没有经验,但我有一个解决方案的想法,因为我在开发中正面临着这个问题

首先,我用我(客户机)向家里的Fred1(有资源的服务器)发送消息的类比,我希望他关掉电灯开关(改变一部分资源的状态)并打开水壶(改变另一部分资源的状态)。在关掉电灯开关后,弗雷德不幸心脏病发作

现在我没有从弗雷德那里得到任何消息来说明他是否按照我的要求做了。弗雷德被另一个弗雷德代替了。我发送的消息没有收到答复。我唯一能继续下去的方法就是问弗雷迪,电灯开关是否关着,水壶是否开着(在我请他为我做事后,资源处于我所期望的状态)。这是一个不幸的状况(错误),增加了我的工作量,但我现在可以继续了,因为我知道弗雷迪在心脏病发作前做了什么。我可以回到绘图板(告诉用户出了问题,我们需要重新做),或者进行更改,如果仍然相关,则完成我的请求(打开水壶)

这是我将如何做的开始,显然有关于范围的问题,但是如果我已经定义了我的范围(我只对灯开关和水壶感兴趣),那么我应该有足够的信息(知道灯开关和水壶的状态)向Fred2发出新命令,而不返回给用户进行指示

听起来怎么样?

我浏览了他们的论文(关于RESTful服务上的分布式原子事务)。他们提出了一个带有协调器资源的Try-Cancel/Confirm协议,该协议最终确认所有参与资源上的更改(或启动先前状态的恢复)。这些资源是分布式服务器,