假设您有一个Person资源,其部分表示包含一个Location值,其值可以是“at home”,“at school”和“at work”。你会如何重新揭露“回家”,“上班”,“上学”等活动?为了便于讨论,让我们规定这些活动需要时间,因此它们是异步执行的,并且有各种各样的方法可能会失败(没有交通工具,旅行期间的交通故障,上帝的其他行为等) 。此外,Person资源还有其他属性和影响这些属性的相关操作(例如attribute = energy-level,operations = eat / sleep / excercise)。
选项1 :在Person资源上重载POST,提供一个输入参数,指示您希望此人做什么(例如,action = go-to-school)。从POST返回202并在Person的表示中公开活动进行中状态属性,客户端可以获取该状态属性以观察进度和成功/失败。
好处:让它变得简单。
缺点:相当于隧道效应。发生的操作隐藏在有效负载中,而不是在URI,动词,标题等中可见。此资源上的POST动词没有单一的语义含义。
选项2 :使用PUT将Person的位置设置为您希望他们拥有的状态。从PUT返回202并通过GET公开状态轮询的活动进行中属性。
好处:不确定我看到了什么。
缺点:实际上,这只是用另一个动词进行隧道传输。此外,它在某些情况下不起作用(睡眠和进食都会增加能量水平,因此将能量水平设置为更高的值在您希望资源执行的操作方面是不明确的。)
选项3 :公开对Person对象进行操作的通用控制器资源。例如,创建一个PersonActivityManager资源,该资源接受带有标识目标Person和请求操作的参数的POST请求。 POST可以返回PersonActivity资源来表示正在进行的活动,客户端可以通过GET来监视进度和成功/失败。
好处:通过将活动及其状态与Person资源分开,看起来更清晰。
缺点:现在我们已将隧道移动到PersonActivityManager资源。
选项4 : 为每个支持的操作建立单独的控制器资源,例ToWorkTransporter资源,接受带有标识Person的参数(或URI元素)的POST请求,以及ToHomeTransporter,ToSchoolTransporter,MealServer,Sleeper和Exerciser。每个都从POST方法返回一个适当的任务监控资源(Commute,Meal,Slumber,Workout),客户端可以通过GET监控它。
好处:好的,我们终于淘汰了隧道。每个POST只意味着一件事。
缺点:现在谈论了很多资源(也许我们可以将传输器合并到一个接受目标参数的传输器中)。其中一些是非常语义上的设计(一个沉睡者?)。它可能更RESTful,但它是否实用?
答案 0 :(得分:18)
Tim似乎在我的#3和#4选项之间解决了问题,暴露了多个控制器资源,但是从“过度”退出并为所有内容分别拥有控制器资源。 蒂姆的帖子由Roy Fielding(It is OK to use POST)导致了另一个帖子,他说,对于有可监控实体状态的情况,以及可能改变该状态的行为,他倾向于使用POST而不是PUT 。针对评论者建议将被监控状态作为单独的PUT资源公开,他说“如果我想更新现有资源中的某些字段,我很倾向 考虑PUT。但这不起作用,因为它应该是 幂等,并重新启动服务器肯定不是。好吧,好吧,做吧 POST我想;没什么大不了的。
但你并没有真正改变一个州,你要求具体的 要发生的一系列行动,国家可能会或可能会这样做 没有达到预期的价值。实际上,当你点击部署开关时, 国家改为部署,然后经过一些不可预测的改变 部署的时间量。重启操作是经典的 箱子侧面有一个大红色开关;问题是如何 按下开关。
所以,我越想到它,我就越认为这些资源是 像按钮,只有一个定义的操作:推。人们一直都是 抱怨“只写资源”,但我没有问题 因为它似乎准确。重启和暂停按钮没有 真的有任何状态,所以你不应该期待任何有用的东西 GET“。
“当更新操作是幂等的时,我们只使用PUT 表示完整。我认为我们应该定义一个额外的 我们认为资源可能对其他人有用的资源 隔离,并使用该资源的GET / PUT方法,但是 我认为我们不应仅仅为了这个目的而定义新资源 避免POST。“
最后,Bill {h}在Just use POST中讨论了使用PUT与POST更新集合资源状态的具体情况,以及其中的权衡。