REST API - odstępstwa od zasad
Grudzień 17, 2023 | #rest-api
010100
001100
101110
O REST API
REST API (Representational State Transfer API) to styl architektury oprogramowania używany do tworzenia interfejsów aplikacji internetowych. Jest chętnie wybierany przez programistów i firmy budujące wszelkiego rodzaju usługi internetowe. Jego popularność wynika z prostoty, elastyczności i kompatybilności z szerokim zakresem technologii. REST API jest powszechnie stosowane w różnych branżach i projektach, od małych aplikacji po duże systemy korporacyjne, a jego zastosowanie obejmuje aplikacje mobilne, usługi internetowe, integracje systemów i wiele innych. Możliwość łatwej integracji z HTTP i wsparcie dla różnych formatów danych, takich jak JSON i XML, czyni go atrakcyjnym wyborem dla developerów.
Standard REST API?
REST API nie jest zdefiniowany przez jedną konkretną specyfikację lub dokument, który moglibyśmy uznać za dominujący standardowy zbiór wytycznych. Podstawowym dokumentem, który wprowadził i opisał REST, jest rozprawa doktorska Roya Fieldinga z 2000 roku, zatytułowana "Architectural Styles and the Design of Network-based Software Architectures". W tej pracy, Fielding, współtwórca protokołu HTTP, szczegółowo opisuje zasady REST jako stylu architektonicznego dla budowania rozproszonych systemów.
Istnieje wiele przewodników i najlepszych praktyk opracowanych przez społeczności i organizacje, które opisują, jak projektować i implementować REST API. Te źródła nie są oficjalnymi standardami, ale dostarczają cennych wskazówek i konwencji. Przykładami mogą być "Best Practices for Designing a Pragmatic RESTful API" od Vinay Sahni, wytyczne Belgijskiej Ramy Interoperacyjności - czyli inicjatywy mającej na celu poprawę kompatybilności między usługami RESTful oferowanymi przez instytucje rządowe Belgi, czy różne przewodniki dostępne od firm technologicznych jak Microsoft oraz Google. Przy okazji zachęcam do przeczytania artykułu mojego autorstwa o modelu dojrzałości REST API Richardsona.
Nie sposób w tym miejscu nie wspomnieć także o OpenAPI, znanym również jako Swagger. Ta specyfikacja używana do opisu interfejsów API REST umożliwia zarówno projektowanie, jak i dokumentowanie interfejsów API w formacie, który jest zarówno zrozumiały dla człowieka, jak i maszynowo przetwarzalny. Specyfikacja OpenAPI jest używana do tworzenia dokładnej dokumentacji dla interfejsów API, w tym dostępnych punktów końcowych, operacji, parametrów i formatów odpowiedzi. Jest to również narzędzie wspierające automatyzację w procesie tworzenia oprogramowania, np. w generowaniu kodu klienckiego, serwerowego i dokumentacji API. OpenAPI stało się standardem branżowym w projektowaniu nowoczesnych interfejsów API i jest zintegrowane z wieloma popularnymi frameworkami czy narzędziami programistycznymi jak choćby FastAPI, czy Spring Boot.
Podsumowując, REST jako styl architektoniczny jest bardziej zbiorem zasad i wytycznych niż sztywno zdefiniowanym standardem nie mniej rozmaite dokumenty i przewodniki dostarczają wskazówek, jak te zasady można wdrażać w praktyce.
Tworząc REST API podążaj za wytycznymi
Choć ten artykuł jest o odstępstwach od reguł, zanim do tego przejdziemy warto krótko wspomnieć dlaczego warto przestrzegać zasad i wypracowanych dobrych praktyk.
Przestrzeganie zasad programowania nie zawsze oznacza tworzenie lepszego kodu, ale zwykle oznacza tworzenie bardziej przewidywalnego kodu.
~ Martin Fowler
Zwiększona czytelność i łatwości użytkowania: Powszechnie stosowane praktyki pomagają w utrzymaniu spójności i czytelności interfejsu API, co ułatwia jego zrozumienie i używanie przez innych programistów. Nowi programiści szybciej się wdrażają jeśli nie napotykają na swojej drodze niestandardowych rozwiązań.
Łatwiejsza integracja i rozszerzalność: Przestrzeganie standardów ułatwia integrację z innymi systemami i serwisami, a także umożliwia łatwiejsze rozszerzanie API w przyszłości. Po standardowym API deweloper może poruszać się niemal bez dokumentacji - nawet jak nie jest jego twórcą.
Poprawa skalowalności: Dobre praktyki, takie jak bezstanowość i wydajne wykorzystanie zasobów, pomagają w skalowaniu aplikacji.
Zapewnione bezpieczeństwo: Stosowanie się do najlepszych praktyk w zakresie bezpieczeństwa minimalizuje ryzyko podatności i ataków. Czasem niestandardowe rozwiązania mogą zaskoczyć atakującego ale jeśli zostały zaprojektowane przez osoby nie znające tematu mogą zostać szybko rozpracowane.
Ułatwione testowanie i konserwacja: API zaprojektowane według standardowych zasad jest łatwiejsze do testowania i utrzymania.
Nieidealna architektura REST API
Mimo swojej popularności i szerokiego zastosowania REST API, ma pewne wady i ograniczenia, które w miarę rozwoju projektu zaczynają coraz bardziej doskwierać.
Rozbudowane zapytania przy złożonych strukturach danych
REST może być niewydajny w sytuacjach, gdy aplikacja klienta potrzebuje złożonego zestawu danych, które muszą być pobrane z wielu różnych punktów końcowych. Może to prowadzić do problemu zwanego "over-fetching" (pobieranie nadmiarowych danych) lub "under-fetching" (konieczność wykonania wielu zapytań, aby uzyskać komplet danych).
Wcześniejsze wersje Graph API Facebooka odstępowały od niektórych zasad REST, szczególnie w zakresie jednolitego interfejsu i HATEOAS (Hypermedia As The Engine Of Application State). Facebook zdecydował się na bardziej elastyczne podejście, które lepiej służyło ich specyficznym wymaganiom dotyczącym obsługi ogromnej ilości danych i złożonych relacji między nimi. Ostatecznie, wprowadzili GraphQL, który jeszcze bardziej odbiega od konwencjonalnego REST i dzisiaj uznawany jest za odrębną architekturę.
Sztywność struktury danych (Rigidity in data structure)
REST API zazwyczaj wymusza ściśle określoną strukturę odpowiedzi, co może być ograniczające, gdy konsumenci API potrzebują większej elastyczności w dostępie do danych. Wymusza to przekształcenia zestawu danych po stronie konsumentów co może okazać się operacją nadmiarową i kosztowną jeśli weźmiemy pod uwagę, że klientami API często są aplikacje mobilne albo strony WWW uruchamiane w przeglądarkach.
Twitter obecnie X, w różnych wersjach swojego API, wprowadzał zmiany, które czasami odchodziły od standardowych praktyk REST, na przykład w zakresie limitów zapytań, buforowania i formatowania odpowiedzi. Celem tych zmian była optymalizacja wydajności i lepsze zarządzanie ruchem sieciowym.
Sztywność struktury może dać się we znaki także w przypadku konstruowania zapytań do API, czego najlepszym przykładem jest historia Elasticsearch API. Elasticsearch początkowo wykorzystywał REST API, ale w praktyce wprowadził pewne niestandardowe rozwiązania, takie jak użycie ciała żądania w zapytaniach GET, co nie jest typowe dla REST. Zrobili to, aby ułatwić przesyłanie skomplikowanych zapytań.
Bezstanowość (Statelessness)
Chociaż bezstanowość jest jedną z zasad REST i przyczynia się do prostoty i skalowalności tej architektury, może być również ograniczeniem funkcjonalność, szczególnie w aplikacjach, które wymagają zachowania stanu sesji.
Programiści wypracowali wiele metod radzenia sobie z zachowywaniem stanu poprzez przesyłanie identyfikatora sesji za pośrednictwem tokenu sesji, ciasteczka, tokenu JWT, lub parametrów Query i Body Request. Niektórzy decydują się także na utrzymywanie stanu po stronie klienta. Każda z tych metod ma swoje zalety i ograniczenia, a wybór odpowiedniej zależy od wymagań specyficznych dla aplikacji i kontekstu bezpieczeństwa.
Wziąwszy jednak pod uwagę że klienci API mogą być liczni i różnorodni pod względem zastosowanej technologi, oraz to że mogą być wdrażani przez podmioty zewnętrzne, niekiedy dużo korzystniejsze wydawałoby się zaimplementowanie pamięci stanu po stronie backendu, po to aby implementację klienta uczynić możliwie najprostszą i najmniej podatną na błędy.
Zależność od protokołu HTTP - wydajność i opóźnienia
REST API w swym pierwotnym założeniu opiera się na protokole HTTP, który może wprowadzać dodatkowe opóźnienia związane z nawiązywaniem połączenia, szczególnie w przypadku dużego obciążenia sieciowego lub wielu zapytań do API.
W serwisach wymagających możliwie natychmiastowej synchronizacji danych, zwłaszcza kiedy mówimy o ruchu w obie strony tzn. nie tylko klient odpytuje serwer o aktualny stan rzeczy ale także backend chce zaktualizować dane na wszystkich swoich klientach, protoków HTTP zawodzi. W takich wypadkach do obsługi standardowych operacji CRUD (Create, Read, Update, Delete) wykorzystuje się REST API a w części aplikacji wymagającej interakcji w czasie rzeczywistym dobrze sprawdza się WebSocket, który zapewnia pełnodupleksowy kanał komunikacji pozwalający na ciągłą wymianę danych między klientem a serwerem. Świetnie sprawdza się to w grach, chatach, aplikacjach giełdowych czy systemach rezerwacji miejsc i biletów.
Trudności z obsługą dużych i strumieniowych danych
REST może nie być najlepszym wyborem dla aplikacji wymagających efektywnego przesyłania dużych ilości danych lub danych strumieniowych, np. w usługach transmisji wideo.
Netflix, w procesie ewolucji swojego API, zdecydował się na odejście od modelu REST w kierunku bardziej specyficznych dla urządzeń interfejsów API. Zrobili to, aby lepiej obsłużyć różnorodne urządzenia klientów, które wymagały różnych formatów danych i poziomów wydajności. Ta decyzja została podjęta, aby zwiększyć wydajność i zredukować obciążenie sieciowe.
Zabezpieczenia
Chociaż nie jest to wada wyłączna dla REST, implementacja bezpiecznych REST API wymaga starannej uwagi do zabezpieczeń, takich jak autoryzacja, uwierzytelnianie i szyfrowanie.
Dlatego funkcjonalność taka jak "login", które w przypadku API REST sprowadza się do pobrania tokena autoryzacyjnego, takiego jak JWT (JSON Web Token), jest realizowane za pomocą metody POST. Używa się POST, ponieważ żądanie często wymaga przesłania poufnych danych, takich jak nazwa użytkownika i hasło, a metoda POST pozwala na przesłanie tych danych w ciele (body) żądania, co jest bezpieczniejsze niż przesyłanie ich w URL (jak w przypadku GET). Odpowiedź serwera na takie żądanie zwykle zawiera token JWT, który następnie jest używany do autoryzacji kolejnych żądań.
Czasem warto łamać reguły
REST API nie ma sztywnej specyfikacji a jest jedynie zbiorem dobrych praktyk wypracowanych i wciąż doprecyzowywanych. Zbiór reguł ułatwia implementację w sposób powszechnie uznawany za poprawną, a tym samą łatwiejszą do rozbudowy, utrzymania i kompatybilną z innymi API. Niestety pomimo wielu zalet, które decydują o wyborze tej architektury jako dominującej w projekcie, nie pokrywa ona wszystkich przypadków użycia i często nakłada na developerów ograniczenia mogące z czasem przybierać na wadze.
Niektóre fimy, czy instytucje decydują się na zmianę dominującej architektury API, ale nie są one przedmiotem tego artykułu. Inne tak dalece odchodzą od pierwotnych zasad, że defacto wypracowują całkiem nowe rozwiązanie. Potwierdzają one słowa Bjarne Stroustrup-a i mogą być inspiracją dla każdego purysty bojącego się przekroczyć linię.
Zasady i praktyki są ważne, ale dopiero łamanie ich prowadzi do prawdziwej innowacji w programowaniu.
~ Bjarne Stroustrup
Natomiast najczęściej wystarczą małe odstępstwa od dobrych praktyk adaptujace API do bierzących potrzeb czego dobrym przykładem jest Amazon Web Services (AWS) API. Niektóre usługi AWS, takie jak Simple Storage Service (S3), nie przestrzegają ściśle zasad REST, zwłaszcza w kwestii jednolitego interfejsu i użycia metod HTTP. Na przykład, AWS S3 używa niestandardowych nagłówków HTTP dla niektórych operacji, co odbiega od typowego użycia metod HTTP w REST.
Chociaż przestrzeganie dobrych praktyk w projektowaniu API REST jest zalecane, istnieją sytuacje, w których odstępstwa od tych wytycznych mogą być uzasadnione lub konieczne. Oto kilka przykładów, kiedy odstąpienie od najlepszych praktyk może być rozważane:
Wymagania legacy lub wsteczna kompatybilność
W przypadku integracji z istniejącymi starszymi systemami (legacy), które nie przestrzegają zasad REST, może być konieczne dostosowanie nowego API do tych systemów, aby zapewnić interoperacyjność.
Przeczytaj o bankowości opartej na SMS dla transakcji kiedy bank napotkał trudności w obsłudze klientów korzystających głównie z prostych telefonów komórkowych. Aby się dostosować, rozwinął system API, gdzie proste telefony mogły komunikować się z bankiem za pomocą SMS-ów, inicjując serię wewnętrznych wywołań API do przetwarzania transakcji.
Specyficzne ograniczenia biznesowe lub techniczne
Czasami unikalne wymagania biznesowe lub ograniczenia techniczne mogą wymagać niestandardowego podejścia do projektowania API, które niekoniecznie pasuje do modelu REST. W niektórych przypadkach, ograniczenia infrastrukturalne, takie jak brak wsparcia dla pewnych metod HTTP przez serwery pośredniczące, mogą wymusić odstępstwa od standardowych metod REST.
Wysoka wydajność i optymalizacja
W bardzo wymagających scenariuszach, gdzie wydajność jest kluczowym priorytetem (na przykład w systemach czasu rzeczywistego), niektóre z zasad REST, takie jak bezstanowość lub jednolity interfejs, mogą być mniej skuteczne i mogą wymagać optymalizacji.
Przeczytaj jak firma kart kredytowych zwiększyła szybkość transakcji. Główna amerykańska firma kart kredytowych potrzebowała przetwarzać miliardy wywołań API z latencją poniżej 70 ms. Ich istniejące rozwiązanie zarządzania API dodawało znaczną latencję.
Złożoność odpowiedzi
REST zaleca, aby każdy zasób miał swój własny unikatowy URI. Jednak w praktyce, szczególnie w przypadku złożonych aplikacji, czasami jest bardziej wydajne łączenie danych z wielu zasobów w jednym zapytaniu, aby zredukować ilość wywołań sieciowych.
Wymogi bezpieczeństwa
Niektóre środowiska mogą wymagać specyficznych schematów uwierzytelniania lub autoryzacji, które nie są typowe dla standardowego podejścia REST.
Integracja z nietypowymi klientami
W przypadku, gdy klienci API mają specyficzne wymagania lub ograniczenia (na przykład ograniczone urządzenia IoT), może być konieczne dostosowanie interfejsu API do tych specyfikacji.
Ewolucja technologii
W miarę jak technologie sieciowe się rozwijają, niektóre z założeń REST mogą stać się mniej odpowiednie. Na przykład, rozwój technologii WebSockets prowadzi do większego zainteresowania dwukierunkową, trwałą komunikacją, co stoi w pewnym opozycji do bezstanowego modelu REST.
W każdym z tych przypadków ważne jest, aby dokładnie rozważyć konsekwencje odstąpienia od standardowych praktyk i szukać równowagi między przestrzeganiem zasad REST a spełnieniem specyficznych wymagań projektu. Warto też pamiętać, że odstępstwa od tych zasad mogą wpłynąć na przyszłą skalowalność, utrzymanie i rozszerzalność API. Dlatego łamanie reguł nie może wynikać z braku wiedzy, ale z dobrze zbilansowanej, świadomej wad i korzyści z tego płynących decyzji.