Я искал, как управлять версиями REST API с помощью Spring 3.2.x, но не нашел ничего, что было бы легко поддерживать. Сначала я объясню свою проблему, а затем решение ... но мне интересно, изобретаю ли я здесь колесо заново.
Я хочу управлять версией на основе заголовка Accept, и, например, если запрос имеет заголовок Accept application/vnd.company.app-1.1+json
, я хочу, чтобы Spring MVC перенаправлял его методу, который обрабатывает эту версию. И поскольку не все методы в API меняются в одном и том же выпуске, я не хочу переходить к каждому из моих контроллеров и изменять что-либо для обработчика, которое не изменилось между версиями. Я также не хочу иметь логику, чтобы выяснить, какую версию использовать в самом контроллере (с помощью локаторов служб), поскольку Spring уже обнаруживает, какой метод вызывать.
Итак, взяв API с версиями 1.0 до 1.8, где обработчик был представлен в версии 1.0 и модифицирован в версии 1.7, я бы хотел обработать это следующим образом. Представьте, что код находится внутри контроллера, и что есть код, который может извлечь версию из заголовка. (Следующее недействительно весной)
@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;
}
Это невозможно весной, так как два метода имеют одинаковую RequestMapping
аннотацию и Spring не загружается. Идея состоит в том, что VersionRange
аннотация может определять диапазон открытой или закрытой версии. Первый метод действителен для версий с 1.0 по 1.6, а второй - для версии 1.7 и выше (включая последнюю версию 1.8). Я знаю, что этот подход ломается, если кто-то решает передать версию 99.99, но я могу с этим жить.
Теперь, поскольку вышеизложенное невозможно без серьезной доработки того, как работает Spring, я думал о том, чтобы поработать с тем, как обработчики сопоставляются с запросами, в частности, чтобы написать свой собственный ProducesRequestCondition
, и иметь там диапазон версий. Например
Код:
@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 уже есть много логики для выбора вызываемого метода контроллера, и я хочу воспользоваться этим.
Редактировать 2
Я поделился исходным POC (с некоторыми улучшениями) в github: https://github.com/augusto/restVersioning
produces={"application/json-1.0", "application/json-1.1"}
etc