【发布时间】:2012-02-21 18:47:34
【问题描述】:
想象一个 Web 应用程序存储一些数据资源,该数据资源具有一些 id,每个数据存储三个附件(例如 pdf)。
网址方案是
data/{id}/attachment1
data/{id}/attachment2
data/{id}/attachment3
附件存在一个 RESTful API,提供 GET/PUT/DELETE 操作,在服务器端实现 CRUD 操作。
设 id 为 123,我想在哪里执行一个操作
- attachment1 被新附件替换(这样
GET file/123/attachment1返回新附件) - attachment2 被删除(这样
GET file/123/attachment2返回 404) - attachment3 保持不变。
更新应该是原子的 - 完整的更新由服务器执行或根本不执行。
应用简单的PUT file/123/attachment1 和DELETE file/123/attachment2 不是原子的,因为客户端可能在 PUT 之后崩溃,而服务器没有提示他应该在这种情况下进行回滚。
那么如何以 RESTful 方式实现操作呢?
我想到了两种解决方案,但它们似乎都不是 100% RESTful:
- 使用 PATCH(可以是 PUT,但 PATCH 更好地反映了 部分更新)在 data/123 上使用 multipart/form-data: multipart/form-data 是由一个新的实体组成的序列 与字段“附件 1”关联的“应用程序/pdf”和 代表空值的东西,表示删除 附件2。
虽然这确保了原子性,但我怀疑这是 RESTful,因为我使用不同的参数列表重载 PATCH 方法,这违反了统一接口约束。
- 使用代表事务的资源。我可以发布数据 id 123
到将创建事务资源的事务 URL
表示存储的数据资源当前状态的副本
在服务器上,例如交易/数据/123。现在我可以调用 PUT 和
删除这个临时资源的附件(例如
DELETE transaction/data/123/attachment2)并沟通 通过 PUT on 将此版本的资源提交到服务器 交易/数据/123。这确保了原子性,而必须 实现额外的服务器端逻辑来处理多个客户端 更改从未提交的相同资源和崩溃的客户端。
虽然这似乎与 REST 一致,但它似乎违反了无状态的约束。事务资源的状态不是服务状态而是应用程序状态,因为每个事务资源都与单个客户端相关联。
我有点卡在这里,所以任何想法都会有所帮助,谢谢!
【问题讨论】:
-
第二种方法的好处是可以提供良好的数据更改历史记录,并且可以让您跳过一些日志记录。
-
@mtsz 我现在正在努力解决这个问题。我喜欢您在下面选择的答案,但是创建一个具有短暂、临时生命周期的事务资源似乎需要做很多工作。您认为将要执行的原子事务命名为“switcheroo”之类的名称并创建一个执行该事务的特定 Web 服务会很糟糕吗?例如,POST /doSwitcheroo 的主体为 {fileId: 123} ...。此服务将具有对 id 为 123 的文件自动执行上述操作的逻辑
标签: rest transactions crud atomic multipartform-data