如何使用spring管理REST API版本控制? [英] How to manage REST API versioning with spring?

查看:91
本文介绍了如何使用spring管理REST API版本控制?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在搜索如何使用Spring 3.2.x管理REST API版本,但我找不到任何易于维护的版本。我先解释一下我遇到的问题,然后解决一个问题......但我确实想知道我是不是在这里重新发明了这个轮子。

I've been searching how to manage a REST API versions using Spring 3.2.x, but I haven't find anything that is easy to maintain. I'll explain first the problem I have, and then a solution... but I do wonder if I'm re-inventing the wheel here.

我想要管理基于Accept标头的版本,例如,如果请求具有Accept标头 application / vnd.company.app-1.1 + json ,我希望spring MVC转发这是处理此版本的方法。并且由于并非API中的所有方法都在同一版本中发生更改,因此我不想转到每个控制器并更改任何版本之间未更改的处理程序。我也不想有逻辑来确定控制器本身使用哪个版本(使用服务定位器),因为Spring已经发现了要调用的方法。

I want to manage the version based on the Accept header, and for example if a request has the Accept header application/vnd.company.app-1.1+json, I want spring MVC to forward this to the method that handles this version. And since not all methods in an API change in the same release, I don't want to go to each of my controllers and change anything for a handler that hasn't changed between versions. I also don't want to have the logic to figure out which version to use in the controller themselves (using service locators) as Spring is already discovering which method to call.

所以采用版本1.0到1.8的API,其中版本1.0中引入了处理程序,并在v1.7中进行了修改,我想通过以下方式处理它。想象一下,代码在控制器内部,并且有一些代码能够从头部提取版本。 (以下在春季无效)

So taken an API with versions 1.0, to 1.8 where a handler was introduced in version 1.0 and modified in v1.7, I would like handle this in the following way. Imagine that the code is inside a controller, and that there's some code that is able to extract the version from the header. (The following is invalid in Spring)

@RequestMapping(...)
@VersionRange(1.0,1.6)
@ResponseBody
public Object method1() {
   // so something
   return object;
}

@RequestMapping(...) //same Request mapping annotation
@VersionRange(1.7)
@ResponseBody
public Object method2() {
   // so something
   return object;
}

这在春天是不可能的,因为2种方法具有相同的 RequestMapping 注释,Spring无法加载。我们的想法是 VersionRange 注释可以定义打开或关闭的版本范围。第一种方法从版本1.0到1.6有效,而第二种方法从版本1.7开始(包括最新版本1.8)。我知道如果有人决定通过99.99版本,这种方法会中断,但这是我可以忍受的。

This is not possible in spring as the 2 methods have the same RequestMapping annotation and Spring fails to load. The idea is that the VersionRange annotation can define an open or closed version range. The first method is valid from versions 1.0 to 1.6, while the second for version 1.7 onwards (including the latest version 1.8). I know that this approach breaks if someone decides to pass version 99.99, but that's something I'm OK to live with.

现在,因为如果没有对Spring如何工作的认真修改,我正在考虑修改处理程序与请求匹配的方式,特别是编写我自己的 ProducesRequestCondition ,并在那里有版本范围。例如

Now, since the above is not possible without a serious rework of how spring works, I was thinking of tinkering with the way handlers matched to requests, in particular to write my own ProducesRequestCondition, and have the version range in there. For example

代码:

@RequestMapping(..., produces = "application/vnd.company.app-[1.0-1.6]+json)
@ResponseBody
public Object method1() {
   // so something
   return object;
}

@RequestMapping(..., produces = "application/vnd.company.app-[1.7-]+json)
@ResponseBody
public Object method2() {
   // so something
   return object;
}

通过这种方式,我可以在产品中定义已关闭或打开的版本范围注释的一部分。我现在正在研究这个解决方案,问题是我仍然需要更换一些核心的Spring MVC类( RequestMappingInfoHandlerMapping RequestMappingHandlerMapping RequestMappingInfo ),我不喜欢,因为每当我决定升级到更新版本的spring时,这意味着额外的工作。

In this way, I can have closed or open version ranges defined in the produces part of the annotation. I'm working on this solution now, with the problem that I still had to replace some core Spring MVC classes (RequestMappingInfoHandlerMapping, RequestMappingHandlerMapping and RequestMappingInfo), which I don't like, because it means extra work whenever I decide to upgrade to a newer version of spring.

我会很感激任何想法......特别是,任何建议都可以用更简单,更容易维护的方式来做到这一点。

I would appreciate any thoughts... and especially, any suggestion to do this in a simpler, easier to maintain way.

添加赏金。为了得到赏金,请回答上面的问题,而不建议在控制器本身有这个逻辑。 Spring已经有很多逻辑来选择调用哪个控制器方法,我想捎带它。

Adding a bounty. To get the bounty, please answer the question above without suggesting to have this logic in the controller themselves. Spring already has a lot of logic to select which controller method to call, and I want to piggyback on that.

我在github中分享了原始POC(有一些改进): https ://github.com/augusto/restVersioning

I've shared the original POC (with some improvements) in github: https://github.com/augusto/restVersioning

推荐答案

无论通过向后兼容的更改是否可以避免版本控制(当你受到某些公司指导方针的约束时可能并不总是可能,或者你的API客户端以错误的方式实现,即使它们不应该会破坏)抽象的要求是一个有趣的要求:

Regardless whether versioning can be avoided by doing backwards compatible changes (which might not always possible when you are bound by some corporate guidelines or your API clients are implemented in a buggy way and would break even if they should not) the abstracted requirement is an interesting one:

如何在不在方法体中进行评估的情况下,对请求中的标头值进行任意评估的自定义请求映射?

此SO答案中所述, lly可以具有相同的 @RequestMapping 并使用不同的注释来区分在运行时期间发生的实际路由。为此,您必须:

As described in this SO answer you actually can have the same @RequestMapping and use a different annotation to differentiate during the actual routing that happens during runtime. To do so, you will have to:


  1. 创建新注释 VersionRange

  2. 实施 RequestCondition< VersionRange> 。由于您将拥有类似最佳匹配算法的内容,因此您必须检查使用其他 VersionRange 值注释的方法是否为当前请求提供了更好的匹配。

  3. 根据注释和请求条件实现 VersionRangeRequestMappingHandlerMapping (如帖子如何实现@RequestMapping自定义属性

  4. 配置spring以评估 VersionRangeRequestMappingHandlerMapping 在使用默认 RequestMappingHandlerMapping 之前(例如,通过将其顺序设置为0)。

  1. Create a new annotation VersionRange.
  2. Implement a RequestCondition<VersionRange>. Since you will have something like a best-match algorithm you will have to check whether methods annotated with other VersionRange values provide a better match for the current request.
  3. Implement a VersionRangeRequestMappingHandlerMapping based on the annotation and request condition (as described in the post How to implement @RequestMapping custom properties ).
  4. Configure spring to evaluate your VersionRangeRequestMappingHandlerMapping before using the default RequestMappingHandlerMapping (e.g. by setting its order to 0).

这不需要任何Spring组件的hacky替换,但使用Spring配置和扩展机制,因此即使您更新Spring版本它也应该工作(只要新版本支持这些机制)。

This wouldn't require any hacky replacements of Spring components but uses the Spring configuration and extension mechanisms so it should work even if you update your Spring version (as long as the new version supports these mechanisms).

这篇关于如何使用spring管理REST API版本控制?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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