java - 基于 JAX-RS 的实现中的简单 REST 资源版本控制?

标签 java rest versioning jersey jax-rs

REST 资源版本控制的最佳实践是将版本信息放入 HTTP 请求的 Accept/Content-Type header 中,同时保持 URI 不变。

以下是用于检索系统信息的 REST API 请求/响应示例:

==>
GET /api/system-info HTTP/1.1
Accept: application/vnd.COMPANY.systeminfo-v1+json

<==
HTTP/1.1 200 OK
Content-Type: application/vnd.COMPANY.systeminfo-v1+json
{
  “session-count”: 19
}

注意版本以MIME类型指定。

这是版本 2 的另一个请求/响应:

==>
GET /api/system-info HTTP/1.1
Accept: application/vnd.COMPANY.systeminfo-v2+json

<==
HTTP/1.1 200 OK
Content-Type: application/vnd.COMPANY.systeminfo-v2+json
{
  “uptime”: 234564300,
  “session-count”: 19
}

有关更多解释和示例,请参阅 http://barelyenough.org/blog/tag/rest-versioning/

是否可以在基于 Java 的基于 JAX-RS 的实现(例如 Jersey 或 Apache CXF)中轻松实现此方法?

目标是拥有多个具有相同@Path 值的@Resource 类,但根据 MIME 类型中指定的实际版本提供请求?

我总体上研究了 JAX-RS,特别研究了 Jersey,但没有发现对此的支持。 Jersey 没有机会用相同的路径注册两个资源。需要实现 WebApplicationImpl 类的替换以支持该类。

你能推荐点什么吗?

注意:同一资源的多个版本需要同时可用。新版本可能会引入不兼容的更改。

最佳答案

JAX-RS 通过 Accept header 分派(dispatch)给使用 @Produces 注释的方法。因此,如果您希望 JAX-RS 进行调度,则需要利用此机制。如果没有任何额外的工作,您将必须为您希望支持的每种媒体类型创建一个方法(和提供程序)。

没有什么可以阻止您拥有多种基于媒体类型的方法,这些方法都调用一个通用方法来完成这项工作,但您必须在每次添加新媒体类型时更新它并添加代码。

一个想法是添加一个过滤器,专门为发送“规范化”您的 Accept header 。也就是说,也许,采取你的:

Accept: application/vnd.COMPANY.systeminfo-v1+json

并将其简单地转换为:

Accept: application/vnd.COMPANY.systeminfo+json

同时,您提取版本信息供以后使用(可能在请求中,或其他一些临时机制)。

然后,JAX-RS 将分派(dispatch)到处理“application/vnd.COMPANY.systeminfo+json”的单一方法。

该方法然后采用“带外”版本控制信息来处理处理中的细节(例如选择适当的类通过 OSGi 加载)。

接下来,您将创建一个具有适当 MessageBodyWriter 的提供者。提供商将由 JAX-RS 为 application/vnd.COMPANY.systeminfo+json 媒体类型选择。由您的 MBW 确定实际的媒体类型(再次基于该版本信息)并创建正确的输出格式(同样,可能分派(dispatch)到正确的 OSGi 加载类)。

我不知道 MBW 是否可以覆盖 Content-Type header 。如果没有,那么您可以委托(delegate)早期的过滤器在退出时为您重写该部分。

这有点令人费解,但如果您想利用 JAX-RS 分派(dispatch),而不是为您的媒体类型的每个版本创建方法,那么这是一种可行的方法。

编辑以回应评论:

是的,本质上,您希望 JAX-RS 根据 Path 和 Accept 类型分派(dispatch)到正确的类。 JAX-RS 不太可能开箱即用,因为它有点边缘情况。我没有查看任何 JAX-RS 实现,但您可以通过在基础架构级别调整其中一个实现来完成您想要的操作。

可能另一个侵入性较小的选择是使用 Apache 世界中的一个古老技巧,并简单地创建一个过滤器来根据 Accept header 重写您的路径。

所以,当系统得到:

GET /resource
Accept: application/vnd.COMPANY.systeminfo-v1+json

您将其重写为:

GET /resource-v1
Accept: application/vnd.COMPANY.systeminfo-v1+json

然后,在您的 JAX-RS 类中:

@Path("resource-v1")
@Produces("application/vnd.COMPANY.systeminfo-v1+json")
public class ResourceV1 {
    ...
}

因此,您的客户获得了正确的 View ,但您的类得到了 JAX-RS 的正确分派(dispatch)。唯一的另一个问题是,如果您的类看起来会看到修改后的路径,而不是原始路径(但如果您愿意,您的过滤器可以将其作为引用填充到请求中)。

它并不理想,但它(大部分)是免费的。

This是一个现有的过滤器,它可能会做你想做的事情,如果不是,它也许可以作为你自己做的灵感。

关于java - 基于 JAX-RS 的实现中的简单 REST 资源版本控制?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4924034/

相关文章:

java - 从文件中读取俄语字符(javaSE)

java - Java继承中的 "this"关键字是如何工作的?

java - hibernate 更新不起作用

rest - Paypal 从 IPN 过渡到 REST API

ruby-on-rails - Rails 记录版本控制解决方案

java - JNI - 从 C++ 调用 Java 方法

rest - 为什么发布到 PayPal 沙盒 API 对我不起作用?

rest - REST 和 Angular 2.0 的 Spring 安全

java - 多配置文件项目的 Maven 版本控制

c# - .NET 中 dll 的版本号