2013-05-22 16 views
6

Jedną z najlepszych praktyk pisania aplikacji RESTFul api jest dodanie wersji. na przykład:Implementacja REST Api przy użyciu Spring

http://my-server/api/v1/getData 
http://my-server/api/v2/getData 

Nasza aplikacja udostępnia REST api przy użyciu frameworka Spring. Oznaczamy klasę jako kontroler, używamy adnotacji RequestMapping do mapowania adresu URL do funkcji i dodawania obiektów, które są tłumaczone na/z obiektów json.

Na przykład:

@RequestMapping(method = RequestMethod.POST, value = "/api/v1/getData") 
public @ResponseBody ResponseDataDTO getData(@RequestBody OperationsDetailsTDO details) {...} 

Teraz chcemy zapewnić drugą wersję API. Około 2/3 funkcji pozostaje bez zmian, a 1/3 się zmienia. Zmiany są zarówno w logice, jak i obiektach JSON.

Zastanawiam się, jak zaprojektować kod. Myślę, że ten rodzaj kodu jest trudna do zarządzania:

@RequestMapping(method = RequestMethod.POST, value = "/api/{version-var}/getData") 
public @ResponseBody ResponseDataDTO createReleaseFromTemplate(@PathVariable("version-var") Integer version, @RequestBody OperationsDetailsTDO details) { 
if (version == 1) 
{ 
    doForVersion1(); 
} 
else if (version == 2) 
{ 
    doForVersion2(); 
} 

} 

To będzie trudne do zarządzania, ponieważ w każdej funkcji nie będzie inaczej rozgałęzienia. Aby zademonstrować problem, jeśli mam automatyczne narzędzie, które generuje dokumentację, nie będzie w stanie zrozumieć, czym jest API.

Po drugie, zastanawiam się, co powinienem zrobić z klasami związanymi z obiektem JSON. Czy muszę zduplikować wszystkie te klasy, aby wprowadzić drobne zmiany?

Thx.

+0

Powiązane http://stackoverflow.com/questions/389169/best-practices-for-api-versioning – andyb

+0

W końcu to inne API. Będziesz musiał zmienić wszystko, co z niego korzysta. –

Odpowiedz

1

Zgadzam się z Tobą w sprawie uchwalenia wersję jako parametr, podobnie jak

@RequestMapping(method = RequestMethod.POST, value = "/api/{version-var}/getData") 

Ale nie sądzę, że to dobry pomysł, aby dodać wiele oddziałów, Trzeba wyodrębnić wszystkie metody w klasie zasobów do interfejsu biznesowego, takiego jak

private IDataRetrieve dataRetriever; 
@RequestMapping(method = RequestMethod.POST, value = "/api/{version-var}/getData") 
public @ResponseBody ResponseDataDTO createReleaseFromTemplate(@PathVariable("version-var") Integer version, @RequestBody OperationsDetailsTDO details) { 
    dataRetiever = DataRetrieverFactory.getDataTrieverByVersion(version); //TODO, create a factory to get DataRetriever 
    return dataRetiever.getData(); 
} 

a potem trzeba dwa zaklasyfikowane do wdrożenia IDataRetriver, (jeden dla V1, inny dla V2); przyczyny, aby uniknąć powielenia kodu, możesz dodać klasę abstrakcyjną dla V1 i V2 i użyć szablonu Patern, aby usunąć zduplikowany kod.

+0

+1 Nie lubię tylko przedrostka 'I' dla interfejsów. Klient nie powinien wiedzieć, że używa interfejsu lub implementacji. – Bart

+0

i co z obiektami JSON? są generowane automatycznie zgodnie z odpowiednimi klasami. Czy muszę zduplikować te klasy? – Jonathan

+0

Nie sądzę, że musimy powielić te klasy. ("te klasy" oznaczają klasy wejścia/widoku, prawda?). Tak jak myślałem, v1/v2 będzie zawierał pewną logikę biznesową, zwrot powinien być taki sam. Jeśli v1 nie obsługuje niektórych metod, po prostu wyrzuć wyjątek. – Stony

0

Możesz używać wyrażeń regularnych w mapowaniu zapytań, jeśli używasz zmiennej ścieżki dla wersji (see here for example). Można też utworzyć nową metodę, która po prostu wywoła stary, ale ma nowszą funkcję RequestMapping dla wersji 2. Lub utwórz ogólną metodę, która pobiera wersję i wywołuje właściwą metodę, która faktycznie obsługuje tę wersję żądania. Bonus za ostatnią metodę: możesz pobrać wersję i wysłać użytkownika do określonego błędu, jeśli wysłana wersja nie jest obsługiwana, na przykład jeśli wysyłają/app/v10/cokolwiek innego.

+0

** a) ** Nie ma potrzeby używania wyrażeń regularnych. Dlaczego więc go używać? ** b) ** Duplikowanie kodu w całym miejscu nie będzie zbyt łatwe w zarządzaniu, gdy liczba wersji APi będzie rosnąć. ** c) ** Nie możesz po prostu zrzucić jednej wersji na inną. Klienci używają tych api. – Bart

+0

a) Wyrażenia regularnego można użyć, aby pomóc w dopasowaniu adresu URL żądania. Właśnie o to prosił OP. B) Nikt nie powiedział, żeby powielać kod. Tworzy nowe API, pozostawiając tam stare. To byłby nowy kod, prawda? Nie sądzę, żeby cokolwiek, o czym wspomniałem, wymagałoby i "duplikowanie kodu" c) Nikt nie powiedział, że zrzuci v1.Powiedziałem "możesz użyć wyrażenia regularnego LUB możesz mieć inną metodę dla v2 w kontrolerze LUB możesz zmienić swoją wersję na ścieżkę var, mieć jedną metodę, która następnie przełącza się do właściwej metody bazowej dla żądanej wersji" Przy okazji, – CodeChimp

+0

Wierzę, że to, co zasugerowałem w poprzednim, było podobne do tego, co zasugerował @StonyZhang, czyli użyj wersji jako zmiennej ścieżki, aby określić, którą wersję wywołać. Zakładałem, że OP stosuje standardowe praktyki OOP i MVC, a "warstwa usług" będzie gdzieś tam. – CodeChimp

Powiązane problemy