Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to manage REST API versioning with spring?
    text
    copied!<p>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.</p> <p>I want to manage the version based on the Accept header, and for example if a request has the Accept header <code>application/vnd.company.app-1.1+json</code>, 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.</p> <p>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)</p> <pre><code>@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; } </code></pre> <p>This is not possible in spring as the 2 methods have the same <code>RequestMapping</code> annotation and Spring fails to load. The idea is that the <code>VersionRange</code> 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.</p> <p>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 <code>ProducesRequestCondition</code>, and have the version range in there. For example</p> <p>Code:</p> <pre><code>@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; } </code></pre> <p>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 (<code>RequestMappingInfoHandlerMapping</code>, <code>RequestMappingHandlerMapping</code> and <code>RequestMappingInfo</code>), which I don't like, because it means extra work whenever I decide to upgrade to a newer version of spring.</p> <p>I would appreciate any thoughts... and especially, any suggestion to do this in a simpler, easier to maintain way.</p> <hr> <h2>Edit</h2> <p>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.</p> <hr> <h2>Edit 2</h2> <p>I've shared the original POC (with some improvements) in github: <a href="https://github.com/augusto/restVersioning">https://github.com/augusto/restVersioning</a></p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload