Operacje inne niż CRUD w usłudze RESTful

106

Jaki jest „RESTful” sposób dodawania operacji innych niż CRUD do usługi RESTful? Powiedzmy, że mam usługę, która umożliwia CRUD dostęp do takich rekordów:

GET /api/car/123           <- Returns information for the Car object with ID 123
POST /api/car              <- Creates a new car (with properties in the request)
PUT /api/car/123           <- Updates car 123 (with properties in the request)
DELETE /api/car/123        <- Deletes car 123    
POST /api/car/123/wheel/   <- Creates a wheel and associates it to car 123

Gdybym chciał zmienić kolor auta, po prostu POST /api/car/123dodałbym zmienną POST dla nowego koloru.

Ale powiedzmy, że chcę kupić samochód, a ta operacja jest bardziej skomplikowana niż zwykła aktualizacja właściwości „posiadanego samochodu” w rekordzie „użytkownika”. Czy RESTful jest po prostu zrobić coś takiego POST /api/car/123/purchase, gdzie „zakup” jest w istocie nazwą metody? A może powinienem użyć niestandardowego czasownika HTTP, na przykład PURCHASEzamiast POST?

A może operacje inne niż CRUD są całkowicie poza zakresem REST?

MikeWyatt
źródło
5
Jeśli zmieniasz kolor samochodu, lepiej byłoby użyć PATCH /api/car/123i wysłać parametr koloru LUB użyć PUT /api/car/123i wysłać cały obiekt samochodu. POST wywnioskowałby, że tworzysz nowy samochód i prawdopodobnie nigdy nie powinien zawierać identyfikatora na końcu adresu URL
RonnyKnoxville

Odpowiedzi:

65

Pomyśl o zakupie jak o jednostce biznesowej lub zasobie w słowniku RESTful. Biorąc to pod uwagę, dokonanie zakupu w rzeczywistości tworzy nowy zasób. Więc:

POST /api/purchase

złoży nowe zamówienie. Szczegóły (użytkownik, samochód itp.) Powinny być przywoływane przez id (lub URI) w treści przesyłanej na ten adres.

Nie ma znaczenia, że ​​zamówienie samochodu to nie tylko zwykłe WSTAWIENIE w bazie danych. W rzeczywistości REST nie polega na ujawnianiu tabel bazy danych jako operacji CRUD. Z logicznego punktu widzenia tworzysz zamówienie (zakup), ale strona serwera może wykonać dowolną liczbę kroków przetwarzania.

Możesz nawet dalej nadużywać protokołu HTTP. Użyj Locationnagłówka, aby zwrócić link do nowo utworzonego zamówienia, uważnie wybierz kody odpowiedzi HTTP, aby poinformować użytkowników o problemach (po stronie serwera lub klienta) itp.

Tomasz Nurkiewicz
źródło
3
REST polega na manipulowaniu stanem zasobów, a każda operacja biznesowa musi być odwzorowana na stanowe operacje CRUD. Jeśli potrzebujesz twardej semantyki operacji biznesowych, musisz iść drogą SOAP (SOAP jest w rzeczywistości przekazywaniem komunikatów, ale zazwyczaj jest zorganizowany w operacje żądanie-odpowiedź).
Tomasz Nurkiewicz
23
Projekt „Zakup jako zasób” wygląda schludnie. Co jeśli zasobem jest „piwo”… i chcę, aby serwer je wypił… (to było dla mnie, na pewno bym to ZROBIŁ;)) .. czy powinniśmy traktować „akcję picia” jako zasób ?! .. czy „picie piwa” to ciężka operacja biznesowa?! A poważniej, czy projekt RESTful traktuje działania jako zasoby?! ..
Myobis,
2
Jak ujawniłbyś „Zatwierdź zamówienie” za pośrednictwem usługi REST? Myślę, że @TomaszNurkiewicz ma rację, że wszystko, czego nie da się zgrabnie zrobić w sposób CRUD, będzie wymagało semantyki operacji zapewnianej przez SOAP. Chyba że „zatwierdzenie zamówienia” jest samodzielnym modelem / podmiotem. Np. Zatwierdzenie POST / po (ze szczegółami PO w żądaniu).
mydoghasworms
2
Z punktu widzenia klienta REST „zatwierdzenie zamówienia” powinno być kolejną aktualizacją zamówienia. Np. Zmień „Zatwierdzone” na „prawda” i wyślij aktualizację do serwera. Serwer prawdopodobnie będzie musiał wykonać kilka testów i prawdopodobnie będzie musiał zaktualizować / utworzyć kilka innych zasobów. Ale to jest problem z serwerami i nie powinien być widoczny dla klienta.
AVee
2
@antinome: „Załóżmy, że klient coś o tym wie”, jeśli tak jest w przypadku, gdy nie robisz REST (może to być nadal prawidłowe, ale rozsądne oprogramowanie!). REST został zaprojektowany, aby móc tworzyć klientów, którzy nie wiedzą tego typu rzeczy, aby tworzyć klientów, którzy nadal będą działać, jeśli zmieni się zachowanie serwera. To, co próbujesz zrobić, to klasyczne RPC, musisz albo przejrzeć swoje podejście, aby pasowało do REST, albo zaakceptować, że robisz RPC i używasz protokołu przeznaczonego dla RPC, takiego jak SOAP. REST bardzo się stara, aby nie być RPC, więc nigdy nie będzie dobrym rozwiązaniem, gdy chcesz / potrzebujesz RPC.
AVee
15

REST, jak rozumiem, polega na tym, że nie potrzebujesz nowych czasowników HTTP, gdzieś jest rzeczownik, który będzie oznaczał to, co musisz zrobić.

Kupujesz samochód? Cóż, nie jest to

POST /api/order
djna
źródło
2
Czy PUT nie jest używany do aktualizowania zasobów, ponieważ jest idempotentny? Oznacza to, że możesz dzwonić do niego tyle razy, ile chcesz, ale ważne jest tylko pierwsze / ostatnie połączenie. Z drugiej strony POST jest używany do tworzenia zasobów, a dwukrotne wywołanie go powinno w rzeczywistości utworzyć dwa.
Tomasz Nurkiewicz
1
@Tomas, tak, literówka. Zasada jest jednak ważna, mamy do czynienia z nową rzeczą, porządkiem, nie potrzeba nowego czasownika.
djna
5

To, co naprawdę robisz, to tworzenie zamówienia. Więc dodaj kolejny zasób do zamówienia i opublikuj i umieść tam podczas procesu zamówienia.

Myśl w kategoriach zasobów, a nie wywołań metod.

Aby sfinalizować zamówienie, prawdopodobnie POST / api / order // ukończone lub coś podobnego.

Andrew Kothmann
źródło
3

Uważam, że interfejsy API REST pomagają na wiele więcej sposobów niż tylko zapewnianie semantyki. Nie można więc wybrać stylu RPC tylko z powodu niektórych wywołań, które wydają się mieć większy sens w stylu obsługi RPC. Przykładem jest interfejs API map Google do znajdowania wskazówek między dwoma miejscami. Wygląda tak: http://maps.googleapis.com/maps/api/directions/json?origin=Jakkur&destination=Hebbal

Mogli nazwać to „findDirections” (czasownik) i potraktować jako operację. Zamiast tego uczynili „kierunek” (rzeczownik) jako zasób i traktowali znajdowanie kierunków jako zapytanie o zasób kierunków (chociaż wewnętrznie nie może istnieć żaden prawdziwy zasób zwany kierunkiem i można go zaimplementować w logice biznesowej, aby znaleźć kierunki na podstawie parametrów).

Maruthi
źródło
To zły przykład. W tym przypadku kierunki (wszystkie możliwe kierunki, nieskończona ich liczba) są zasobami, a parametry to tylko filtry. Ale nie możesz z tym zrobić „zakupu”, ponieważ filtry mają sens tylko w przypadku operacji pobierania, a składanie zamówienia lub anulowanie to operacje, które zmieniają dane
Tseng,
2
zakup to POST to / order z plikiem JSON w treści wskazującym, że zamówienie zostało utworzone. Anulowanie byłoby PUT do / order z json przenoszącym zmianę stanu zamówienia, aby wskazać, że jest to idempotentna aktualizacja. Nadal mam do czynienia z operacją, której nie można wyrazić w formacie zasobu. Chciałbym więc zobaczyć taki przykład
Maruthi