Szukałem, jak zarządzać wersjami REST API za pomocą Spring 3.2.x, ale nie znalazłem niczego, co byłoby łatwe w utrzymaniu. Najpierw wyjaśnię problem, który mam, a potem rozwiązanie ... ale zastanawiam się, czy tu ponownie wymyślam koło.
Chcę zarządzać wersją opartą na nagłówku Accept i na przykład, jeśli żądanie ma nagłówek Accept application/vnd.company.app-1.1+json
, chcę, aby Spring MVC przekazał to do metody, która obsługuje tę wersję. A ponieważ nie wszystkie metody w API zmieniają się w tym samym wydaniu, nie chcę przechodzić do każdego z moich kontrolerów i zmieniać niczego dla procedury obsługi, która nie zmieniła się między wersjami. Nie chcę też mieć logiki, która pozwoliłaby na ustalenie, której wersji użyć w samym kontrolerze (używając lokalizatorów usług), ponieważ Spring już odkrywa, którą metodę wywołać.
Więc wziąwszy API z wersjami 1.0 do 1.8, gdzie handler został wprowadzony w wersji 1.0 i zmodyfikowany w v1.7, chciałbym zająć się tym w następujący sposób. Wyobraź sobie, że kod znajduje się wewnątrz kontrolera i że istnieje kod, który jest w stanie wyodrębnić wersję z nagłówka. (Poniższe informacje są nieważne na wiosnę)
@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;
}
Nie jest to możliwe wiosną, ponieważ obie metody mają takie same RequestMapping
adnotacje, a sprężyna nie ładuje się. Chodzi o to, że VersionRange
adnotacja może definiować otwarty lub zamknięty zakres wersji. Pierwsza metoda obowiązuje od wersji 1.0 do 1.6, a druga dla wersji 1.7 i nowszych (w tym najnowszej wersji 1.8). Wiem, że to podejście zawodzi, jeśli ktoś zdecyduje się przekazać wersję 99.99, ale to jest coś, z czym mogę żyć.
Teraz, ponieważ powyższe nie jest możliwe bez poważnej zmiany sposobu działania sprężyny, myślałem o majstrowaniu przy sposobie dopasowywania programów obsługi do żądań, w szczególności o pisaniu własnych ProducesRequestCondition
i posiadaniu tam zakresu wersji. Na przykład
Kod:
@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;
}
W ten sposób mogę mieć zamknięte lub otwarte zakresy wersji zdefiniowane w części adnotacji produkującej. Pracuję nad tym roztworze teraz z problemem, że miałem jeszcze wymienić kilka podstawowych klas wiosny MVC ( RequestMappingInfoHandlerMapping
, RequestMappingHandlerMapping
i RequestMappingInfo
), która mi się nie podoba, bo to oznacza dodatkową pracę, gdy zdecyduję się uaktualnienie do nowszej wersji wiosna.
Byłbym wdzięczny za wszelkie przemyślenia ... a zwłaszcza wszelkie sugestie, aby zrobić to w prostszy, łatwiejszy do utrzymania sposób.
Edytować
Dodanie nagrody. Aby otrzymać nagrodę, odpowiedz na powyższe pytanie bez sugerowania posiadania tej logiki w samym kontrolerze. Spring ma już dużo logiki, aby wybrać metodę kontrolera do wywołania i chcę na to przejść.
Edytuj 2
Udostępniłem oryginalny POC (z pewnymi ulepszeniami) na github: https://github.com/augusto/restVersioning
produces={"application/json-1.0", "application/json-1.1"}
Itd.