Я искал, как управлять версиями API REST с помощью 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, я хотел бы обработать это следующим образом. Представьте, что код находится внутри контроллера и что есть код, который может извлечь версию из заголовка. (В 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;
}
Это невозможно в Spring, поскольку 2 метода имеют одинаковую аннотацию 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.
Я был бы признателен за любые мысли... и особенно, любое предложение сделать это проще, легче поддерживать.
Изменить
Добавление щедрости. Чтобы получить награду, пожалуйста, ответьте на вопрос выше, не предлагая эту логику в самом контроллере. Spring уже имеет много логики, чтобы выбрать, какой метод контроллера вызывать, и я хочу с этим справиться.
Изменить 2
Я поделился исходным POC (с некоторыми улучшениями) в github: https://github.com/augusto/restVersioning