rest Samouczek
Rozpoczęcie odpoczynku
Szukaj…
Uwagi
W tej sekcji omówiono, czym jest reszta i dlaczego deweloper może chcieć z niej skorzystać.
Powinien również wymieniać wszelkie duże tematy w spoczynku i link do powiązanych tematów. Ponieważ Dokumentacja do odpoczynku jest nowa, konieczne może być utworzenie początkowych wersji tych powiązanych tematów.
Przegląd REST
REST oznacza RE prezentacyjny S tate T ransfer i został wymyślony przez Roy Fielding w jego pracy doktorskiej stylów architektury i projektowania sieci opartych na architekturze Software . W nim identyfikuje określone zasady architektury, takie jak:
Zasoby adresowalne: kluczowa abstrakcja informacji i danych w REST jest zasobem i każdy zasób musi być adresowalny przez URI.
Jednolity, ograniczony interfejs: użycie małego zestawu dobrze zdefiniowanych metod do manipulowania naszymi zasobami.
Zorientowane na reprezentację: zasób, do którego odnosi się jeden identyfikator URI, może mieć różne formaty, a różne platformy potrzebują różnych formatów, na przykład przeglądarki potrzebują HTML, JavaScript wymaga JSON, a aplikacje Java mogą wymagać XML, JSON, CSV, tekstu itp. Więc współpracujemy z usługami przy użyciu reprezentacji tej usługi.
Komunikuj się bezstanowo: aplikacje bezstanowe są łatwiejsze do skalowania.
Hypermedia jako silnik stanu aplikacji: pozwól, aby nasze formaty danych sterowały zmianami stanu w naszych aplikacjach.
Zestaw tych zasad architektonicznych nazywa się REST. Koncepcje REST są inspirowane koncepcją HTTP. Roy Fielding, który dał nam REST, jest również jednym z autorów specyfikacji HTTP.
Usługi sieciowe i usługi RESTful Web Services to usługi, które są narażone na dostęp do Internetu w celu zautomatyzowanego dostępu. Są to API online, które możemy wywołać z naszego kodu. Istnieją dwa rodzaje „dużych” usług sieciowych SOAP i REST.
Usługi sieci Web RESTful : usługi sieci Web napisane przy użyciu koncepcji architektonicznych REST nazywane są usługami sieci RESTful, które koncentrują się na zasobach systemowych i sposobie przesyłania stanu zasobów przez protokół HTTP do różnych klientów.
Ten dokument dotyczy wyłącznie usług sieciowych RESTful, więc nie będziemy wchodzić w szczegóły SOAP WS.
Podczas projektowania usług internetowych typu RESTful nie ma żadnych ścisłych zasad
- Brak standardu protokołu
- Brak standardowego kanału komunikacji
- Brak standardu definicji usługi
Ale SOAP ma rygorystyczne zasady dla nich wszystkich. Wszystkie usługi sieciowe SOAP są zgodne ze specyfikacją SOAP, która określa, jaka powinna być każda usługa internetowa SOAP. Niniejsza specyfikacja jest opracowywana i zarządzana przez komitet, a jeśli SOAP WS nie przestrzega nawet jednej reguły, to z definicji nie jest SOAP.
Koncepcje RESTful Web Services
Istnieje kilka wskazówek, które należy wziąć pod uwagę przy projektowaniu / rozwijaniu interfejsu API RESTful:
- Lokalizacje oparte na zasobach / URI
- Właściwe stosowanie metod HTTP
- HATEOAS (Hypermedia jako silnik stanu aplikacji)
Głównym podejściem podczas opracowywania interfejsów API RESTful powinno być uczynienie interfejsu API „możliwie jak najbardziej RESTful”.
REST przez HTTP
REST to architektura niezależna od protokołu, zaproponowana przez Roy Fieldinga w jego rozprawie (rozdział 5 jest prezentacją REST), która uogólnia sprawdzoną koncepcję przeglądarek internetowych jako klientów w celu oddzielenia klientów w systemie rozproszonym od serwerów.
Aby usługa lub interfejs API był RESTful, musi spełniać określone ograniczenia, takie jak:
- Klient-serwer
- Bezpaństwowiec
- Pamięć podręczna
- System warstwowy
- Jednolity interfejs
- Identyfikacja zasobów
- Reprezentacja zasobów
- Wiadomości opisowe
- Hipermedia
Poza ograniczeniami wymienionymi w rozprawie Fielding, w swoim blogu interfejsy API REST muszą być oparte na hipertekstie , Fielding wyjaśnił, że samo wywołanie usługi przez HTTP nie powoduje, że RESTful . Usługa powinna zatem również przestrzegać innych zasad, które streszczono w następujący sposób:
Interfejs API powinien być zgodny z podstawowym protokołem i nie może go naruszać. Chociaż REST jest używany przez HTTP przez większość czasu, nie jest on ograniczony do tego protokołu.
Silny nacisk na zasoby i ich prezentację za pośrednictwem mediów.
Klienci nie powinni mieć wstępnej wiedzy ani założeń na temat dostępnych zasobów lub ich zwróconego stanu ( „typowanego” zasobu ) w interfejsie API, ale powinni uczyć się ich w locie za pośrednictwem wydanych żądań i analizowanych odpowiedzi. Daje to serwerowi możliwość łatwego przenoszenia lub zmiany nazw zasobów bez przerywania implementacji klienta.
Model dojrzałości Richardsona
Model dojrzałości Richardsona jest sposobem na zastosowanie ograniczeń REST przez HTTP w celu uzyskania usług sieciowych RESTful.
Leonard Richardson podzielił aplikacje na te 4 warstwy:
- Poziom 0: użycie HTTP do transportu
- Poziom 1: użycie adresu URL do identyfikacji zasobów
- Poziom 2: użycie czasowników i statusów HTTP do interakcji
- Poziom 3: korzystanie z HATEOAS
Ponieważ nacisk kładziony jest na reprezentację stanu zasobu, zaleca się obsługę wielu reprezentacji tego samego zasobu. Reprezentacja może zatem przedstawiać przegląd stanu zasobu, podczas gdy inna zwraca pełne szczegóły tego samego zasobu.
Należy również zauważyć, że biorąc pod uwagę ograniczenia Fielding, interfejs API jest skutecznie RESTful dopiero po zaimplementowaniu 3. poziomu RMM .
Żądania i odpowiedzi HTTP
Żądanie HTTP to:
- Czasownik (inaczej metoda), w większości przypadków GET , POST , PUT , DELETE lub PATCH
- URL
- Nagłówki (pary klucz-wartość)
- Opcjonalnie ciało (inaczej ładunek, dane)
Odpowiedź HTTP to:
- Stan, przeważnie jeden z 2xx (sukces) , 4xx (błąd klienta) lub 5xx (błąd serwera)
- Nagłówki (pary klucz-wartość)
- Ciało (inaczej ładowność, dane)
Charakterystyka czasowników HTTP:
- Czasowniki, które mają ciało:
POST
,PUT
,PATCH
- Czasowniki, które muszą być bezpieczne (tzn. Nie mogą modyfikować zasobów):
GET
- Czasowniki, które muszą być idempotentne (tj. Nie mogą ponownie wpływać na zasoby, gdy są uruchamiane wiele razy):
GET
(nullipotent),PUT
,DELETE
body safe idempotent
GET ✗ ✔ ✔
POST ✔ ✗ ✗
PUT ✔ ✗ ✔
DELETE ✗ ✗ ✔
PATCH ✔ ✗ ✗
W związku z tym czasowniki HTTP można porównać do funkcji CRUD :
Zauważ, że żądanie PUT
prosi klientów o przesłanie całego zasobu ze zaktualizowanymi wartościami. Aby częściowo zaktualizować zasób, można użyć czasownika PATCH
(zobacz Jak częściowo zaktualizować zasób? ).
Zwykłe stany odpowiedzi HTTP
Sukces
- 201 (UTWORZONY) : zasób został utworzony
- 202 (AKCEPTOWANE) : żądanie zostało zaakceptowane, ale proces jest nadal w toku
- 204 (BRAK TREŚCI) : żądanie spełnione, bez dodatkowej treści
- W przeciwnym razie: 200 (OK)
Przekierowanie
- 304 (NIEZMODYFIKOWANY) : klient może użyć buforowanej wersji żądanego zasobu
Błędy klienta
- 401 (NIEAUTORYZOWANY) : anonimowe żądanie uzyskuje dostęp do chronionego interfejsu API
- 403 (ZABRONIONE) : uwierzytelnione żądanie nie ma wystarczających uprawnień, aby uzyskać dostęp do chronionego interfejsu API
- 404 (NIE ZNALEZIONO) : nie znaleziono zasobu
- 409 (KONFLIKT) : konflikt stanu zasobów (np. Użytkownik próbuje utworzyć konto z już zarejestrowanym adresem e-mail)
- 410 (BRAK) : to samo co 404, ale zasób istniał
- 412 (AWARIA WSTĘPNA) : żądanie próbuje zmodyfikować zasób, który jest w nieoczekiwanym stanie
- 422 (NIEPRZETWARZANA PODMIOT) : ładunek żądania jest poprawny składniowo, ale semantycznie błędny (np. Wymagane pole, które nie zostało wycenione)
- 423 (ZABLOKOWANY) : zasób jest zablokowany
- 424 (AWARIA NIEUDANA) : żądane działanie zależało od innego działania, które się nie powiodło
- 429 (ZBYT WIELE WNIOSKÓW) : użytkownik wysłał zbyt wiele żądań w danym czasie
- W przeciwnym razie: 400 (ZŁE WNIOSEK)
Błędy serwera
- 501 (NIEZ WDROŻONY) : serwer nie obsługuje funkcji wymaganych do spełnienia żądania
- 503 (USŁUGA NIEDOSTĘPNA) : serwer obecnie nie jest w stanie obsłużyć żądania z powodu tymczasowego przeciążenia lub zaplanowanej konserwacji
- 507 (NIESAMOWITE PRZECHOWYWANIE) : serwer nie może zapisać reprezentacji potrzebnej do pomyślnego zakończenia żądania
- W przeciwnym razie: 500 (BŁĄD SERWERA WEWNĘTRZNEGO)
Notatki
Nic nie stoi na przeszkodzie, aby dodać ciało do błędnych odpowiedzi, aby wyjaśnienie klientów było wyraźniejsze. Na przykład 422 (NIEPRZETWARZANA PODMIOT) jest nieco niejasny: organ odpowiedzi powinien podać powód, dla którego podmiot nie mógł zostać przetworzony.
HATEOAS
Każdy zasób musi zapewniać hipermedialne zasoby, z którymi jest powiązany. Link składa się co najmniej z:
-
rel
(na rel acji vel nazwa) opisuje zależność pomiędzy głównym źródłem i połączonej jednym (S) -
href
: adres URL kierowany do połączonych zasobów
Można również użyć dodatkowych atrybutów, aby pomóc w wycofaniu, negocjowaniu treści itp.
Cormac Mulhall wyjaśnia, że klient powinien zdecydować, którego czasownika HTTP użyć, na podstawie tego, co próbuje zrobić . W razie wątpliwości dokumentacja API powinna i tak pomóc w zrozumieniu dostępnych interakcji ze wszystkimi hipermediami.
Rodzaje mediów
Typy mediów pomagają w tworzeniu samoopisujących wiadomości. Odgrywają rolę umowy między klientami a serwerami, aby mogli wymieniać zasoby i hipermedie.
Chociaż application/json
i application/xml
są dość popularnymi typami mediów, nie zawierają dużej semantyki. Po prostu opisują ogólną składnię zastosowaną w dokumencie. Należy stosować bardziej wyspecjalizowane typy nośników, które obsługują wymagania HATEOAS (lub rozszerzyć je na typy nośników dostawców ), takie jak:
Klient informuje serwer, jakie typy mediów rozumie, dodając do swojego żądania nagłówek Accept
, na przykład:
Accept: application/hal+json
Jeśli serwer nie jest w stanie wygenerować żądanego zasobu w takiej reprezentacji, zwraca wartość 406 (NIEDOPUSZCZALNA) . W przeciwnym razie dodaje typ nośnika w nagłówku Content-Type
odpowiedzi zawierającej reprezentowany zasób, na przykład:
Content-Type: application/hal+json
Bezpaństwowy> stanowy
Dlaczego?
Serwer stanowy oznacza, że sesje klientów są przechowywane w lokalnej pamięci instancji serwera (prawie zawsze w sesjach serwera WWW). To zaczyna być problemem podczas próby skalowania w poziomie : jeśli ukryjesz kilka instancji serwera za modułem równoważenia obciążenia, jeśli jeden klient zostanie najpierw wysłany do instancji nr 1 podczas logowania, a następnie do instancji nr 2 podczas pobierania chronionego zasobu, na przykład , wówczas druga instancja obsłuży żądanie jako anonimowe, ponieważ sesja klienta została zapisana lokalnie w instancji nr 1 .
Znaleziono rozwiązania pozwalające rozwiązać ten problem (np. Poprzez konfigurację replikacji sesji i / lub sesji trwałej ), ale architektura REST proponuje inne podejście: po prostu nie wprowadzaj stanu serwera, uczyń go bezstanowym . Według Fieldinga :
Każde żądanie od klienta do serwera musi zawierać wszystkie informacje niezbędne do zrozumienia żądania i nie może korzystać z żadnego kontekstu przechowywanego na serwerze. Stan sesji jest zatem w całości przechowywany na kliencie.
Innymi słowy, żądanie musi być obsługiwane dokładnie w ten sam sposób, niezależnie od tego, czy jest wysyłane do instancji nr 1 czy instancji nr 2 . Dlatego aplikacje bezstanowe są uważane za łatwiejsze do skalowania .
W jaki sposób?
Powszechnym podejściem jest uwierzytelnianie oparte na tokenach , szczególnie w przypadku modnych tokenów internetowych JSON . Zauważ, że JWT wciąż ma pewne problemy, szczególnie dotyczące unieważnienia i automatycznego przedłużania ważności (tj. Funkcja zapamiętaj mnie ).
Notatki dodatkowe
Używanie plików cookie lub nagłówków (lub czegokolwiek innego) nie ma nic wspólnego z tym, czy serwer jest stanowy czy bezstanowy: są to tylko media, które są tutaj używane do transportu tokenów (identyfikator sesji dla serwerów stanowych, JWT itp.), Nic więcej.
Podczas relaksującego API jest używany tylko przez przeglądarki ( HttpOnly i bezpieczna ) Ciasteczka mogą być bardzo wygodne, ponieważ przeglądarki będą automatycznie dołącza je do żądań wychodzących. Warto wspomnieć, że jeśli zdecydujesz się na pliki cookie, pamiętaj o CSRF (dobrym sposobem na zapobieganie temu jest generowanie i wysyłanie przez klientów tej samej unikalnej tajnej wartości zarówno w pliku cookie, jak i niestandardowym nagłówku HTTP ).
Buforowalny interfejs API z żądaniami warunkowymi
Z nagłówkiem Last-Modified
Serwer może dostarczyć nagłówek daty Last-Modified
odpowiedzi zawierającej zasoby, które można buforować. Klienci powinni następnie przechowywać tę datę razem z zasobem.
Teraz za każdym razem, gdy klienci proszą API o odczytanie zasobu, mogą dodać do swoich żądań nagłówek If-Modified-Since
zawierający najnowszą datę ostatniej Last-Modified
którą otrzymali i zapisali. Serwer musi następnie porównać nagłówek żądania i faktyczną datę ostatniej modyfikacji zasobu. Jeśli są one równe, serwer zwraca 304 (NIE ZMODYFIKOWANY) z pustą treścią: klient żądający powinien użyć aktualnie buforowanego zasobu, który ma.
Ponadto, gdy klienci proszą API o aktualizację zasobu (tj. Czasownikiem niebezpiecznym), mogą dodać nagłówek If-Unmodified-Since
. Pomaga to w radzeniu sobie z warunkami wyścigu: jeśli nagłówek i data ostatniej modyfikacji są różne, serwer zwraca 412 (AWARIA WSTĘPNA) . Klient powinien następnie odczytać nowy stan zasobu przed ponowną próbą zmodyfikowania zasobu.
Z nagłówkiem ETag
ETag (znacznik encji) to identyfikator określonego stanu zasobu. Może to być skrót MD5 zasobu dla silnego sprawdzania poprawności lub specyficzny dla domeny identyfikator słabego sprawdzania poprawności .
Zasadniczo proces jest taki sam, jak w przypadku nagłówka Last-Modified
: serwer dostarcza nagłówek ETag
do odpowiedzi zawierających zasoby, które można buforować, a klienci powinni następnie przechowywać ten identyfikator razem z zasobem.
Następnie klienci dostarczają nagłówek If-None-Match
gdy chcą odczytać zasób, zawierający najnowszy znacznik ETag, który otrzymali i zapisali. Serwer może teraz zwrócić 304 (NIEZMODYFIKOWANY), jeśli nagłówek odpowiada faktycznemu znacznikowi ET zasobu.
Ponownie, klienci mogą dostarczyć nagłówek If-Match
gdy chcą zmodyfikować zasób, a serwer musi zwrócić 412 (WSTĘP NIEUDANY), jeśli podany ETag nie pasuje do rzeczywistego.
Dodatkowe uwagi
ETag> data
Jeśli klienci podają w swoich żądaniach zarówno datę, jak i znacznik ETag, datę należy zignorować. Z RFC 7232 ( tu i tutaj ):
Odbiorca MUSI zignorować
If-Modified-Since
/If-Unmodified-Since
jeśli żądanie zawiera pole nagłówkaIf-None-Match
/If-Match
; warunek wIf-None-Match
/ wIf-Match
jest uważany za bardziej dokładny zamiennik warunku wIf-Modified-Since
/If-Unmodified-Since
If-Modified-Since
If-Unmodified-Since
oraz oba są łączone wyłącznie w celu współpracy ze starszymi pośrednikami które mogą nie implementowaćIf-None-Match
/If-Match
.
Płytkie ETagi
Ponadto, chociaż jest całkiem oczywiste, że ostatnie modyfikowane daty są zachowywane wraz z zasobami po stronie serwera, w ETag dostępnych jest kilka podejść .
Typowym podejściem jest wdrażanie płytkich znaczników ET: serwer przetwarza żądanie tak, jakby nie podano nagłówków warunkowych, ale tylko na samym końcu generuje znacznik ETag odpowiedzi, którą ma zamiar zwrócić (np. Mieszając go), i porównuje z dostarczonym. Jest to stosunkowo łatwe do wdrożenia, ponieważ potrzebny jest tylko przechwytywacz HTTP (a wiele implementacji już istnieje w zależności od serwera). To powiedziawszy, warto wspomnieć, że takie podejście pozwoli zaoszczędzić przepustowość, ale nie wydajność serwera :
Głębsza implementacja mechanizmu ETag może potencjalnie przynieść znacznie większe korzyści - takie jak obsługa niektórych żądań z pamięci podręcznej i wcale nie konieczność wykonywania obliczeń - ale implementacja z pewnością nie byłaby tak prosta, ani tak łatwa w podłączeniu, jak płytkie podejście opisane tutaj.
Częste pułapki
Dlaczego nie powinienem umieszczać czasowników w adresach URL?
HTTP nie jest RPC : tym, co znacznie różni HTTP od RPC, jest to, że żądania są kierowane do zasobów . W końcu URL oznacza Uniform Resource Locator, a URL to URI : Uniden Resource Idenfitier. Adres URL jest skierowany na zasób, z którym chcesz się uporać , metoda HTTP wskazuje, co chcesz z nim zrobić . Metody HTTP są również znane jako czasowniki : czasowniki w adresach URL nie mają wtedy sensu. Pamiętaj, że relacje HATEOAS nie powinny również zawierać czasowników, ponieważ linki również kierują zasoby.
Jak częściowo zaktualizować zasób?
Ponieważ żądania PUT
proszą klientów o przesłanie całego zasobu ze zaktualizowanymi wartościami, PUT /users/123
nie może być użyty na przykład do aktualizacji e-maila użytkownika. Jak wyjaśnił William Durand w Please. Nie łataj jak idiota. , dostępnych jest kilka rozwiązań zgodnych z REST:
- Ujawnij właściwości zasobu i użyj metody
PUT
, aby wysłać zaktualizowaną wartość, ponieważ specyfikacjaPUT
stwierdza, że częściowe aktualizacje treści są możliwe poprzez celowanie w osobno zidentyfikowany zasób ze stanem pokrywającym się z częścią większego zasobu :
PUT https://example.com/api/v1.2/users/123/email
body:
new.email@example.com
- Użyj żądania
PATCH
które zawiera zestaw instrukcji opisujących, w jaki sposób należy zmodyfikować zasób (np. Następujące poprawki JSON ):
PATCH https://example.com/api/v1.2/users/123
body:
[
{ "op": "replace", "path": "/email", "value": "new.email@example.com" }
]
- Użyj żądania
PATCH
zawierającego częściową reprezentację zasobu, jak zaproponowano w komentarzu Matta Chapmana :
PATCH https://example.com/api/v1.2/users/123
body:
{
"email": "new.email@example.com"
}
Co z działaniami, które nie pasują do świata operacji CRUD?
Cytując Vinay Sahni w najlepszych praktykach dotyczących projektowania pragmatycznego interfejsu API RESTful :
To tutaj rzeczy mogą się rozmazać. Istnieje wiele podejść:
Zmień strukturę akcji, aby wyglądała jak pole zasobu. Działa to, jeśli akcja nie przyjmuje parametrów. Na przykład akcja aktywacji może być odwzorowana na pole
activated
logicznie i zaktualizowana za pomocą PATCHA do zasobu.Traktuj to jak pod-zasób z zasadami RESTful. Na przykład interfejs API GitHub pozwala oznaczyć gwiazdkę za pomocą
PUT /gists/:id/star
i unstar za pomocąDELETE /gists/:id/star
.Czasami naprawdę nie ma sposobu, aby odwzorować akcję na rozsądną strukturę RESTful. Na przykład wyszukiwanie wielu zasobów nie ma sensu, aby stosować je do punktu końcowego określonego zasobu. W takim przypadku
/search
ma sens, nawet jeśli nie jest zasobem. To jest OK - po prostu rób to, co jest właściwe z punktu widzenia konsumenta interfejsu API i upewnij się, że jest to dobrze udokumentowane, aby uniknąć nieporozumień.
Wspólne praktyki
API jest udokumentowane. Dostępne są narzędzia pomocne w budowaniu dokumentacji, np. Swagger lub Spring REST Docs .
Interfejs API jest wersjonowany za pomocą nagłówków lub adresu URL:
https://example.com/api/v1.2/blogs/123/articles
^^^^
- Zasoby mają wiele nazw :
https://example.com/api/v1.2/blogs/123/articles
^^^^^ ^^^^^^^^
- Adresy URL używają wielkości kebab (słowa są pisane małymi literami i rozdzielane myślnikiem):
https://example.com/api/v1.2/quotation-requests
^^^^^^^^^^^^^^^^^^
- HATEOAS zapewnia „samodzielny” link do zasobów, celując w siebie:
{
...,
_links: {
...,
self: { href: "https://example.com/api/v1.2/blogs/123/articles/789" }
^^^^
}
}
- Relacje HATEOAS używają lowerCamelCase (słowa są pisane małymi literami, a następnie pisane wielkimi literami, z wyjątkiem pierwszej, a spacje są pomijane), aby umożliwić klientom JavaScript stosowanie notacji kropkowej przy jednoczesnym przestrzeganiu konwencji nazewnictwa JavaScript podczas uzyskiwania dostępu do linków:
{
...,
_links: {
...,
firstPage: { "href": "https://example.com/api/v1.2/blogs/123/articles?pageIndex=1&pageSize=25" }
^^^^^^^^^
}
}
Zarządzanie blogami za pomocą interfejsu API RESTful HTTP
Poniższe przykłady używają HAL do wyrażenia HATEOAS i wykorzystują:
- CURIE (kompaktowy URI): służy do udostępniania linków do dokumentacji API
- Szablony URI : URI, który zawiera parametry, które muszą zostać podstawione przed rozwiązaniem URI
Uzyskaj blog 123
Żądanie
GET https://example.com/api/v1.2/blogs/123
headers:
Accept: application/hal+json
Odpowiedź
status: 200 (OK)
headers:
Content-Type: application/hal+json
body:
{
"id": 123,
"title": "The blog title",
"description": "The blog description",
"_links": {
"curies": [{ "name": "doc", "href": "https://example.com/docs/{rel}", "templated": true }],
"self": { "href": "https://example.com/api/v1.2/blogs/123" },
"doc:articles": { "href": "https://example.com/api/v1.2/blogs/123/articles{?pageIndex,pageSize}", "templated": true }
}
}
Utwórz nowy artykuł na blogu 123
Żądanie
POST https://example.com/api/v1.2/blogs/123/articles
headers:
Content-Type: application/json
Accept: application/hal+json
X-Access-Token: XYZ
body:
{
"title": "The title 2",
"content": "The content 2"
}
Odpowiedź
status: 201 (CREATED)
headers:
Content-Type: application/hal+json
body:
{
"id": 789,
"title": "The title 2",
"content": "The content 2",
"_links": {
"curies": [{ "name": "doc", "href": "https://example.com/docs/{rel}", "templated": true }],
"self": { "href": "https://example.com/api/v1.2/blogs/123/articles/789" },
"doc:blog": { "href": "https://example.com/api/v1.2/blogs/123", "title": "The blog title" },
"doc:comments": { "href": "https://example.com/api/v1.2/blogs/123/articles/789/comments{?pageIndex,pageSize}", "templated": true }
}
}
Uzyskaj artykuł 789 bloga 123
Żądanie
GET https://example.com/api/v1.2/blogs/123/articles/789
headers:
Accept: application/hal+json
Odpowiedź
status: 200 (OK)
headers:
Content-Type: application/hal+json
body:
{
"id": 789,
"title": "The title 2",
"content": "The content 2",
"_links": {
"curies": [{ "name": "doc", "href": "https://example.com/docs/{rel}", "templated": true }],
"self": { "href": "https://example.com/api/v1.2/blogs/123/articles/789" },
"doc:blog": { "href": "https://example.com/api/v1.2/blogs/123", "title": "The blog title" },
"doc:comments": { "href": "https://example.com/api/v1.2/blogs/123/articles/789/comments{?pageIndex,pageSize}", "templated": true }
}
}
Uzyskaj czwartą stronę z 25 artykułów na blogu 123
Żądanie
GET https://example.com/api/v1.2/blogs/123/articles?pageIndex=4&pageSize=25
headers:
Accept: application/hal+json
Odpowiedź
status: 200 (OK)
headers:
Content-Type: application/hal+json
body:
{
"pageIndex": 4,
"pageSize": 25,
"totalPages": 26,
"totalArticles": 648,
"_link": {
"firstPage": { "href": "https://example.com/api/v1.2/blogs/123/articles?pageIndex=1&pageSize=25" },
"previousPage": { "href": "https://example.com/api/v1.2/blogs/123/articles?pageIndex=3&pageSize=25" },
"self": { "href": "https://example.com/api/v1.2/blogs/123/articles?pageIndex=4&pageSize=25" },
"nextPage": { "href": "https://example.com/api/v1.2/blogs/123/articles?pageIndex=5&pageSize=25" },
"lastPage": { "href": "https://example.com/api/v1.2/blogs/123/articles?pageIndex=26&pageSize=25" }
},
"_embedded": [
{
...
}, {
"id": 456,
"title": "The title 1",
"content": "The content 1",
"_links": {
"curies": [{ "name": "doc", "href": "https://example.com/docs/{rel}", "templated": true }],
"self": { "href": "https://example.com/api/v1.2/blogs/123/articles/456" },
"doc:blog": { "href": "https://example.com/api/v1.2/blogs/123", "title": "The blog title" },
"doc:comments": { "href": "https://example.com/api/v1.2/blogs/123/articles/456/comments{?pageIndex,pageSize}", "templated": true }
}
}, {
"id": 789,
"title": "The title 2",
"content": "The content 2",
"_links": {
"curies": [{ "name": "doc", "href": "https://example.com/docs/{rel}", "templated": true }],
"self": { "href": "https://example.com/api/v1.2/blogs/123/articles/789" },
"doc:blog": { "href": "https://example.com/api/v1.2/blogs/123", "title": "The blog title" },
"doc:comments": { "href": "https://example.com/api/v1.2/blogs/123/articles/789/comments{?pageIndex,pageSize}", "templated": true }
}
}, {
...
}
]
}
Zaktualizuj artykuł 789 blogu 123
Żądanie
PUT https://example.com/api/v1.2/blogs/123/articles/789
headers:
Content-Type: application/json
Accept: application/hal+json
X-Access-Token: XYZ
body:
{
"id": 789,
"title": "The title 2 updated",
"content": "The content 2 updated"
}
Odpowiedź
status: 200 (OK)
headers:
Content-Type: application/hal+json
body:
{
"id": 789,
"title": "The title 2 updated",
"content": "The content 2 updated",
"_links": {
"curies": [{ "name": "doc", "href": "https://example.com/docs/{rel}", "templated": true }],
"self": { "href": "https://example.com/api/v1.2/blogs/123/articles/789" },
"doc:blog": { "href": "https://example.com/api/v1.2/blogs/123", "title": "The blog title" },
"doc:comments": { "href": "https://example.com/api/v1.2/blogs/123/articles/789/comments{?pageIndex,pageSize}", "templated": true }
}
}
Notatki
- Identyfikator używany do identyfikacji zasobu do aktualizacji to ten znajdujący się w adresie URL : ten w treści (jeśli istnieje) musi zostać cicho zignorowany.
- Gdy żądanie
PUT
aktualizuje cały zasób, jeśli żadnacontent
nie zostałaby wysłana, należy ją usunąć z utrwalonego zasobu.
Usuń artykuł 789 z blogu 123
Żądanie
DELETE https://example.com/api/v1.2/blogs/123/articles/789
headers:
Accept: application/hal+json
X-Access-Token: XYZ
Odpowiedź
status: 204 (NO CONTENT)
headers:
Content-Type: application/hal+json
body:
{
"_links": {
"curies": [{ "name": "doc", "href": "https://example.com/docs/{rel}", "templated": true }],
"doc:blog": { "href": "https://example.com/api/v1.2/blogs/123", "title": "The blog title" }
}
}
Naruszenie REST
<stock>
<add>
<item>
<name>Milk</name>
<quantity>2</quantity>
</item>
</add>
</stock>
Umieszczenie tego ciała w zasobach takich jak /stocks/123
narusza ideę REST. Chociaż to ciało jest put
i zawiera wszystkie niezbędne informacje, zawiera również wywołanie metody, które można add
gdzieś, gdy ciało jest przetwarzane. Po REST należy opublikować item
w /stocks/123/items/
.