基于JAX-RS的实现中的简单REST资源版本控制? [英] Easy REST resource versioning in JAX-RS based implementations?

查看:111
本文介绍了基于JAX-RS的实现中的简单REST资源版本控制?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Best practice for REST resource versioning is putting version information into Accept/Content-Type headers of HTTP request leaving URI intact.

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

Here is the sample request/response to REST API for retrieving system information:

==>
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类型中指定的。

Pay attention that version is specified in MIME type.

这是另一个请求/对版本2的回复:

Here is another request/response for version 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/ 获取更多解释和示例。

See http://barelyenough.org/blog/tag/rest-versioning/ for more explanation and examples.

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

Is it possible to implement this approach easily in Java-targeted JAX-RS based implementations, such as Jersey or Apache CXF?

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

The goal is to have several @Resource classes with the same @Path value, but serving the request based on actual version specified in MIME type?

我已经研究了JAX-RS,特别是泽西和发现不支持。泽西岛没有机会用相同的路径注册两个资源。需要实现WebApplicationImpl类的替换以支持它。

I've looked into JAX-RS in general and Jersey in particlaur and found no support for that. Jersey doesn't give a chance to register two resources with the same path. Replacement for WebApplicationImpl class needs to implemented to support that.

你能建议吗?

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

推荐答案

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

JAX-RS dispatches to methods annotated with @Produces via the Accept header. So, if you want JAX-RS to do your dispatching, you'll need to leverage this mechanism. Without any extra work, you would have to create a method (and Provider) for every media type you wish to support.

没有什么可以阻止你使用基于媒体类型的几种方法来调用常用的方法来完成这项工作,但是你必须更新它并每次添加代码你添加新媒体类型的时间。

There's nothing stopping you from having several methods based on media type that all call a common method to do that work, but you'd have to update that and add code every time you added a new media type.

一个想法是添加一个过滤器,专门为调度规范化你的Accept标头。也就是说,或许,拿下你的:

One idea is to add a filter that "normalizes" your Accept header specifically for dispatch. That is, perhaps, taking your:

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

并将其转换为:

Accept: application/vnd.COMPANY.systeminfo+json

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

At the same time, you extract the version information for later use (perhaps in the request, or some other ad hoc mechanism).

然后,JAX-RS将调度到处理的单个方法application / vnd.COMPANY.systeminfo + json。

Then, JAX-RS will dispatch to the single method that handles "application/vnd.COMPANY.systeminfo+json".

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

THAT method then takes the "out of band" versioning information to handle details in processing (such as selecting the proper class to load via OSGi).

接下来,您将使用适当的MessageBodyWriter创建一个Provider。 JAX-RS将为application / vnd.COMPANY.systeminfo + json媒体类型选择提供程序。由你的MBW决定实际的媒体类型(再次基于该版本信息)并创建正确的输出格式(再次,可能调度到正确的OSGi加载类)。

Next, you then create a Provider with an appropriate MessageBodyWriter. The provider will be selected by JAX-RS for the application/vnd.COMPANY.systeminfo+json media type. It will be up to your MBW to figure out the actual media type (based again on that version information) and to create the proper output format (again, perhaps dispatching to the correct OSGi loaded class).

我不知道MBW是否可以覆盖Content-Type标头。如果没有,那么您可以委派早期的过滤器在出路时为您重写该部分。

I don't know if an MBW can overwrite the Content-Type header or not. If not, then you can delegate the earlier filter to rewrite that part for you on the way out.

这有点令人费解,但是如果你想利用JAX-RS发送,而不是为您的媒体类型的每个版本创建方法,然后这是一个可能的路径。

It's a little convoluted, but if you want to leverage JAX-RS dispatch, and not create methods for every version of your media type, then this is a possible path to do that.

编辑以回应评论:

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

Yea, essentially, you want JAX-RS to dispatch to the proper class based on both Path and Accept type. It is unlikely that JAX-RS will do this out of the box, as it's a bit of an edge case. I have not looked at any of the JAX-RS implementations, but you may be able to do what you want by tweaking one of the at the infrastructure level.

可能是另一个更少侵入性的选择是使用来自Apache世界的古老技巧,并简单地创建一个基于Accept标头重写路径的过滤器。

Possibly another less invasive option is to use an age old trick from the Apache world, and simply create a filter that rewrites your path based on the Accept header.

因此,当系统获取:

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

您将其重写为:

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

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

Then, in your JAX-RS class:

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

因此,您的客户端可以获得正确的视图,但JAX-RS会正确调度您的类。唯一的另一个问题是你的类看起来会看到修改后的路径,而不是原始路径(但是如果你愿意,你的过滤器可以将请求中的内容作为参考)。

So, your clients get the correct view, but your classes get dispatched properly by JAX-RS. The only other issue is that your classes, if they look, will see the modified Path, not the original path (but your filter can stuff that in the request as a reference if you like).

这不是理想的,但它(大多数)是免费的。

It's not ideal, but it's (mostly) free.

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

This is an existing filter that might do what you want to do, if not it perhaps can act as an inspiration for you to do it yourself.

这篇关于基于JAX-RS的实现中的简单REST资源版本控制?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆