To dobre i trudne pytanie. Temat projektowania URI jest jednocześnie najważniejszą częścią interfejsu API REST, a zatem potencjalnie długoterminowym zobowiązaniem wobec użytkowników tego interfejsu API .
Ponieważ ewolucja aplikacji i, w mniejszym stopniu, jej API jest faktem i że jest nawet podobna do ewolucji pozornie złożonego produktu, takiego jak język programowania, projekt URI powinien mieć mniej naturalnych ograniczeń i powinien zostać zachowany z czasem . Im dłuższa żywotność aplikacji i interfejsu API, tym większe zaangażowanie użytkowników aplikacji i interfejsu API.
Z drugiej strony, innym faktem jest to, że trudno jest przewidzieć wszystkie zasoby i ich aspekty, które zostałyby zużyte przez API. Na szczęście nie jest konieczne projektowanie całego API, które będzie używane do Apokalipsy . Wystarczy poprawnie zdefiniować wszystkie punkty końcowe zasobu i schemat adresowania każdego zasobu i instancji zasobu.
Z czasem może być konieczne dodanie nowych zasobów i nowych atrybutów do każdego konkretnego zasobu, ale metoda stosowana przez użytkowników API w celu uzyskania dostępu do określonych zasobów nie powinna ulec zmianie, gdy schemat adresowania zasobów stanie się publiczny, a zatem ostateczny.
Ta metoda ma zastosowanie do semantyki czasownika HTTP (np. PUT powinna zawsze aktualizować / zamieniać) i kodów statusu HTTP, które są obsługiwane we wcześniejszych wersjach API (powinny one dalej działać, aby klienci API, którzy pracowali bez interwencji człowieka, mogli kontynuować pracę tak).
Ponadto, ponieważ osadzenie wersji API w URI zakłóciłoby koncepcję hipermediów jako silnika stanu aplikacji (podanego w rozprawie doktorskiej Roy T. Fieldingsa) poprzez posiadanie adresu zasobu / URI, który zmieniałby się z czasem, doszedłbym do wniosku, że API wersje nie powinny być przechowywane w identyfikatorach URI zasobów przez długi czas, co oznacza, że identyfikatory URI zasobów, na których użytkownicy API mogą polegać, powinny być linkami stałymi .
Oczywiście możliwe jest osadzenie wersji interfejsu API w podstawowym identyfikatorze URI, ale tylko do uzasadnionych i ograniczonych zastosowań, takich jak debugowanie klienta interfejsu API, który działa z nową wersją interfejsu API. Takie wersje API powinny być ograniczone czasowo i dostępne tylko dla ograniczonych grup użytkowników API (np. Podczas zamkniętych bet). W przeciwnym razie zobowiązujesz się tam, gdzie nie powinieneś.
Kilka uwag na temat utrzymania wersji API, które mają na nich datę ważności. Wszystkie platformy / języki programowania powszechnie używane do wdrażania usług sieciowych (Java, .NET, PHP, Perl, Rails itp.) Pozwalają na łatwe powiązanie punktów końcowych usługi internetowej z podstawowym identyfikatorem URI. W ten sposób łatwo jest zebrać i zachować zbiór plików / klas / metod oddzielnie dla różnych wersji API .
Z POV użytkowników API łatwiej jest pracować i łączyć się z określoną wersją API, gdy jest to oczywiste, ale tylko przez ograniczony czas, tj. Podczas programowania.
Z POV opiekuna API łatwiej jest utrzymywać równolegle różne wersje API, wykorzystując systemy kontroli źródła, które przeważnie działają na plikach jako najmniejsze jednostki wersji (kodu źródłowego).
Jednak przy wersjach interfejsu API wyraźnie widocznych w URI istnieje zastrzeżenie: można również sprzeciwić się temu podejściu, ponieważ historia interfejsu API staje się widoczna / widoczna w projekcie URI, a zatem jest podatna na zmiany w czasie, co jest niezgodne z wytycznymi REST. Zgadzam się!
Sposobem na obejście tego uzasadnionego sprzeciwu jest zaimplementowanie najnowszej wersji interfejsu API w ramach podstawowego URI interfejsu API bez wersji. W takim przypadku programiści klienta API mogą wybrać:
rozwijać się w stosunku do najnowszej (zobowiązując się do utrzymania aplikacji chroniącej ją przed ewentualnymi zmianami API, które mogą uszkodzić źle zaprojektowanego klienta API ).
powiązać z określoną wersją interfejsu API (która staje się widoczna), ale tylko przez ograniczony czas
Na przykład, jeśli API v3.0 jest najnowszą wersją API, następujące dwa powinny być aliasami (tzn. Zachowywać się identycznie dla wszystkich żądań API):
http: // shonzilla / api / klienci / 1234
http: // shonzilla / api /v3.0 / klienci / 1234
http: // shonzilla / api / v3 / klienci / 1234
Ponadto klienci API, którzy nadal próbują wskazać stary interfejs API, powinni zostać poinformowani o korzystaniu z najnowszej poprzedniej wersji interfejsu API, jeśli używana wersja interfejsu API jest przestarzała lub nie jest już obsługiwana . Dostęp do któregoś z przestarzałych identyfikatorów URI, takich jak te:
http: // shonzilla / api / v2.2 / klienci / 1234
http: // shonzilla / api / v2.0 / klienci / 1234
http: // shonzilla / api / v2 / klienci / 1234
http: // shonzilla / api / v1.1 / klienci / 1234
http: // shonzilla / api / v1 / klienci / 1234
powinien zwrócić dowolny z 30x kodów stanu HTTP wskazujących przekierowanie, które są używane w połączeniu z Location
nagłówkiem HTTP, który przekierowuje do odpowiedniej wersji identyfikatora URI zasobu, który pozostaje tym:
http: // shonzilla / api / klienci / 1234
Istnieją co najmniej dwa kody statusu przekierowania HTTP odpowiednie dla scenariuszy wersjonowania API:
301 Przeniesiono na stałe, wskazując, że zasób z żądanym identyfikatorem URI jest trwale przeniesiony do innego identyfikatora URI (powinien to być bezpośredni link do instancji zasobu, który nie zawiera informacji o wersji interfejsu API). Tego kodu stanu można użyć do wskazania przestarzałej / nieobsługiwanej wersji interfejsu API, informując klienta interfejsu API, że wersjonowany identyfikator URI zasobu został zastąpiony przez bezpośredni link zasobu .
302 Znaleziono wskazujące, że żądany zasób tymczasowo znajduje się w innej lokalizacji, podczas gdy żądany identyfikator URI może być nadal obsługiwany. Ten kod stanu może być przydatny, gdy identyfikatory URI bez wersji są tymczasowo niedostępne i żądanie należy powtórzyć przy użyciu adresu przekierowania (np. Wskazując na identyfikator URI z osadzoną wersją APi) i chcemy poinformować klientów, aby nadal go używali (tj. permalinki).
inne scenariusze można znaleźć w rozdziale Przekierowanie 3xx specyfikacji HTTP 1.1
410 Gone
, ponieważ przekierowanie może oznaczać, że nowa lokalizacja jest kompatybilna, gdy nie jest. Jeśli interfejs API jest po prostu przestarzały, ale nadal istnieje,Warning
opcjonalnym może być nagłówek HTTP odpowiedzi.Adres URL NIE powinien zawierać wersji. Ta wersja nie ma nic wspólnego z „pomysłem” żądanego zasobu. Powinieneś pomyśleć o adresie URL jako ścieżce do koncepcji, którą chcesz - a nie o tym, jak chcesz zwrócić przedmiot. Wersja dyktuje reprezentację obiektu, a nie jego koncepcję. Jak powiedzieli inni plakaty, należy określić format (w tym wersję) w nagłówku żądania.
Jeśli spojrzysz na pełne żądanie HTTP dla adresów URL, które mają wersje, wygląda to tak:
Nagłówek zawiera wiersz zawierający reprezentację, o którą prosisz („Accept: application / xml”). Właśnie tam powinna iść wersja. Wydaje się, że wszyscy zastanawiają się nad tym, że możesz chcieć tego samego w różnych formatach i że klient powinien móc zapytać o to, czego chce. W powyższym przykładzie klient prosi o JAKĄKOLWIEK reprezentację zasobu XML - nie jest to prawdziwa reprezentacja tego, czego chce. Serwer teoretycznie mógłby zwrócić coś całkowicie niezwiązanego z żądaniem, o ile był to XML, i musiałby zostać przeanalizowany, aby zdać sobie sprawę, że jest on błędny.
Lepszym sposobem jest:
Ponadto, powiedzmy, że klienci uważają, że XML jest zbyt szczegółowy i teraz zamiast tego chcą JSON. W innych przykładach musiałbyś mieć nowy adres URL dla tego samego klienta, aby uzyskać:
(lub coś podobnego). Gdy w rzeczywistości każde żądanie HTTP zawiera poszukiwany format:
Korzystając z tej metody, masz dużo więcej swobody w projektowaniu i faktycznie przestrzegasz oryginalnej idei REST. Możesz zmieniać wersje bez zakłócania działania klientów lub stopniowo zmieniać klientów wraz ze zmianą interfejsów API. Jeśli zdecydujesz się przestać obsługiwać reprezentację, możesz odpowiedzieć na żądania za pomocą kodu stanu HTTP lub kodów niestandardowych. Klient może również sprawdzić, czy odpowiedź ma poprawny format i zweryfikować XML.
Istnieje wiele innych zalet i niektóre z nich omawiam tutaj na moim blogu: http://thereisnorightway.blogspot.com/2011/02/versioning-and-types-in-resthttp-api.html
Ostatni przykład pokazujący, jak złe jest umieszczanie wersji w adresie URL. Powiedzmy, że chcesz mieć jakieś informacje wewnątrz obiektu i masz wersje różnych obiektów (klienci mają v3.0, zamówienia to v2.0, a obiekt shipto to v4.2). Oto nieprzyjemny adres URL, który musisz podać w kliencie:
źródło
-x
ponieważ jest przestarzały przez RFC6648 .Uznaliśmy, że praktyczne i przydatne jest umieszczenie wersji w adresie URL. Łatwo jest na pierwszy rzut oka stwierdzić, z czego korzystasz. Wykonujemy aliasy / foo do / foo / (najnowsze wersje) w celu ułatwienia użytkowania, krótszych / czystszych adresów URL itp., Zgodnie z sugerowaną odpowiedzią.
Utrzymanie wstecznej kompatybilności na zawsze jest często kosztowne i / lub bardzo trudne. Wolimy powiadomić z wyprzedzeniem o wycofaniu, przekierowaniach takich jak sugerowane tutaj, dokumentach i innych mechanizmach.
źródło
Zgadzam się, że wersjonowanie reprezentacji zasobów lepiej odpowiada podejściu REST ... ale jednym dużym problemem z niestandardowymi typami MIME (lub typami MIME, które dołączają parametr wersji) jest słaba obsługa zapisu w nagłówkach Accept i Content-Type w HTML i JavaScript.
Na przykład nie jest możliwe, aby IMO POST używał następujących nagłówków w formularzach HTML5, aby utworzyć zasób:
To dlatego, że HTML5
enctype
atrybut stanowi wyliczenie, więc coś innego niż zwykleapplication/x-www-formurlencoded
,multipart/form-data
itext/plain
są nieważne.... i nie jestem pewien, czy jest obsługiwany we wszystkich przeglądarkach w HTML4 (który ma bardziej luźny atrybut encytpe, ale byłby problem z implementacją przeglądarki, czy typ MIME został przekazany)
Z tego powodu uważam, że najbardziej odpowiednią drogą do wersji jest URI, ale akceptuję, że nie jest to „poprawny” sposób.
źródło
Umieść swoją wersję w URI. Jedna wersja interfejsu API nie zawsze obsługuje typy z innej, więc argument, że zasoby są migrowane tylko z jednej wersji do drugiej, jest po prostu błędny. To nie to samo, co zmiana formatu z XML na JSON. Typy mogą nie istnieć lub mogły ulec zmianie semantycznej.
Wersje są częścią adresu zasobu. Trasujesz z jednego interfejsu API do drugiego. Ukrywanie adresowania w nagłówku nie jest RESTful.
źródło
Istnieje kilka miejsc, w których można przeprowadzić kontrolę wersji w interfejsie API REST:
Jak wspomniano, w URI. Może to być łatwe do wykonania, a nawet estetyczne, jeśli przekierowania i tym podobne są dobrze stosowane.
W nagłówku Accepts:, więc wersja ma typ pliku. Jak „mp3” vs „mp4”. To również zadziała, chociaż IMO działa nieco mniej ładnie niż ...
W samym zasobie. Wiele formatów plików ma osadzone numery wersji, zwykle w nagłówku; pozwala to nowszemu oprogramowaniu „po prostu działać”, rozumiejąc wszystkie istniejące wersje typu pliku, podczas gdy starsze oprogramowanie może działać, jeśli określona jest nieobsługiwana (nowsza) wersja. W kontekście interfejsu API REST oznacza to, że Twoje identyfikatory URI nigdy nie muszą się zmieniać, a jedynie twoja odpowiedź na konkretną wersję przekazanych danych.
Widzę powody, dla których warto zastosować wszystkie trzy podejścia:
źródło
Wersjonowanie interfejsu API REST jest analogiczne do wersjonowania dowolnego innego interfejsu API. Drobne zmiany można wprowadzić na miejscu, poważne zmiany mogą wymagać zupełnie nowego interfejsu API. Najłatwiej jest zaczynać od zera za każdym razem, czyli wtedy, gdy umieszczenie wersji w adresie URL ma sens. Jeśli chcesz ułatwić życie klientowi, staraj się zachować kompatybilność wsteczną, co możesz zrobić z wycofaniem (trwałe przekierowanie), zasobami w kilku wersjach itp. Jest to bardziej kłopotliwe i wymaga większego wysiłku. Ale właśnie to zachęca REST w „Fajne identyfikatory URI się nie zmieniają”.
Ostatecznie jest tak jak każdy inny projekt API. Porównaj wysiłek z wygodą klienta. Rozważ zastosowanie wersji semantycznej dla swojego interfejsu API, co wyjaśni klientom, w jaki sposób nowa wersja jest kompatybilna wstecz.
źródło