Usługi RESTful
Architektura Representational State Transfer i zasady projektowania API.
Wprowadzenie: Od Stron Internetowych do Usług Sieciowych
Na początku swego istnienia, sieć internetowa była przede wszystkim zbiorem połączonych hiperłączami dokumentów, przeznaczonych do konsumpcji przez ludzi. Przeglądarka (klient) żądała strony internetowej od serwera, a serwer odpowiadał kompletnym dokumentem HTML, stylizowanym za pomocą CSS i wzbogaconym o JavaScript, wszystko to miało na celu wyrenderowanie na ekranie treści dla człowieka do przeczytania. Chociaż ten model napędza wizualną sieć, którą przeglądamy każdego dnia, w tle istnieje inna, równie ważna sieć: sieć dla aplikacji.
Nowoczesne aplikacje rzadko są monolityczne. Twoja mobilna aplikacja bankowa, urządzenie inteligentnego domu, tablica w mediach społecznościowych. Te aplikacje nieustannie muszą komunikować się z serwerami, aby pobierać dane, przesyłać aktualizacje i wykonywać działania. Nie są one zainteresowane otrzymywaniem w pełni sformatowanej strony HTML. Zamiast tego potrzebują ustrukturyzowanego, przewidywalnego sposobu na wymianę surowych danych. Ta programistyczna interakcja między różnymi aplikacjami za pośrednictwem sieci jest możliwa dzięki , czyli Interfejsowi Programowania Aplikacji.
Na przestrzeni lat pojawiło się wiele stylów budowy tych sieciowych API, takich jak SOAP i RPC. Jednak jeden styl architektoniczny stał się de facto standardem budowy nowoczesnych usług sieciowych ze względu na swoją prostotę, skalowalność i zgodność z zasadami samej sieci: REST.
Czym Jest REST? Styl Architektoniczny, a nie Protokół
Kluczowe jest zrozumienie, że , czyli Representational State Transfer, nie jest protokołem, standardem ani konkretną technologią. Nie można „zainstalować” REST. Zamiast tego jest to styl architektoniczny, zbiór wytycznych lub ograniczeń dotyczących projektowania aplikacji sieciowych. Został zdefiniowany przez Roya Fieldinga w jego rozprawie doktorskiej w 2000 roku. Fielding był jednym z głównych autorów specyfikacji HTTP, a styl REST w zasadzie destyluje zasady architektoniczne, które uczyniły World Wide Web tak udanym i skalowalnym.
API lub usługa internetowa, która przestrzega ograniczeń REST, nazywana jest API RESTful. API RESTful wykorzystują istniejące funkcje protokołu HTTP do ułatwienia komunikacji. Zamiast wymyślać nowe mechanizmy, REST wykorzystuje moc adresów URL do identyfikacji zasobów i metod HTTP (GET, POST, PUT, DELETE) do definiowania działań na tych zasobach. To sprawia, że usługi RESTful są intuicyjne i łatwe w użyciu dla każdego, kto zna zasady działania sieci.
Sześć Wytycznych Ograniczających REST
Aby API było prawdziwie RESTful, musi przestrzegać sześciu konkretnych ograniczeń architektonicznych. Te ograniczenia współdziałają, tworząc system, który jest prosty, skalowalny i niezawodny.
- 1. Architektura Klient-Serwer
- REST nakazuje ścisłe rozdzielenie odpowiedzialności między klientem a serwerem. Klient jest odpowiedzialny za interfejs użytkownika i doświadczenia użytkownika, podczas gdy serwer odpowiada za przechowywanie danych, logikę biznesową i bezpieczeństwo. Są one niezależne i mogą ewoluować oddzielnie. Serwer może być aktualizowany bez wpływu na klienta, a nowa aplikacja kliencka może być tworzona na inną platformę (np. nowa aplikacja mobilna), o ile mówi tym samym językiem API.
- 2. Bezstanowość (Stateless)
- Jest to być może najbardziej fundamentalne ograniczenie. W architekturze RESTful cała komunikacja od klienta do serwera musi zawierać wszystkie informacje niezbędne serwerowi do zrozumienia i przetworzenia żądania. Serwer nie może przechowywać żadnego kontekstu klienta ani stanu sesji między żądaniami. Każde żądanie jest traktowane jako nowa, niezależna transakcja. Jeśli wymagane jest uwierzytelnienie, klient musi przesyłać swoje poświadczenia przy każdym pojedynczym żądaniu. Ta bezstanowość znacznie poprawia skalowalność, ponieważ każdy serwer może obsłużyć żądanie dowolnego klienta, co upraszcza projekt serwera i ułatwia dodawanie kolejnych serwerów w celu obsługi obciążenia.
- 3. Buforowalność (Cacheable)
- Odpowiedzi z API RESTful muszą jawnie oznaczać się jako buforowalne lub niebuforowalne. Gdy odpowiedź jest oznaczona jako buforowalna, klient może ponownie wykorzystać te dane do równoważnych kolejnych żądań przez pewien czas. Poprawia to wydajność i efektywność, zmniejszając liczbę żądań, które muszą dotrzeć do serwera. Buforowanie jest zazwyczaj kontrolowane za pomocą nagłówków HTTP, takich jak
Cache-Control. - 4. Jednolity Interfejs (Uniform Interface)
- Aby uprościć i oddzielić architekturę, REST definiuje jednolity interfejs między klientami a serwerami. Jest to serce projektu RESTful i składa się z czterech pod-ograniczeń:
- Identyfikacja Zasobów: Każdy pojedynczy zasób musi być jednoznacznie identyfikowalny za pomocą stabilnego identyfikatora, którym w internetowych API REST jest URL. Na przykład,
/uzytkownicy/123jest unikalnym identyfikatorem użytkownika o ID 123. - Manipulacja Zasobami Poprzez Reprezentacje: Klient nie wchodzi w interakcję bezpośrednio z zasobem, ale z jego reprezentacją. Ta reprezentacja jest zazwyczaj formatem danych, takim jak JSON lub XML. Gdy klient chce zaktualizować dane użytkownika, pobiera reprezentację tego użytkownika (np. obiekt JSON), modyfikuje ją i wysyła nową reprezentację z powrotem na serwer.
- Samopisujące się Wiadomości: Każda wiadomość musi zawierać wystarczająco dużo informacji, aby opisać, jak ją przetworzyć. Osiąga się to za pomocą nagłówków HTTP (np.
Content-Type: application/jsoninformuje odbiorcę, że ciało wiadomości jest w formacie JSON) oraz użycia standardowych metod HTTP. - Hipermedia jako Silnik Stanu Aplikacji (HATEOAS): Jest to najbardziej dojrzała i często najrzadziej implementowana zasada. Stwierdza ona, że klient powinien być w stanie odkryć wszystkie dostępne akcje i zasoby za pomocą hiperłączy dostarczanych w odpowiedziach serwera. Na przykład odpowiedź serwera dla zasobu użytkownika może zawierać linki do „edytuj-uzytkownika” lub „zobacz-zamowienia-uzytkownika”, kierując kolejne kroki klienta.
- Identyfikacja Zasobów: Każdy pojedynczy zasób musi być jednoznacznie identyfikowalny za pomocą stabilnego identyfikatora, którym w internetowych API REST jest URL. Na przykład,
- 5. System Warstwowy (Layered System)
- Klient nie powinien być w stanie stwierdzić, czy jest połączony bezpośrednio z serwerem końcowym, czy z pośrednikiem po drodze. System RESTful może składać się z wielu warstw serwerów (np. proxy bezpieczeństwa, serwery buforujące, load balancery). Te warstwy można dodawać lub usuwać w razie potrzeby, aby poprawić wydajność, bezpieczeństwo i skalowalność, bez wpływu na klienta, o ile wszystkie przestrzegają jednolitego interfejsu.
- 6. Kod na Żądanie (Code on Demand) (Opcjonalne)
- To jedyne opcjonalne ograniczenie. Pozwala serwerowi na tymczasowe rozszerzenie lub dostosowanie funkcjonalności klienta poprzez transfer kodu wykonywalnego, takiego jak JavaScript. Przeglądarka internetowa jest najczęstszym tego przykładem, gdzie serwery wysyłają kod JavaScript, który jest następnie wykonywany w przeglądarce w celu tworzenia dynamicznych doświadczeń użytkownika.
Projektowanie API RESTful: Zasoby i Akcje
Projektowanie API RESTful polega na myśleniu o swojej aplikacji w kategoriach zasobów i standardowych operacji, które można na nich wykonywać za pomocą metod HTTP. Zasób jest kluczową abstrakcją informacji w REST. Może to być dokument, obraz, zbiór innych zasobów lub dowolny inny obiekt.
Identyfikacja Zasobów
Pierwszym krokiem jest zidentyfikowanie „rzeczowników” w systemie. Jakie są kluczowe byty? W przypadku aplikacji e-commerce zasobami mogą być klienci, produkty, zamówienia i pozycje w koszyku.
Każdy zasób powinien mieć unikalny, intuicyjny i spójny adres URL. Dobre praktyki sugerują:
- Używaj rzeczowników, a nie czasowników, w adresach URL (np.
/produkty, a nie/pobierzProdukty). - Używaj rzeczowników w liczbie mnogiej dla kolekcji (np.
/zamowieniareprezentuje listę wszystkich zamówień). - Używaj unikalnego ID do odwoływania się do konkretnego zasobu w kolekcji (np.
/zamowienia/123odnosi się do konkretnego zamówienia o ID 123). - Używaj zagnieżdżonych ścieżek dla powiązanych zasobów (np.
/zamowienia/123/pozycjereprezentuje listę pozycji w zamówieniu 123).
Mapowanie Akcji na Metody HTTP
Gdy już zdefiniujesz adresy URL swoich zasobów, używasz standardowych metod HTTP do wykonywania na nich akcji. To mapowanie jest centralne dla filozofii REST. Najczęstsze operacje to CRUD (Utwórz, Odczytaj, Zaktualizuj, Usuń).
| Operacja | Metoda HTTP | Przykładowy URL | Opis |
|---|---|---|---|
| Odczyt (Kolekcja) | GET | /produkty | Pobierz listę wszystkich produktów. |
| Odczyt (Konkretny element) | GET | /produkty/456 | Pobierz szczegóły produktu 456. |
| Utwórz | POST | /produkty | Utwórz nowy produkt. Dane nowego produktu są wysyłane w ciele żądania. |
| Aktualizuj (w całości) | PUT | /produkty/456 | Zastąp cały produkt 456 danymi wysłanymi w ciele żądania. |
| Aktualizuj (częściowo) | PATCH | /produkty/456 | Zastosuj częściową aktualizację do produktu 456 (np. zmień tylko cenę). |
| Usuń | DELETE | /produkty/456 | Usuń produkt 456. |
Formaty Danych: "Reprezentacje" w REST
REST jest elastyczny co do formatu używanego do reprezentacji danych, ale zdecydowanie najczęściej używanym formatem jest (JavaScript Object Notation). Jego prosta, tekstowa struktura par klucz-wartość i tablic jest łatwa do zrozumienia zarówno dla ludzi, jak i maszyn.
Żądanie GET na adres /produkty/456 może zwrócić następującą reprezentację JSON:
{
"id": 456,
"nazwa": "Bezprzewodowa mysz ergonomiczna",
"cena": 199.99,
"na_stanie": true,
"kategoria": "Peryferia"
}Aby zaktualizować ten produkt za pomocą metody PUT, klient wysłałby podobny obiekt JSON w ciele swojego żądania. Klient i serwer używają nagłówków Content-Type i Accept do negocjacji i określenia, że komunikują się za pomocą typu medium application/json. Chociaż JSON dominuje, API RESTful mogą również używać innych formatów, takich jak XML, YAML, czy nawet zwykły tekst.