Pamiętaj, że mam podstawowe rozumienie REST. Powiedzmy, że mam ten adres URL:
http://api.animals.com/v1/dogs/1/
A teraz chcę, aby kelner powodował szczekanie psa. Tylko serwer wie, jak to zrobić. Powiedzmy, że chcę, aby działał w trybie CRON, który powoduje, że pies szczeka co 10 minut przez resztę wieczności. Jak wygląda to wezwanie? W pewnym sensie chcę to zrobić:
Żądanie adresu URL:
ACTION http://api.animals.com/v1/dogs/1/
W treści żądania:
{"action":"bark"}
Zanim zdenerwujesz się na mnie, że stworzyłem własną metodę HTTP, pomóż mi i daj mi lepszy pomysł, jak powinienem wywołać metodę po stronie serwera w RESTful sposób. :)
EDYTUJ W CELU WYJAŚNIENIA
Więcej wyjaśnień na temat tego, co robi metoda „kory”. Oto kilka opcji, które mogą skutkować różną strukturą wywołań interfejsu API:
- szczeka po prostu wysyła e-mail na adres dog.email i nic nie rejestruje.
- bark wysyła e-mail na adres dog.email i zwiększa liczbę dog.barkCount o 1.
- bark tworzy nowy rekord „bark” z zapisem bark.timestamp, kiedy nastąpiła kora. Zwiększa również liczbę dog.barkCount o 1.
- bark uruchamia polecenie systemowe, aby pobrać najnowszą wersję kodu psa z Githuba. Następnie wysyła wiadomość tekstową do właściciela psa, informując go, że nowy kod psa jest w produkcji.
api
rest
url
api-design
restful-architecture
Kirk Ouimet
źródło
źródło
PATCH
może być odpowiedni. Pod koniec mojej odpowiedzi wyjaśniam dlaczego .Odpowiedzi:
Dlaczego warto dążyć do projektu RESTful?
Zasady RESTful wprowadzają funkcje, które sprawiają, że strony internetowe są łatwe (dla losowego użytkownika do „surfowania” po nich) do projektu API usług sieciowych , dzięki czemu są one łatwe w użyciu dla programisty. REST nie jest dobry, ponieważ jest REST, jest dobry, ponieważ jest dobry. I to jest dobre głównie dlatego, że jest proste .
Prostota zwykłego protokołu HTTP (bez kopert SOAP i
POST
usług przeciążonych jednym identyfikatorem URI ), co niektórzy mogą nazwać „brakiem funkcji” , jest w rzeczywistości jego największą zaletą . Od samego początku HTTP prosi o adresowalność i bezpaństwowość : dwie podstawowe decyzje projektowe, które zapewniają skalowalność HTTP do dzisiejszych mega-witryn (i mega-usług).Ale REST nie jest najlepszym rozwiązaniem: czasami może być odpowiedni styl RPC („zdalne wywołanie procedury” - na przykład SOAP) , a czasami inne potrzeby mają pierwszeństwo przed zaletami sieci Web. Jest okej. To, czego tak naprawdę nie lubimy, to niepotrzebna złożoność . Zbyt często programista lub firma sprowadza usługi w stylu RPC do zadań, z którymi zwykły stary HTTP mógłby sobie poradzić. Efekt jest taki, że HTTP jest zredukowane do protokołu transportowego dla olbrzymiego ładunku XML, który wyjaśnia, co się „naprawdę” dzieje (nie URI ani metoda HTTP dają o tym wskazówkę). Wynikowa usługa jest zbyt złożona, niemożliwa do debugowania i nie będzie działać, jeśli Twoi klienci nie będą mieli dokładnej konfiguracji zgodnie z zamierzeniami programisty.
W ten sam sposób kod Java / C # nie może być zorientowany obiektowo, samo użycie protokołu HTTP nie czyni projektu zgodnym z REST. Można złapać się w pośpiechu myślenia o swoich usługach w kategoriach działań i metod zdalnych, które należy nazwać. Nic dziwnego, że skończy się to głównie w usłudze w stylu RPC (lub w hybrydzie REST-RPC). Pierwszym krokiem jest myślenie inaczej. Projekt zgodny ze standardem REST można osiągnąć na wiele sposobów, jednym ze sposobów jest myślenie o aplikacji w kategoriach zasobów, a nie działań:
Poniżej przedstawię przykłady. (Innym kluczowym aspektem REST jest użycie HATEOAS - nie szczotkuję go tutaj, ale mówię o tym szybko w innym poście .)
Zagadnienia pierwszego projektu
Rzućmy okiem na proponowany projekt:
Po pierwsze, nie powinniśmy rozważać tworzenia nowego czasownika HTTP (
ACTION
). Ogólnie rzecz biorąc, jest to niepożądane z kilku powodów:ACTION
czasownik istnieje?Rozważmy teraz użycie
POST
(poniżej omówię dlaczego, po prostu uwierz mi na słowo):To mogłoby być OK ... ale tylko wtedy, gdy :
{"action":"bark"}
był dokumentem; i/v1/dogs/1/
był identyfikatorem URI „procesora dokumentów” (podobnym do fabrycznego). „Procesor dokumentów” to URI, do którego po prostu „wrzucasz” i „zapomnisz” o nich - procesor może przekierować cię do nowo utworzonego zasobu po „rzuceniu”. Np. URI do wysyłania wiadomości w usłudze brokera komunikatów, który po wysłaniu przekierowuje do URI, który pokazuje stan przetwarzania wiadomości.Nie wiem zbyt wiele o twoim systemie, ale założę się, że oba nie są prawdziwe:
{"action":"bark"}
nie jest dokumentem , w rzeczywistości jest to metoda, którą próbujesz wkraść się do serwisu; i/v1/dogs/1/
URI oznacza „pies” zasób (prawdopodobnie z psemid==1
), a nie procesora dokumentów.Więc wszystko, co teraz wiemy, to to, że powyższy projekt nie jest tak RESTful, ale co to dokładnie jest? Co w tym złego? Zasadniczo jest to złe, ponieważ jest to złożony identyfikator URI o złożonych znaczeniach. Nic z tego nie można wywnioskować. Skąd programista miałby wiedzieć, że pies ma
bark
akcję, którą można potajemnie wprowadzićPOST
do niego?Projektowanie wywołań API pytania
Przejdźmy więc do sedna i spróbujmy zaprojektować te szczekanie RESTO, myśląc w kategoriach zasobów . Pozwólcie mi zacytować książkę Restful Web Services :
W następstwie powyższego opisu widać, że
bark
można modelować jako o subresource Urządzonydog
(ponieważbark
zawiera się w psa, to jest kora jest „szczekaly” przez psa).Z tego rozumowania już mamy:
POST
/barks
Zasobem jest podźródło psa:,/v1/dogs/1/barks
reprezentującebark
„fabrykę”. Ten identyfikator URI jest unikalny dla każdego psa (ponieważ znajduje się poniżej/v1/dogs/{id}
).Teraz każdy przypadek na twojej liście ma określone zachowanie.
1. kora po prostu wysyła e-mail
dog.email
i nic nie rejestruje.Po pierwsze, czy szczekanie (wysyłanie wiadomości e-mail) jest zadaniem synchronicznym czy asynchronicznym? Po drugie, czy
bark
żądanie wymaga jakiegoś dokumentu (może e-mail), czy jest puste?1.1 kora wysyła e-mail do
dog.email
i nic nie rejestruje (jako zadanie synchroniczne)Ta sprawa jest prosta. Wezwanie do
barks
zasobów fabryki powoduje natychmiastowe wyświetlenie kory (wysłanie wiadomości e-mail), a odpowiedź (jeśli jest OK lub nie) jest natychmiast udzielana:Ponieważ nic nie rejestruje (nie zmienia),
200 OK
to wystarczy. Pokazuje, że wszystko poszło zgodnie z oczekiwaniami.1.2 Bark wysyła e-mail
dog.email
i nic nie rejestruje (jako zadanie asynchroniczne)W takim przypadku klient musi mieć możliwość śledzenia
bark
zadania.bark
Następnie zadanie powinno być zasobem z własnym URI .:W ten sposób każdy
bark
jest identyfikowalny. Klient może następnie wydaćGET
nabark
URI, by poznać jego aktualny stan. Może nawet użyj,DELETE
aby to anulować.2. kora wysyła e-mail do,
dog.email
a następnie zwiększadog.barkCount
o 1To może być trudniejsze, jeśli chcesz poinformować klienta, że
dog
zasób zostanie zmieniony:W tym przypadku
location
intencją nagłówka jest poinformowanie klienta, że powinien się przyjrzećdog
. Z HTTP RFC o303
:Jeśli zadanie jest asynchroniczne,
bark
zasób podrzędny jest potrzebny tak jak1.2
sytuacja i303
powinien zostać zwróconyGET .../barks/Y
po zakończeniu zadania.3. Kora tworzy nowy "
bark
" rekord zbark.timestamp
nagraniem, kiedy nastąpiło szczekanie. Zwiększa się równieżdog.barkCount
o 1.Tutaj
bark
jest utworzony w wyniku żądania, więc status201 Created
jest stosowany.Jeśli tworzenie jest asynchroniczne, zamiast tego
202 Accepted
wymagana jest litera ( zgodnie z dokumentem HTTP RFC ).Zapisana sygnatura czasowa jest częścią
bark
zasobu i można ją pobrać za pomocąGET
do. Zaktualizowany pies może być również w tym „udokumentowany”GET dogs/X/barks/Y
.4. bark uruchamia polecenie systemowe, aby pobrać najnowszą wersję kodu psa z Githuba. Następnie wysyła wiadomość tekstową z
dog.owner
informacją, że nowy nieśmiertelnik jest w produkcji.Sformułowanie tego jest skomplikowane, ale jest to w zasadzie proste zadanie asynchroniczne:
Następnie klient wyda
GET
S aby/v1/dogs/1/barks/a65h44
poznać aktualny stan (jeśli kod został wycofany, to adres e-mail został wysłany do właściciela i takie tam). Za każdym razem, gdy pies się zmienia, obowiązuje a303
.Podsumowując
Cytując Roya Fieldinga :
W powyższych przykładach
POST
jest jednolicie zaprojektowany. To sprawi, że pies "bark
". To nie jest bezpieczne (co oznacza, że kora ma wpływ na zasoby), ani idempotentne (każde żądanie daje nowybark
), co dobrze pasuje doPOST
czasownika.Programista będzie wiedział: a
POST
dobarks
dajebark
. Kody statusu odpowiedzi (w razie potrzeby również z treścią encji i nagłówkami) wyjaśniają, co się zmieniło i jak klient może i powinien postępować.Uwaga: Głównymi używanymi źródłami były: książka „ Restful Web Services ”, HTTP RFC i blog Roya Fieldinga .
Edytować:
Pytanie, a tym samym odpowiedź, zmieniły się nieco od czasu ich powstania. Oryginalne pytanie poproszony o projektowaniu URI, takich jak:
Poniżej znajduje się wyjaśnienie, dlaczego nie jest to dobry wybór:
Sposób, w jaki klienci mówią serwerowi, CO ZROBIĆ z danymi, to informacje o metodzie .
KTÓRA CZĘŚĆ danych [klient chce, aby serwer] działała, jest informacją o zakresie .
Jako przykład weźmy identyfikator URI Google
http://www.google.com/search?q=DOG
. Tam znajdują się informacje o metodzieGET
i informacje o zakresie/search?q=DOG
.Krótko mówiąc:
I praktyczna zasada:
Możesz umieścić akcję „bark” w adresie URL (lub w treści encji) i użyć . Nie ma problemu, to działa i może być najprostszym sposobem na zrobienie tego, ale nie jest to RESTful .
POST
Aby Twoja usługa była naprawdę RESTful, być może będziesz musiał cofnąć się o krok i pomyśleć o tym, co naprawdę chcesz tutaj zrobić (jaki wpływ będzie to miało na zasoby).
Nie mogę mówić o twoich konkretnych potrzebach biznesowych, ale pozwól mi podać przykład: Rozważ usługę zamawiania RESTful, w której zamówienia są z identyfikatorami URI
example.com/order/123
.Teraz powiedz, że chcemy anulować zamówienie, jak to zrobimy? Można pokusić się o myślenie, że jest to „działanie” „anulowania ” i zaprojektowanie go jako
POST example.com/order/123?do=cancel
.To nie jest RESTful, jak mówiliśmy powyżej. Zamiast tego możemy
PUT
nową reprezentację elementuorder
zcanceled
elementem wysłanym dotrue
:I to wszystko. Jeśli zamówienia nie można anulować, można zwrócić określony kod statusu. (Dla uproszczenia może być również dostępny projekt zasobów podrzędnych, podobnie jak
POST /order/123/canceled
w przypadku treści encjitrue
).W swoim konkretnym scenariuszu możesz spróbować czegoś podobnego. W ten sposób, gdy na przykład szczeka pies,
GET
at/v1/dogs/1/
może zawierać tę informację (np<barking>true</barking>
. ) . Lub ... jeśli to zbyt skomplikowane, poluzuj swoje wymagania RESTful i trzymaj sięPOST
.Aktualizacja:
Nie chcę, aby odpowiedź była zbyt obszerna, ale zrozumienie algorytmu ( akcji ) jako zestawu zasobów zajmuje trochę czasu . Zamiast myśleć w kategoriach działań ( „poszukaj miejsc na mapie” ), trzeba myśleć kategoriami wyników tego działania ( „lista miejsc na mapie spełniających kryteria wyszukiwania” ).
Może się okazać, że wrócisz do tego kroku, jeśli okaże się, że projekt nie pasuje do jednolitego interfejsu HTTP.
Zmienne zapytania to informacje o zakresie , ale nie oznaczają nowych zasobów (
/post?lang=en
jest to wyraźnie ten sam zasób, co/post?lang=jp
tylko inna reprezentacja). Są raczej używane do przekazywania stanu klienta (na przykład?page=10
stan ten nie jest przechowywany na serwerze;?lang=en
jest to również przykład) lub parametrów wejściowych do zasobów algorytmicznych (/search?q=dogs
,/dogs?code=1
). Ponownie, nie są to odrębne zasoby.Właściwości (metody) czasowników HTTP:
Inną jasną kwestią, która pojawia się
?action=something
w identyfikatorze URI, nie jest RESTful, są właściwości czasowników HTTP:GET
iHEAD
są bezpieczne (i idempotentne);PUT
iDELETE
są tylko idempotentni;POST
Nie jest.Bezpieczeństwo : żądanie
GET
lubHEAD
żądanie to żądanie odczytania niektórych danych, a nie żądanie zmiany stanu serwera. Klient może poprosićGET
lubHEAD
poprosić 10 razy i jest to to samo, co zrobienie tego raz lub nigdy nie .Idempotencja : idempotentna operacja w jednej, która ma ten sam efekt, niezależnie od tego, czy zastosujesz ją raz, czy więcej niż raz (w matematyce mnożenie przez zero jest idempotentne). Jeśli
DELETE
raz otrzymałeś zasób, ponowne usunięcie będzie miało ten sam efekt (zasóbGONE
już jest ).POST
nie jest ani bezpieczny, ani idempotentny. Wysłanie dwóch identycznychPOST
żądań do zasobu „fabryki” prawdopodobnie spowoduje, że dwa podrzędne zasoby będą zawierały te same informacje. W przypadku przeciążenia (metoda w URI lub treść jednostki)POST
wszystkie zakłady są wyłączone.Obie te właściwości były ważne dla powodzenia protokołu HTTP (w zawodnych sieciach!): Ile razy aktualizowałeś (
GET
) stronę bez czekania, aż zostanie w pełni załadowana?Utworzenie akcji i umieszczenie jej w adresie URL wyraźnie łamie kontrakt metod HTTP. Po raz kolejny technologia na to pozwala, możesz to zrobić, ale to nie jest projekt RESTful.
źródło
POST
został zaprojektowany w celu „dostarczania bloku danych ... do procesu przetwarzania danych” . Wydaje się, że wielu ludzi odróżnia zasoby od działań, ale tak naprawdę działania to tylko rodzaj zasobów.POST
„dostarczeniem bloku danych ... do procesu przetwarzania danych”, ale różnica polega na tym, że blok danych , a nie blok danych, a procedura (akcja, metoda, polecenie) ma być stracony wtedy. To jestPOST
przeciążenie, aPOST
przeciążanie to projekt w stylu RPC, a nie REST.I odpowiedział wcześniej , ale ta odpowiedź zaprzecza mój stary odpowiedź i następuje znacznie inną strategię zbliża się do rozwiązania. Pokazuje, jak żądanie HTTP jest zbudowane na podstawie koncepcji definiujących REST i HTTP. Używa również
PATCH
zamiastPOST
lubPUT
.Przechodzi przez ograniczenia REST, następnie składniki HTTP, a następnie możliwe rozwiązanie.
ODPOCZYNEK
REST to zestaw ograniczeń, które mają być zastosowane do rozproszonego systemu hipermediów w celu uczynienia go skalowalnym. Nawet aby nadać temu sens w kontekście zdalnego sterowania akcją, trzeba pomyśleć o zdalnym sterowaniu działaniem jako części rozproszonego systemu hipermedialnego - części systemu służącego do odkrywania, przeglądania i modyfikowania połączonych informacji. Jeśli to więcej kłopotów niż jest to warte, prawdopodobnie nie warto próbować uczynić go RESTful. Jeśli potrzebujesz tylko GUI typu „panel sterowania” na kliencie, który może wyzwalać akcje na serwerze przez port 80, to prawdopodobnie potrzebujesz prostego interfejsu RPC, takiego jak JSON-RPC przez żądania / odpowiedzi HTTP lub WebSocket.
Ale REST to fascynujący sposób myślenia, a przykład w pytaniu jest łatwy do modelowania za pomocą interfejsu RESTful, więc podejmijmy wyzwanie dla zabawy i edukacji.
REST jest definiowany przez cztery ograniczenia interfejsu:
Pytasz, jak zdefiniować interfejs, spełniający te ograniczenia, za pośrednictwem którego jeden komputer każe drugiemu zrobić szczekanie psa. W szczególności chcesz, aby twój interfejs był HTTP i nie chcesz odrzucać funkcji, które sprawiają, że HTTP REST jest używany zgodnie z przeznaczeniem.
Zacznijmy od pierwszego ograniczenia: identyfikacji zasobów .
Zatem pies jest zasobem. Należy go zidentyfikować.
Ci wymodelować psa poprzez zestaw identyfikatorów i przedstawień i mówiąc wszystkie są powiązane ze sobą w danym czasie. Na razie użyjmy identyfikatora „pies # 1”. To prowadzi nas do drugiego i trzeciego ograniczenia: reprezentacji zasobów i samoopisu .
Poniżej znajduje się sekwencja bajtów przechwytująca zamierzony stan psa, tj. Reprezentacja, którą chcemy skojarzyć z identyfikatorem „pies # 1” (zwróć uwagę, że reprezentuje ona tylko część stanu, ponieważ nie uwzględnia imienia psa, stanu zdrowia lub nawet wcześniejsze szczekanie):
Ma być dołączony do opisujących go metadanych. Te metadane mogą być przydatne:
Na koniec spójrzmy na czwarte ograniczenie: HATEOAS .
W interfejsie RESTful klient otrzymuje reprezentację zasobów, aby dowiedzieć się, w jaki sposób powinien odebrać lub wysłać reprezentację. Gdzieś w aplikacji musi znajdować się reprezentacja, z której klient może dowiedzieć się, w jaki sposób odebrać lub wysłać wszystkie oświadczenia, które powinien mieć możliwość odebrania lub wysłania, nawet jeśli po łańcuchu oświadczeń dochodzi do tych informacji. Wydaje się to dość proste:
Klient prosi o przedstawienie zasobu zidentyfikowanego jako strona główna; w odpowiedzi otrzymuje reprezentację zawierającą identyfikator każdego psa, którego może chcieć klient. Klient pobiera z niego identyfikator i pyta obsługę, w jaki sposób może wchodzić w interakcję ze zidentyfikowanym psem, a usługa mówi, że klient może wysłać angielskie oświadczenie opisujące część zamierzonego stanu psa. Następnie klient wysyła takie oświadczenie i otrzymuje komunikat o powodzeniu lub komunikat o błędzie.
HTTP
HTTP implementuje ograniczenia REST w następujący sposób:
identyfikacja zasobu : URI
reprezentacja zasobów : treść jednostki
opis własny : metoda lub kod statusu, nagłówki i ewentualnie części ciała jednostki (np. URI schematu XML)
HATEOAS : hiperłącza
Zdecydowałeś się
http://api.animals.com/v1/dogs/1
na URI. Załóżmy, że klient uzyskał to z jakiejś strony w witrynie.Wykorzystajmy to ciało encji (wartość
next
to znacznik czasu; wartość0
oznacza „kiedy to żądanie zostanie odebrane”):Teraz potrzebujemy metody. PATCH pasuje do opisu „części zamierzonego stanu”, na który się zdecydowaliśmy:
I kilka nagłówków:
Aby wskazać język ciała encji:
Content-Type: application/json
Aby upewnić się, że zdarzy się to tylko raz:
If-Unmodified-Since: <date/time this was first sent>
Mamy prośbę:
Po pomyślnym zakończeniu klient powinien otrzymać
204
w odpowiedzi kod statusu lub,205
jeśli reprezentacja/v1/dogs/1/
zmieniła się, aby odzwierciedlić nowy harmonogram szczekania.W przypadku niepowodzenia powinien otrzymać plik
403
pomocny komunikat dlaczego.REST nie jest niezbędny, aby usługa odzwierciedlała harmonogram korygowania w reprezentacji w odpowiedzi
GET /v1/dogs/1/
, ale najbardziej sensowne byłoby, gdyby reprezentacja JSON obejmowała to:Traktuj zadanie cron jako szczegół implementacji, który serwer ukrywa przed interfejsem. Na tym polega piękno ogólnego interfejsu. Klient nie musi wiedzieć, co serwer robi za kulisami; liczy się tylko to, że usługa rozumie i reaguje na żądane zmiany stanu.
źródło
Większość ludzi używa POST do tego celu . Jest on odpowiedni do wykonywania „wszelkich niebezpiecznych lub nieefektywnych operacji, gdy żadna inna metoda HTTP nie wydaje się odpowiednia”.
Interfejsy API, takie jak XMLRPC, używają POST do wyzwalania akcji, które mogą uruchamiać dowolny kod. „Działanie” jest zawarte w danych POST:
Podano przykład RPC, aby pokazać, że POST jest konwencjonalnym wyborem czasowników HTTP dla metod po stronie serwera. Oto przemyślenia Roya Fieldinga na temat POST - prawie mówi, że użycie metod HTTP zgodnie z opisem jest RESTful.
Zauważ, że samo RPC nie jest bardzo RESTful, ponieważ nie jest zorientowane na zasoby. Ale jeśli potrzebujesz bezpaństwowości, buforowania lub warstwowania, nie jest trudno dokonać odpowiednich transformacji. Na przykład patrz http://blog.perfectapi.com/2012/opinionated-rpc-apis-vs-restful-apis/ .
źródło
POST api.animals.com/v1/dogs1?action=bark
/RPC2
nie robi nic w celu zidentyfikowania zasobu - identyfikuje technologię serwera. Zamiast tegomethodName
próbuje „zidentyfikować” „zasób” - ale nawet wtedy nie korzysta z rozróżnienia rzeczownik / czasownik; jedyną rzeczą podobną do „czasownika” jest tutajmethodCall
. To jest jak „pobieranie nazwy stanu” zamiast „pobieranie nazwy stanu” - to drugie ma o wiele więcej sensu.POST
to metoda HTTP zaprojektowana dlaMetody po stronie serwera obsługujące akcje niezamapowane na CRUD są tym, co Roy Fielding zamierzał w REST, więc jesteś w tym dobry i dlatego
POST
został stworzony, aby nie był idempotentny.POST
obsłuży większość wysyłania danych do metod po stronie serwera w celu przetwarzania informacji.To powiedziawszy, w scenariuszu szczekania psa, jeśli chcesz, aby szczekanie po stronie serwera było wykonywane co 10 minut, ale z jakiegoś powodu potrzebujesz wyzwalacza pochodzącego od klienta,
PUT
lepiej służyłoby temu celowi ze względu na jego idempotencję. Cóż, ściśle według tego scenariusza nie ma wyraźnego ryzyka, że wiele żądań POST spowoduje zamiast tego miauczenie twojego psa, ale tak czy inaczej, to jest celem dwóch podobnych metod. Moja odpowiedź na podobne pytanie SO może być dla Ciebie przydatna.źródło
PUT
adres URL odnosi się do tego, co powinno zostać zastąpione treścią klienta, aPOST
adres URL odnosi się do tego, co powinno przetwarzać zawartość klienta, jak chce.Jeśli założymy, że szczekanie jest zasobem wewnętrznym / zależnym / podrzędnym, na którym konsument może działać, możemy powiedzieć:
pies numer 1 szczeka
zwraca ostatni znacznik czasu kory
nie dotyczy! więc zignoruj to.
źródło
/v1/dogs/1/bark
jest to zasób per se iPOST
ma być opisem tego, jak powinien zmienić się stan wewnętrzny tego zasobu. Uważam, że bardziej sensowne jest rozważenie tego/v1/dogs/1/
jako zasobu i wskazanie w ciele istoty, że powinno szczekać.Wcześniejsze wersje niektórych odpowiedzi sugerowały użycie RPC. Nie trzeba patrzeć na RPC, ponieważ jest całkiem możliwe, aby robić to, co chcesz jednoczesnym przestrzeganiu ograniczeń resztę.
Po pierwsze, nie umieszczaj parametrów akcji w adresie URL. Adres URL określa, do czego wykonujesz akcję, a parametry zapytania są częścią adresu URL. Powinien być traktowany w całości jako rzeczownik.
http://api.animals.com/v1/dogs/1/?action=bark
to inny zasób - inny rzeczownik - tohttp://api.animals.com/v1/dogs/1/
. [nb Asker usunął?action=bark
identyfikator URI z pytania.] Na przykład porównajhttp://api.animals.com/v1/dogs/?id=1
zhttp://api.animals.com/v1/dogs/?id=2
. Różne zasoby, rozróżniane tylko na podstawie ciągu zapytania. Zatem akcja żądania, chyba że bezpośrednio odpowiada bezcielesnemu typowi metody (TRACE, OPTIONS, HEAD, GET, DELETE, itp.) Musi być zdefiniowana w treści żądania.Następnie zdecyduj, czy działanie jest „ idempotentne ”, co oznacza, że można je powtórzyć bez negatywnych skutków (więcej wyjaśnień znajduje się w następnym akapicie). Na przykład ustawienie wartości na true może zostać powtórzone, jeśli klient nie jest pewien, czy nastąpił pożądany efekt. Wysyłają żądanie ponownie, a wartość pozostaje prawdziwa. Dodanie 1 do liczby nie jest idempotentne. Jeśli klient wysyła polecenie Add1, nie jest pewien, czy zadziałało, i wysyła je ponownie, czy serwer dodał jedną lub dwie? Kiedy już to ustalisz, będziesz mieć lepszą pozycję do wyboru pomiędzy
PUT
iPOST
dla swojej metody.Idempotentne oznacza, że żądanie można powtórzyć bez zmiany wyniku. Efekty te nie obejmują logowania i innych podobnych działań administratora serwera. Korzystając z pierwszego i drugiego przykładu, wysłanie dwóch e-maili do tej samej osoby skutkuje innym stanem niż wysłanie jednego e-maila (odbiorca ma dwa w swojej skrzynce odbiorczej, które mogą uznać za spam), więc zdecydowanie użyłbym do tego POST . Jeśli barkCount w przykładzie 2 ma być widziany przez użytkownika twojego API lub wpływa na coś, co jest widoczne dla klienta, jest to również coś, co sprawi, że żądanie nie będzie idempotentne. Jeśli ma być przeglądany tylko przez Ciebie, liczy się jako logowanie do serwera i powinien być ignorowany podczas określania idempotencji.
Na koniec określ, czy można oczekiwać, że akcja, którą chcesz wykonać, zakończy się natychmiastowym sukcesem, czy nie. BarkDog to szybko zaliczająca się akcja. RunMarathon nie jest. Jeśli twoja akcja jest powolna, rozważ zwrócenie a
202 Accepted
, z adresem URL w treści odpowiedzi, aby użytkownik mógł odpytać, czy akcja została zakończona. Alternatywnie, poproś użytkowników POST do adresu URL listy,/marathons-in-progress/
a następnie po zakończeniu akcji przekieruj ich z adresu URL identyfikatora w toku na adres/marathons-complete/
URL.W szczególnych przypadkach # 1 i # 2 serwer powinien hostować kolejkę, a klient wysyłał do niej partie adresów. Akcją nie byłoby SendEmails, ale coś w rodzaju AddToDispatchQueue. Serwer może następnie odpytać kolejkę, aby sprawdzić, czy są jakieś oczekujące adresy e-mail i wysłać e-maile, jeśli je znajdzie. Następnie aktualizuje kolejkę, aby wskazać, że oczekująca akcja została wykonana. Miałbyś inny identyfikator URI pokazujący klientowi bieżący stan kolejki. Aby uniknąć podwójnego wysyłania wiadomości e-mail, serwer może również przechowywać dziennik, do którego wysłał tę wiadomość e-mail i sprawdzać każdy adres, aby upewnić się, że nigdy nie wyśle dwóch na ten sam adres, nawet jeśli POSTAWASZ tę samą listę dwa razy do kolejka.
Wybierając identyfikator URI do czegokolwiek, staraj się myśleć o nim jako wyniku, a nie akcji. Na przykład
google.com/search?q=dogs
pokazuje wyniki wyszukiwania słowa „psy”. Nie ma konieczności wykonywania wyszukiwania.Przypadki # 3 i # 4 z Twojej listy również nie są działaniami idempotentnymi. Sugerujesz, że różne sugerowane efekty mogą wpłynąć na projekt interfejsu API. We wszystkich czterech przypadkach użyłbym tego samego interfejsu API, ponieważ wszystkie cztery zmieniają „stan świata”.
źródło
Zobacz moją nową odpowiedź - zaprzecza tej i wyjaśnia REST i HTTP jaśniej i dokładniej.
Oto zalecenie, które jest RESTful, ale z pewnością nie jest jedyną opcją. Aby rozpocząć szczekanie, gdy usługa otrzyma żądanie:
token
to dowolna liczba, która zapobiega zbędnym szczekaniu bez względu na to, ile razy to żądanie jest wysyłane.next
wskazuje czas następnej kory; wartość0
oznacza „JAK NAJSZYBCIEJ”.Zawsze
GET /v1/dogs/1/bark-schedule
powinieneś dostać coś takiego, gdzie t to czas ostatniego szczekania i U jest t + 10 minut:{"last": t, "next": u}
Zdecydowanie zalecam użycie tego samego adresu URL do zażądania szczekania, którego używasz do sprawdzenia aktualnego stanu szczekania psa. Nie jest to niezbędne dla REST, ale podkreśla akt modyfikowania harmonogramu.
Odpowiedni kod statusu to prawdopodobnie 205 . Wyobrażam sobie klienta, który patrzy na bieżący harmonogram
POST
pod ten sam adres URL, aby go zmienić, i jest instruowany przez usługę, aby ponownie spojrzał na harmonogram, aby udowodnić, że został zmieniony.Wyjaśnienie
ODPOCZYNEK
Zapomnij na chwilę o HTTP. Ważne jest, aby zrozumieć, że zasób to funkcja, która wymaga czasu jako danych wejściowych i zwraca zestaw zawierający identyfikatory i reprezentacje . Uprośćmy to, aby: zasób to zbiór R identyfikatorów i reprezentacji; R może się zmieniać - członków można dodawać, usuwać lub modyfikować. (Chociaż to zły, niestabilny projekt usuwania lub modyfikowania identyfikatorów.) Mówimy, że identyfikator będący elementem R identyfikuje R , a reprezentacja będąca elementem R oznacza R .
Powiedzmy, że R to pies. Zdarza Ci się zidentyfikować R jako
/v1/dogs/1
. (Czyli/v1/dogs/1
jest członkiem R ). To tylko jeden z wielu sposobów można zidentyfikować R . Możesz również zidentyfikować R jako/v1/dogs/1/x-rays
i jako/v1/rufus
.Jak reprezentujesz R ? Może ze zdjęciem. Może z zestawem promieni rentgenowskich. A może ze wskazaniem daty i godziny ostatniego szczekania R. Pamiętaj jednak, że są to wszystkie reprezentacje tego samego zasobu .
/v1/dogs/1/x-rays
jest identyfikatorem tego samego zasobu, który jest reprezentowany przez odpowiedź na pytanie "kiedy R ostatnio szczekał?"HTTP
Wielokrotne reprezentacje zasobu nie są zbyt przydatne, jeśli nie możesz odnieść się do tego, który chcesz. Dlatego HTTP jest użyteczny: pozwala łączyć identyfikatory z reprezentacjami . Oznacza to, że jest to sposób, aby usługa otrzymała adres URL i zdecydowała, która reprezentacja ma być dostarczona klientowi.
A przynajmniej tak jest
GET
.PUT
jest w zasadzie odwrotnościąGET
: youPUT
a reprezentacja r pod adresem URL, jeśli chcesz, aby przyszłeGET
żądania do tego adresu URL zwracały r , z pewnymi możliwymi tłumaczeniami, takimi jak JSON na HTML.POST
to luźniejszy sposób modyfikowania reprezentacji. Pomyśl o logice wyświetlania i logice modyfikacji, które są sobie odpowiednikami - obie odpowiadają temu samemu adresowi URL. Żądanie POST to żądanie logiki modyfikacji w celu przetworzenia informacji i zmodyfikowania wszelkich reprezentacji (nie tylko reprezentacji znajdujących się pod tym samym adresem URL), jakie usługa uzna za stosowne. Zwróć uwagę na trzeci akapit po 9.6 PUT : nie zastępujesz rzeczy pod adresem URL nową treścią; prosisz rzecz pod adresem URL o przetworzenie pewnych informacji i inteligentną odpowiedź w formie reprezentacji informacyjnych.W naszym przypadku prosimy o logikę modyfikacji w
/v1/dogs/1/bark-schedule
(która jest odpowiednikiem logiki wyświetlania, która mówi nam, kiedy ostatnio szczekał i kiedy będzie ponownie szczekał) o przetworzenie naszych informacji i odpowiednie zmodyfikowanie niektórych reprezentacji. W odpowiedzi na przyszłeGET
błędy logika wyświetlania odpowiadająca temu samemu adresowi URL powie nam, że pies szczeka teraz tak, jak chcemy.Potraktuj zadanie crona jako szczegół implementacji. HTTP zajmuje się przeglądaniem i modyfikowaniem reprezentacji. Od tej chwili obsługa poinformuje klienta, kiedy ostatnio szczekał pies i kiedy będzie następny. Z punktu widzenia usługi jest to uczciwe, ponieważ te czasy odpowiadają przeszłym i planowanym zadaniom crona.
źródło
REST jest standardem zorientowanym na zasoby i nie jest oparty na działaniu, jak byłoby to RPC.
Jeśli chcesz, aby Twój serwer szczekał , powinieneś przyjrzeć się różnym pomysłom, takim jak JSON-RPC lub komunikację w gniazdach internetowych.
Moim zdaniem każda próba zachowania RESTful zakończy się niepowodzeniem: możesz wydać
POST
zaction
parametrem, nie tworzysz żadnych nowych zasobów, ale ponieważ możesz mieć skutki uboczne, jesteś bezpieczniejszy.źródło
POST
został zaprojektowany w celu „dostarczania bloku danych… do procesu przetwarzania danych” . Wydaje się, że wielu ludzi odróżnia zasoby od działań, ale tak naprawdę działania to tylko rodzaj zasobów. Wywołanie zasobu akcji na serwerze jest nadal jednolitym interfejsem, buforowalnym, modułowym i skalowalnym. Jest również bezstanowy, ale może zostać naruszony, jeśli klient ma oczekiwać odpowiedzi. Ale wywołanie „metody void” na serwerze jest tym, co zamierzał Roy Fielding w przypadku REST .