Jakiś czas temu miałem przyjemność napisać artykuł dotyczący API. Warto zaznaczyć, że sposobów na wymianę danych z nim jest kilka. Aby jedna aplikacja (klient) mogła połączyć się z serwerem pełniącym rolę API, potrzebny jest pewien format, który obie strony komunikacji będą potrafiły zrozumieć i przetworzyć. Jednym z nich jest właśnie REST (ang. Representational State Transfer). 🧐
Do czego ten REST?
W internecie jest ogromna ilość usług, które wymieniają między sobą dane. Załóżmy, że każdy z nich posługuje się własnymi zasadami wymiany i dostępu do informacji. Bez ustalonych reguł, integracja takich systemów byłaby bardzo trudna w realizacji i utrzymaniu. Dlatego właśnie zostały utworzone rozwiązania, które tworzą pewne standardy.
REST zyskał ogromną popularność m.in. dzięki swojej prostocie, szybkości i uniwersalności, a jego implementacja jest możliwa w wielu językach programowania. Dzięki temu, systemy wymieniające się między sobą informacjami, nie muszą być realizowane w tej samej technologii, gdyż cała magia kryje się w formacie danych! REST doczekał się wielu bibliotek zarówno po stronie frontendu jak i backendu, które znacznie przyspieszają prace nad aplikacjami.
Warto pamiętać, że REST to nie synonim dla HTTP! HTTP to protokół komunikacji, a REST jest rozwiązaniem architektonicznym, które z owego protokołu korzysta.
Jakie są ogólne reguły w RESTful?
Żeby aplikacje RESTowe były spójne, a implementacja komunikacji między nimi łatwiejsza, zostały przyjęte reguły, których spełnienie nadaje aplikacji miano RESTful. Niestety… nie jest to ścisły i oficjalny standard, a jedynie zbiór reguł, którego można się trzymać lub nie. O jakich zasadach mowa? 🤓
1. Jednolity interfejs komunikacyjny (ang. Uniform Interface)
Serwer powinien udostępniać API, które będzie rozumiane przez wszystkie aplikacje komunikujące się z nim. Zwracane dane powinny mieć ten sam format i zakres danych, a dobrze zaprojektowany interfejs powinien zaspokoić potrzeby wielu urządzeń i aplikacji.
2. Podział na aplikacje klient-serwer (ang. client-server)
Rozdzielenie aplikacji pozwala na ich niezależny rozwój i działanie. Taki podział zdecydowanie zwiększa możliwości skalowania, przenośności i rozszerzalność, a obsługa błędów jest znacznie łatwiejsza. Takie podejście zdecydowanie ułatwia realizację punktu numer 1. Rozdzielenie aplikacji na warstwy klient-serwer, ułatwi w przyszłości integrację z innymi usługami klienckimi.
O wiele sprawniej zostanie przeprowadzona instalacja aplikacji WWW, która bazuje na HTML wraz z JS i która łączy się z niezależnym API, niż konfigurowanie całej aplikacji, będącej monolitem zbudowanym z frontendu oraz backendu.
3. Bezstanowość (ang. Stateless)
Po stronie serwera nie powinno być mechanizmów przetrzymujących dane klienta, które byłyby potrzebne do poprawnego działania systemu. API nie powinno trzymać stanu aplikacji, a jedynie interpretować informacje przesłane przez klienta i na tej podstawie funkcjonować. Klient zawsze powinien przesyłać komplet informacji potrzebnych do poprawnego wykonania żądania (request).
Reguła ta jest mocno powiązana z sesją użytkownika, która często realizowana jest po stronie serwera. To dzięki niej weryfikuje się, czy użytkownik ma dostęp do systemu i jakie ma uprawnienia. W przypadku RESTful API, każdy request, który trafia do serwera powinien zawierać w swoich nagłówkach specjalny token, np. JWT. To na jego podstawie API może decydować, czy request powinien być przetworzony czy odrzucony.
4. Cache danych (ang. Cacheability)
Przez to, że API może obsługiwać bardzo duży ruch, stosuje się „triki”, które zmniejszają obciążenie sieciowe i sprzętowe. Jednym ze sposobów jest wykorzystanie mechanizmu przeglądarek lokalnie „zapamiętujących” odpowiedzi serwera, które bazują na metodach GET oraz POST. Do tego celu wykorzystuje się specjalne nagłówki HTTP, które definiują czy response ma być zapamiętany, a jeżeli tak to kiedy powinien zostać odświeżony lub usunięty.
- Expires – data wygaśnięcia danych. Kiedy termin upłynie, zasób musi zostać pobrany z serwera i może być ponownie zapamiętany.
- Cache-Control – definiuje czy zasób powinien być zapamiętany oraz na jak długo.
- ETag – unikalny identyfikator / token, bezpośrednio powiązany z zapamiętanym zasobem. Zmienia się w momencie aktualizacji wartości.
- Last-Modified – określa, kiedy zasób został zaktualizowany / zmodyfikowany.
Kolejnym rozwiązaniem jaki można zastosować jest Redis lub Memcached, które pozwalają cache’ować całe odpowiedzi serwera dla konkretnych żądań.
Request przychodzi do cache serwera, który sprawdza czy posiada dane dla tego żądania. Jeżeli tak, to pobiera je i zwraca do klienta. W takim scenariuszu pomijane jest pobieranie zasobów z API, co automatycznie odciąża go w wielu aspektach.
5. Odseparowane warstwy (ang. Layered system)
Komunikacja i wymiana danych między aplikacjami klienckimi, a API nie powinna być obciążona informacjami o zewnętrznych serwisach i usługach, z których serwer korzysta. Pozwala to zachować transparentność i separację logiki od warstwy WWW.
6. Wysyłanie kodu do aplikacji klienta (ang. Code on demand)
API może wysyłać gotowe fragmenty kodu do aplikacji klienckich w celu ich przetworzenia i uruchomienia (np. skrypty JS). Ta reguła jako jedyna z całej szóstki jest opcjonalna.
Co ja bym dodał do REST API?
Powyższe punkty niewątpliwie są istotne, lecz dotyczą głównie kwestii związanych z architekturą. Warto zwrócić też uwagę na inne aspekty. 🤔
1. Wersjonowanie
Przydaje się w sytuacji kiedy konieczne jest dokonanie modyfikacji w interfejsach służących do wymiany danych. W takiej sytuacji bardzo trzeba uważać na zachowanie kompatybilności ze wszystkimi usługami komunikującymi się z API.
Dlaczego? Klient może przestać rozumieć odpowiedzi z API, a API może przestać rozumieć wysyłane do niego dane. O ile łatwo nad tym zapanować kiedy z API korzysta jeden klient, to w przypadku wielu usług klienckich może zrobić się bałagan. Najpopularniejsze sposoby na wersjonowanie:
- Przez ścieżkę URI:
https://zaprogramujzycie.pl/api/v1/dogs
- Przez parametr URI:
https://zaprogramujzycie.pl/api/dogs?v=1
- Accept header:
Accept: application/vnd.zaprogramujzycie.v1+json
- Custom header (poza standardem HTTP):
Accept-version: v1
2. Dokumentacja
Dobrze by było, aby API posiadało przygotowaną dokumentację, w której zawarte są informacje o wszystkich URI, przykładowych requestach i odpowiedziach z serwera. Na szczęście nie trzeba jej robić ręcznie! W większości języków programowania dostępne są specjalne biblioteki (np. SwaggerUI), które na podstawie endpointów zdefiniowanych w kodzie aplikacji, potrafią wygenerować odpowiedni plik z dokumentacją.
3. Rzeczowniki, nie czasowniki!
Możliwości i opcji jak zbudować URI jest wiele, dlatego warto zwracać na to szczególną uwagę aby utrzymać porządek i przejrzystość. Jak można zauważyć, użycie rzeczownika znacznie skraca listę kombinacji, co w rezultacie bardzo ułatwia prace z API.
Rzeczowniki ✅
GET /dogs
POST /dogs
PUT /dogs/{id}
DELETE /dogs/{id}
Czasowniki ❌
POST /add/dogs
POST /create/dogs
POST /addDogs
DELETE /delete/dogs/{id}
DELETE /deleteDogs/{id}
DELETE /delete-dogs/{id}
DELETE /dogs/{id}/delete
4. Liczba mnoga dla zbiorów
Odpowiednie sterowanie liczbą mnogą może być bardzo wartościowe, gdyż w rezultacie umożliwia szybkie zdefiniowanie, który zasób jest kolekcją, a który pojedynczym elementem.
Liczba mnoga ✅
GET /cats
POST /cats
PUT /cats/{id}
DELETE /cats/{id}
Liczba pojedyncza ❌
GET /cat
POST /cat
PUT /cat/{id}
DELETE /cat/{id}
Podsumowanie
Podsumowując, czym jest REST?
- Przede wszystkim jednym z kilku sposobów na komunikację między urządzeniami i usługami sieciowymi.
- Nie posiada swojej oficjalnej specyfikacji. Ma jedynie zbiór zasad, które mają na celu ułatwienie i uspójnienie procesu wymiany danych.
- Z pewnością, w większości przypadków bazuje na formacie JSON, a zdecydowanie rzadziej jest to XML.
- Ma na celu rozdzielenie aplikacji, co jest zalążkiem architektury mikroserwisowej.
- Nie każda aplikacja bazująca na REST jest RESTful!
- REST to nie HTTP!
- REST API to serwer, który komunikuje się z innymi usługami wykorzystując styl architektoniczny REST.
Na koniec warto zaznaczyć, że REST nie jest jedyną formą wymiany danych między systemami. Myślę jednak, że jest to materiał na osobny artykuł, który niebawem postaram się przygotować.
Daj lajka i czytaj dalej 😉
Jesteś ciekawy jak wygląda pierwszy dzień pracy programisty? Z pewnością zainteresuje Cię poniższy film mojego autorstwa 🧐
Jeżeli chcesz być na bieżąco z artykułami i jesteś ciekawy co będzie dalej, daj lajka na naszym profilu FB, a przede wszystkim zapisz się do newslettera! Spodobał Ci się artykuł? Z pewnością zaciekawią Cię inne wpisy na naszym blogu lub filmy na kanale YT!
Dzięki za Twój czas, widzimy się niebawem! 😉