代码之家  ›  专栏  ›  技术社区  ›  Kevin Pauli

对调用服务器端操作到资源的按钮按下的RESTful建模

  •  3
  • Kevin Pauli  · 技术社区  · 15 年前

    我正在着手开发一款新的网络应用程序,我们想让它安静地运行。现在是时候开始设计交互了,一些基本的关于休息的东西让我很为难。我正在尝试找出最佳的方法来调解REST和OO之间的阻抗失配,而不降低RPC的滑坡。让我举个(人为的)例子。

    可以创建、修改小部件,然后提交以供审阅。

    要修改ID为123的小部件,用户需要执行一个put to/myapp/widget/123和新的表单数据。服务器将所有表单数据重新打包为POJO,并将其交给逻辑层进行验证和后续持久化,调用widgetmanager.update(widgetpojo)。

    要提交一个小部件以供审阅,用户单击一个按钮,该按钮也会执行Put to/MyApp/Widget/123操作,但现在表单数据只有一个字段,状态为“已提交”(我不再发送所有表单数据,只发送要更改的字段)。但是,现在服务器需要调用另一个业务对象widgetStateManager.updateState(123,“已提交”),除了更新状态外,该对象还将执行其他一些专门的处理。

    因此,为了实现RESTful,我对小部件更新和提交供审阅操作进行了建模,并将其放到相同的URL/myapp/widget/123中。所以现在,在我的服务器端代码中,我需要弄清楚一个特定的Put请求在业务函数方面意味着什么,因此需要调用哪个业务函数。

    但是,我如何能够通过检查表单数据中的值来可靠地确定要调用哪个函数呢?很容易通过一个“action”字段和表单数据,在put中有一个值,如“update”或“submit for review”!然后服务器可以根据该值进行切换。但是,这当然不是休息,只是打扮成RPC。

    仅仅通过在restlet中使用一堆if-then-else检查表单数据就可以推断出单击了什么按钮,这看起来既不安全也不可扩展。我可以想象在一个小部件上可以执行几十种不同的操作,因此可以想象几十种if-then-else。我这里缺什么?我的直觉告诉我我没有正确地建模我的资源,或者我缺少一个可以帮助我的资源抽象。

    3 回复  |  直到 15 年前
        1
  •  3
  •   Chris McCauley    15 年前

    几点;

    服务接口的域!=实现域

    您的服务公开的资源不必在代码中作为对象直接实现。(服务)接口不是实现。


    Put&Post需要所有外部状态

    在进行更新时,必须提供所有资源状态(您说过只提供更改—这是一个补丁,而不是一个Put)。


    通过收集资源模拟状态变化

    有时最好将状态更改建模为集合资源。在您的示例中,您确实需要考虑具有关联的“审阅队列”的“审阅”资源。 向小部件添加“需要检查”属性。

    方法1。“审阅队列”的容器

    拥有“review”对象可以很容易地列出要查看的小部件、分配要查看的资源等。

    GET/REVIEW队列——列出需要评审的小部件

    发布/审阅队列——创建一个新的审阅条目(只列出小部件的ID、名称和返回小部件的URL)

    delete/review queue/x——当小部件被检查时从队列中删除

    如果存在与“审查队列”相关联的重要行为,例如与添加用于审查的小部件相关联的权限、多个审查队列等,我将使用此方法。

    方法2。“需要审查”属性

    您可能会认为一个单独的资源对您的需求来说是多余的。您可以使用post、put和get对基本功能进行建模。

    当一个小部件被创建时,它的状态包括一个“需要审查”属性,该属性设置为假。显然你需要所有的外部状态

    当一个小部件需要审查时,获取它并将其放回“需要审查”更新。再一次, 你需要所有的外部状态 投入中

    列出小部件以供审阅时使用

    获取/微件/?需要审查=真


    可怜的旧RPC

    你在最后一段提到了RPC,尽管它已经脱离主题,但我还是忍不住要评论…

    我想也许我们现在都有罪,因为我们把这个世界的恶习归咎于RPC。RPC的真正问题是,它的目的是使远程函数调用对程序员透明,隐藏故障场景,并试图使远程调用在实现语言中与标准函数调用等效。作为一个老的CORBA(遭受同样的问题)程序员,我可以理解REST是如何纠正这种失败的。


    从你的岗位上得到的其他点

    如果不检查新状态并将其与现有状态进行比较,就无法确定要调用的方法。

    您应该在执行任何其他操作之前验证新状态,将任何错误传递回提交者。

    从你最后一段开始,我想你已经知道了-对不起。

    克里斯

        2
  •  4
  •   Willis Blackburn    15 年前

    您不限于将URL映射到域对象。RESTfulAPI有少量的操作,但有大量的资源可以应用这些操作。

    创建小部件:

    发布到/rest/widget(返回“123”)。

    (post方法用于请求源服务器接受请求中包含的实体作为请求行中请求URI标识的资源的新下属。)

    验证小部件123:

    发布到/restapi/validator/123

    (该资源是小部件123的名义“验证器”。)

    更新小部件123:

    放入/restapi/widget/123

    提交小部件123以供审查:

    发布到/restapi/reviewqueue

    (只有一个审查队列,因此不需要/123。)

    删除小部件:

    删除到/restapi/widget/123

        3
  •  0
  •   Stefan Tilkov    15 年前

    很难说不知道该领域的更多信息,但是拥有一个“待审查”的收集资源可能是一个好主意。当您的资源在流程中流动时,您可以将它们从一个列表移动到下一个列表。作为一个附带的好处,您还可以选择在这些列表中进行一次访问,以了解哪些资源处于该特定状态。