我想知道如何在REST中实现以下用例.甚至可以不牺牲概念模型吗?
在单个事务的范围内读取或更新多个资源.例如,将Bob的银行帐户中的100美元转入John的帐户.
据我所知,实现这一点的唯一方法是作弊.您可以POST到与John或Bob关联的资源,并使用单个事务执行整个操作.就我而言,这打破了REST体系结构,因为你实际上是通过POST隧道化RPC调用而不是真正操作单个资源.
考虑一个RESTful购物篮场景.购物篮在概念上是您的交易包装.以同样的方式,您可以将多个项目添加到购物篮,然后提交该篮子来处理订单,您可以将Bob的帐户条目添加到事务包装器,然后将Bill的帐户条目添加到包装器.当所有部分都到位后,您可以使用所有组件POST/PUT事务包装器.
有一些重要案例没有通过这个问题得到解答,我认为这个问题太糟糕了,因为它在Google上的搜索条件排名很高:-)
具体来说,一个不错的属性是:如果你POST两次(因为一些缓存打中间),你不应该转移两次.
为此,您将事务创建为对象.这可能包含您已知的所有数据,并将事务置于挂起状态.
POST /transfer/txn {"source":"john's account", "destination":"bob's account", "amount":10} {"id":"/transfer/txn/12345", "state":"pending", "source":...}
完成此事务后,您可以提交它,例如:
PUT /transfer/txn/12345 {"id":"/transfer/txn/12345", "state":"committed", ...} {"id":"/transfer/txn/12345", "state":"committed", ...}
请注意,此时多次放置并不重要; 即使是txn上的GET也会返回当前状态.具体来说,第二个PUT会检测到第一个PUT已经处于适当的状态,并且只是返回它 - 或者,如果你在它已经处于"已提交"状态后尝试将其置于"回滚"状态,你将得到一个错误,以及实际提交的事务.
只要您与单个数据库或具有集成事务监视器的数据库通信,此机制实际上就可以正常工作.您可能还会为交易引入超时,如果您愿意,甚至可以使用Expires标题表达.
在REST术语中,资源是可以使用CRUD(创建/读取/更新/删除)动词执行操作的名词.由于没有"转账"动词,我们需要定义一个可以用CRUD作用的"交易"资源.这是HTTP + POX中的一个示例.第一步是CREATE(HTTP POST方法)一个新的空事务:
POST /transaction
这返回一个交易ID,例如"1234"并根据URL"/ transaction/1234".请注意,多次触发此POST不会创建具有多个ID的相同事务,也不会引入"挂起"状态.此外,POST不能始终是幂等的(REST要求),因此通常最好将POST中的数据最小化.
您可以将事务ID的生成留给客户端.在这种情况下,您将POST/transaction/1234创建事务"1234",如果服务器已存在则服务器将返回错误.在错误响应中,服务器可以返回具有适当URL的当前未使用的ID.使用GET方法向服务器查询新ID并不是一个好主意,因为GET永远不会改变服务器状态,创建/保留新ID会改变服务器状态.
接下来,我们使用所有数据UPDATE(PUT HTTP方法)事务,隐式提交它:
PUT /transaction/1234/account/john /account/bob 100
如果ID为"1234"的事务之前已经是PUT,则服务器会给出错误响应,否则会显示OK响应和URL以查看已完成的事务.
注意:在/ account/john中,"john"应该是John唯一的帐号.
很棒的问题,REST主要通过类似数据库的示例来解释,其中存储,更新,检索和删除了某些内容.很少有像这样的例子,服务器应该以某种方式处理数据.我不认为罗伊菲尔丁在他的论文中包含任何内容,毕竟这是基于http的.
但他确实将"代表性国家转移"称为国家机器,并将链接转移到下一个州.通过这种方式,文档(表示)跟踪客户端状态,而不是服务器必须这样做.通过这种方式,没有客户端状态,只有您所在的链接状态.
我一直在考虑这个,在我看来合理的是让服务器为你处理一些东西,当你上传时,服务器会自动创建相关的资源,并给你链接(事实上,它不会不需要自动创建它们:它只能告诉你链接,它只会在你跟随它们的时候创建它们 - 懒惰创建).并且还为您提供了创建新相关资源的链接- 相关资源具有相同的URI但更长(添加后缀).例如:
您使用所有信息上载(POST)事务概念的表示. 这看起来就像一个RPC调用,但它确实创建了"建议的事务资源".例如:URI:/transaction
毛刺会导致创建多个这样的资源,每个资源都有不同的URI.
服务器的响应表明创建的资源的URI,其表示 - 这包括用于创建新的"已提交事务资源"的相关资源的链接(URI).其他相关资源是删除建议交易的链接.这些是状态机中的状态,客户端可以遵循这些状态.从逻辑上讲,这些是在服务器上创建的资源的一部分,超出了客户端提供的信息.例如URI : /transaction/1234/proposed
, /transaction/1234/committed
您POST到链接以创建"已提交的事务资源",该资源创建该资源,更改服务器的状态(两个帐户的余额)**.就其本质而言,此资源只能创建一次,并且无法更新.因此,不会发生提交许多事务的故障.
您可以获取这两种资源,以查看其状态.假设POST可以更改其他资源,现在该提议将被标记为"已提交"(或者可能根本不可用).
这类似于网页的运作方式,最终的网页上写着"你确定要这么做吗?" 最终的网页本身就是交易状态的表示,其中包括转到下一个状态的链接.不只是金融交易; 也(例如)预览然后在维基百科上提交.我想REST中的区别在于状态序列中的每个阶段都有一个显式名称(它的URI).
在现实交易/销售中,交易的不同阶段(提案,采购订单,收据等)通常有不同的物理凭证.甚至更多的购房,结算等.
OTOH这对我来说就像玩语义一样; 将动词转换为名词使其成为RESTful的名词化让我感到不舒服,"因为它使用名词(URI)而不是动词(RPC调用)".即名词"已提交的交易资源"而不是动词"提交此交易".我想名义化的一个优点是你可以按名称引用资源,而不需要以其他方式指定它(例如维护会话状态,所以你知道"这个"事务是什么......)
但重要的问题是:这种方法有哪些好处?即这种REST风格以什么方式比RPC风格更好?对于网页而言,这项技术是否也有助于处理信息,而不是存储/检索/更新/删除?我认为REST的主要优点是可扩展性; 其中一个方面是不需要显式维护客户端状态(但是将其隐含在资源的URI中,并将下一个状态作为其表示中的链接).从这个意义上说它有所帮助 也许这有助于分层/流水线?OTOH只有一个用户会查看他们的特定交易,因此缓存它没有任何优势,所以其他人可以阅读它,http的大赢.
如果你回过头来总结一下这里的讨论,很明显REST不适用于许多API,特别是当客户端 - 服务器交互本质上是有状态的时,就像非平凡事务一样.为什么要跳过建议的所有箍,对于客户端和服务器,为了迂腐地遵循一些不适合问题的原则?更好的原则是为客户提供最简单,最自然,最有效的方式来组合应用程序.
总之,如果您真的在应用程序中执行了大量事务(类型,而不是实例),那么您实际上不应该创建RESTful API.
我离这个话题已经十年了.回来后,我无法相信当你谷歌休息+可靠时,你所涉及的宗教伪装成科学.混乱是神话.
我将这个广泛的问题分成三个:
下游服务.您开发的任何Web服务都将具有您使用的下游服务,其交易语法您别无选择,只能遵循.您应该尝试从服务的用户隐藏所有这些,并确保操作的所有部分作为一个组成功或失败,然后将此结果返回给您的用户.
您的服务.客户希望对Web服务调用有明确的结果,而直接在实质性资源上发出POST,PUT或DELETE请求的常见REST模式对我来说是一种糟糕且易于改进的提供这种确定性的方式.如果您关心可靠性,则需要确定操作请求.此id可以是在客户端上创建的guid,也可以是服务器上关系数据库的种子值,这无关紧要.对于服务器生成的ID,请求响应专用于交换id.如果此请求失败或一半成功,没问题,客户端只是重复请求.未使用的ID不会造成伤害.
这很重要,因为它允许所有后续请求完全是幂等的,因为如果它们重复n次,它们将返回相同的结果,并且不会再发生任何事情.服务器根据操作ID存储所有响应,如果它看到相同的请求,则重放相同的响应.这个模式的更全面的处理是在谷歌文档.该文档建议实现,我相信(!),广泛遵循REST原则.专家肯定会告诉我它是如何侵犯他人的.无论是否涉及下游交易,此模式都可用于对您的Web服务进行任何不安全的调用.
将您的服务集成到由上游服务控制的"事务"中.在网络服务的背景下,完整的ACID交易通常被认为是不值得的,但您可以通过在确认响应中提供取消和/或确认链接来极大地帮助您的服务的消费者,从而通过补偿实现交易.
您的要求是基本要求.不要让别人告诉你你的解决方案不是犹太人.根据他们解决问题的能力和简单程度来判断他们的架构.
您必须推出自己的"事务ID"类型的tx管理.所以这将是4个电话:
http://service/transaction (some sort of tx request) http://service/bankaccount/bob (give tx id) http://service/bankaccount/john (give tx id) http://service/transaction (request to commit)
您必须处理在DB中(如果负载平衡)或在内存等中存储操作,然后处理提交,回滚,超时.
在公园里真的不是一个美好的一天.