BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

在RESTful服务中实现部分更新

| 作者 Dilip Krishnan 关注 0 他的粉丝 ,译者 池建强 关注 4 他的粉丝 发布于 2010年12月7日. 估计阅读时间: 6 分钟 | QCon上海2018 关注大数据平台技术选型、搭建、系统迁移和优化的经验。

近期Alex Scordellis 发表了一篇文章,文章主题是如何针对客户端与RESTFul服务的交互进行建模和设计,实现部分资源的更新。 

[在 REST In Practice(由 Ian RobinsonJim WebberSavas Parastatidis合著)这本书中]有个问题很让我困扰,作者们推荐使用POST方式更新资源的状态。这是根据对PUT语义的解释做出的选择。根据HTTP规范的描述:

如果请求的URI指向已经存在的资源,那么封装的实体应该被视为驻留在原始服务器上实体的修改后的版本。

在这本书里,作者们对此的解释是,在同一个URI里,PUT请求封装的正文(body)中应该包含与GET请求的表现形式相同的元素。由于我们正在使用 HATEOAS风格,表现形式包括链接和其他超媒体表现形式。其含义就是客户端PUT的内容应该同时包含业务数据(例如咖啡订单的新内容)和超媒体控件(工作流程中的下一个有效步骤)。  

Alex的观点是服务的超媒体和资源展现形式应该驱动客户端的工作流,并且他提出了四种可能的方法针对这种交互方式进行建模。其中一些例子可以从RESTBucks的文章里找到。

使用PATCH
[......]这种方式没有得到广泛的支持。我也觉得它语义上存在问题。从客户的角度来看,业务数据组成的订单(多少杯拿铁?)就是整个资源。客户并不会把这种方式看做是PATCH,而会看做是替换,例如PUT。PATCH对于阐述像“在拿铁中放脱脂牛奶,而不是我原来定的全脂牛奶”这样的场景才有意义。
使用POST
这种方法是书中推荐的。对我来说,它与PATCH有类似的问题。POST意味着追加资源。在咖啡订单资源里POST一杯卡布奇诺,感觉就像追加了一杯卡布奇诺,而不是用卡布奇诺替换原有咖啡订单。
使用PUT,包含超媒体
如果遵循严格的解释,PUT应该包括整个展现形式,客户端同时发送完整新咖啡订单和所有的超媒体控件。
使用PUT,不包含超媒体
客户端发送新订单的完整展现形式,但没有链接。我觉的这个概念是对的。客户端通过发送可用的部分数据的完整表现形式来满足PUT的需要,但并不负责哪些超媒体控件是有效的。

经过与 @serialseb@iansrobinson 和 @jimwebber讨论之后,Alex总结了以下规则,这也满足了PUT作为动词语义的期望。

针对GET请求的响应,服务提供现有状态的完整表现形式,包括业务数据和有效的超媒体控件。客户端PUT由其负责的那部分数据的完整展现形式。

针对这一讨论,William Vambenepe补充了其他需要注意的事项

我们来举个简单的例子。如果一个元素没有在部分更新中描述,这意味着什么?是明确的删除动作,表示在展现形式中删除该元素?或表示“不要改变其当前值”。如果是后者的话,我怎么做删除操作呢?是需要部分DELETE,就像部分PUT一样?我希望不是,否则必须要有一种机制来实现类似PUT的部分删除元素。空值?这和并不存在的元素不是一回事。Nil值?那么我如何在JSON中处理它呢?

他声称,设计部分资源更新是个十分困难的问题,现在正试图通过规范解决,例如WSDM、WS-Management和WS-ResourceTransfer。

好消息是我们已经犯了很多错,而且已经得到了很多经验教训(参阅 technical rant、 post-mortem 或 experiment)。坏消息是有大量的新的错误还在等待着我们。

Stu Charlton同样对这个问题抱有疑惑,而且他指出了这样一个事实,RESTFul超媒体不能真正描述数据模型。据他而言,RESTful服务要想具备更好的交互能力,还需要做以下两件事:

(a)[封闭的]数据模型覆盖80%的公共用例,可以基于JSON和XML格式进行描述。

(b)多媒体类型覆盖80%的公共用例,用来描述资源的生命周期和状态转移──换句话说,就是让POST在超媒体中实现自描述。因为计算机的世界不仅仅是更新数据,更多是关于抽象的描述。

针对Alex发表的文章的评论:

你应该具备/两种/资源:客户端的订单告诉服务器它想要什么,服务端的“票据”负责与客户端确认详细信息──增加任何其需要的附加数据、链接等。服务端的票据依赖于客户端的订单,包括在订单执行过程中任何内外部流程的状态。但谁来提供客户订单呢?当然是客户端!那么,除非你有一个不对称的设置,在这种情况下,客户端可以POST和/或PUT它的订单到服务器的某处。现在客户端可以一次性提交和改变/整个/订单资源,不需要担心任何服务端产生的数据。

有很多提议用来解决这一问题,而且,如果能够对资源进行恰当的建模,这个问题似乎可以很容易解决。很多时候会考虑到,把资源作为实体来支持CRUD操作也是同样的问题,只有把建模的资源作为“资源”和提供的服务,就像在Duncan Craggs示例中一样,才是解决问题的方案。不过更大的问题是如何让所有人都同意这个方案。请仔细阅读初始文章评论,并分享你的观点。

查看英文原文:Implementing Partial Updates In RESTful Services

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

的确被这个问题困扰过 by hua wen

自己思考过这个问题,在向别人介绍rest 时,也被问过这个问题
原来还没有比较标准的解决方案。
只有等了,比较靠谱的方案出来,再到有支持的框架,估计还要一段时间

补充 by chi jacky

Stu Charlton提到的两件事,原文中应用不全
(a) a data model that covers 80% of common use cases and can be formatted with JSON and XML. This needs to be a closed-world model, like most databases, and thus I don't think RDF qualifies.

(b) a media type that covers 80% of common use cases to describe a resource's lifecycle and state transitions -- in other words, to make POSTs self-descriptive in hypermedia. Because the world of computing isn't just about updating data, it's about abstractions.

REST是否需要描述业务模型 by chi jacky

如果所有的交互,不管是内部还是外部,都给予RESTful Service来进行,那么肯定是需要描述业务模型的
如果只是进行系统间的交互,是否只需要在JSON或XML中描述清楚要传输的数据和状态,双方遵守契约即可

WCF RAI Service是什么 by Chen Steven

WCF RAI Service是什么

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

4 讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT