Restful Pre-Post 或 Pre-Put 警告消息的发送方式

Restful way of sending Pre-Post or Pre-Put warning message

我正在尝试将遗留应用程序转换为 Restful 网络服务。我们的一个旧表单在加载表单时立即显示一条警告消息。此警告消息取决于用户 属性.

例如,如果有一个 属性 isInactiveByDefault,当设置为 "true" 时,将通过 [=12] 设置新创建的员工的状态=] 到 "Inactive"。 "Employee" 表单加载中的用户将看到一条警告消息 "Any new employee created will have inactive status"。

本来想提供一个资源获取属性的状态,让客户端根据属性的值来处理是否显示警告信息。但是我的经理想避免在客户端出现任何业务逻辑。按照他的说法,这是一个业务逻辑,应该从服务器处理。

我想知道发送此警告消息的 Restful 方式是什么。我可以发送带有 POST 响应的消息,但这意味着他们将在操作后收到消息。

我认为将显示或不显示消息的选择权委托给客户端处于所谓的“业务逻辑”的最前沿。我相信这里有争论的余地..

但抛开这一点,如果我们考虑将消息显示为数据,那么只要您的客户端可以进行 REST 调用(通过 JS,AJAX 或其他),您应该能够在加载表单之前或加载时查询服务器(以及 wait/sync)。

因此,在服务上执行 GET 请求以检索警告消息列表(最终国际化)并显示它们是完全正确的,并且“RESTful”。服务器将根据这样或那样的 属性 和 return 准备此警告列表(如 JSON 或其他)。您的客户端只需在您的表单旁边显示请求的解析结果(要列出的 0-N 条消息)。

编辑

您的用例的示例 REST 服务:

@POST
@Path("/v1/employees")
public Response someFormHandlingMethod() {
   // Your form processing
   ...
   if(EmployeeParameters.isInactiveByDefault()) {
      emp.setInactive(true);
   }
   ...
}

@GET
@Path("/v1/employees/formwarnings")
public Response getEmployeeFormWarnings() {
   // "Business logic" -> Determine warning messages to return to client
   ...
   if(EmployeeParameters.isInactiveByDefault()) {
      warnings.add("Any new employee created will have inactive status");
   }
   ...
   // and return them in Response (entity as JSON or whatever). Could also be List<String> for example.
}

这只是一个示例,以便您理解,但实际实施将取决于您的 Jersey 配置、mappers/converters、注释(例如 @Produces)等

REST 架构的重点是通过定义一组双方都应遵守的约束来将客户端与服务器分离。如果严格遵守这些约束,它允许服务器在未来自由发展,而不必冒破坏也遵守 REST 架构的客户端的风险,而这些客户端将因此变得更加健壮以适应变化。因此,服务器应该告诉客户端某些事情需要是什么样子(即通过提供表单和form-controls)以及客户端可以从其当前状态执行的进一步操作(即链接)。

通过请求 Pre-PostPre-Put 操作,我猜您已经假设了一个 HTTP 交互,这对于所谓的“RESTful”系统来说是很常见的。尽管正如 Jim Webber 指出的那样,HTTP 只是一种传输协议,其应用领域是将文档从源传输到目标,我们从该交互中得出的任何业务规则都只是实际文档管理的副作用.所以我们得想办法根据某些单据的处理来触发某些业务活动。除此之外,HTTP 不知道 pre-post 或 pre-put 之类的东西。

通常分布式计算的经验法则是永远不要信任任何客户端输入,从而再次验证服务器端的输入。第一个验证解决方案在服务器上运行,为客户端提供一个 Web form ,它向客户端传授资源的可用属性,并为客户端提供一组输入控件以与该表单交互(即发送按钮单击会将输入数据编组为与服务器支持的 HTTP 操作一起发送的表示格式)。因此,客户端不需要知道服务器的任何内部结构,因为它已获得构成下一个请求所需的所有信息。这本质上就是 HATEOAS 的全部意义所在。一旦服务器在某个端点上收到请求,它就会开始处理接收到的文档,即输入数据,如果违反了对该资源施加的某些限制,它基本上会向客户端发送与以前相同的表单,尽管这次是客户端的输入数据包括进一步的标记,该标记被添加到指示输入错误的表单表示中。通过向该错误添加样式属性,这些错误通常从一般页面设计中脱颖而出(通常是产生违规的输入控件旁边的红色文本 and/or 框),因此可以更轻松地处理问题。

随着 JavaScript 的引入,一些聪明的人想出了一种方法,不仅可以将表单发送到客户端,还可以创建一个脚本,该脚本会在后台自动检查用户输入,如果违反,则会添加上面提到的失败标记动态地添加到当前 form/page 的 DOM,因此通知用户当前输入可能存在的问题。然而,这需要当前的表示格式,或者更正式地说它的 media-type,确实支持动态内容,例如脚本和操纵当前的表示格式。

不幸的是,许多在典型的“REST APIs/services”中交换的表示格式不支持此类属性。一个普通的 JSON 文档,即只定义了基本语法(即 objects 是 key-value 花括号之间的容器,...)但它没有为它定义的任何字段定义语义可能包含,它甚至不知道 URI 是什么等等。因此,JSON 不是 REST 架构的良好表示格式。在 HAL/JSON or JSON Hyper-Schema attempt to add support for links and rudimentary semantics, they yet create their own media-types and thus representation formats all along. Other JSON based media types, such as hal-forms, halo+json (halform) and ion 期间尝试添加 form-support。其中一些 media-type 格式可能允许对某些 form-elements 添加限制,这些限制会自动以用户警告告终,如果违反则阻止实际文档传输,尽管当前大多数媒体类型可能还缺乏支持 client-sided 脚本或动态内容更新。

这样的情况导致菲尔丁在他的 famous blog posts 之一中得出这样的陈述:

A REST API should spend almost all of its descriptive effort in defining the media type(s) used for representing resources and driving application state, or in defining extended relation names and/or hypertext-enabled mark-up for existing standard media types

通常问题不应该是支持哪种媒体类型,而是您的 server/client 应该支持多少种不同的媒体类型,因为它可以处理的媒体类型表示越多,它与对等方交互的能力就越强。理想情况下,您希望为所有交互重用同一个客户端,而同一个服务器应该能够为多个客户端提供服务,尤其是那些不受您直接控制的客户端。

关于“RESTful”解决方案,我不建议使用自定义 headers 或专有消息格式,因为它们通常只能被有限数量的客户端理解和处理,这是与 REST 架构的实际目标相反。此类消息通常还需要服务器行为的先验知识,如果服务器需要更改,这可能会导致问题。

所以,长话短说,本质上是引入“RESTful”的最安全方式(~这符合 REST 架构实施的约束)对资源的输入验证是通过使用 form-based 表示,它教导客户端创建实际请求所需的一切,其中请求由服务器,如果某些输入约束得到验证,则会导致将表单再次返回给客户端,并提示相应的输入问题。

如果出于性能方面的考虑(这通常不是手头的核心问题),您希望尽量减少客户端和服务器之间的交互,您可能需要定义自己的媒体类型,以添加脚本支持和动态内容更新,通过类似的手段比如DOM操纵之类的。然而,这样的自定义媒体类型应该是 registered with IANA 以允许其他实现者添加对此类类型的支持,从而允许其他客户端将来与您的系统交互。