Не-CRUD-операції в службі RESTful


106

Який "RESTful" спосіб додавання не-CRUD-операцій до служби RESTful? Скажіть, у мене є служба, яка дозволяє CRUD отримати доступ до таких записів:

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

Якщо я хочу змінити колір автомобіля, я б просто POST /api/car/123включив змінну POST для нового кольору.

Але скажімо, що я хочу придбати автомобіль, і ця операція є складнішою, ніж просто оновлення власності "власного автомобіля" запису "користувача". Чи РЕЗЕМНО просто робити щось на кшталт POST /api/car/123/purchase, де "покупка" - це по суті назва методу? Або я повинен використовувати користувацьке дієслово HTTP, наприклад PURCHASEзамість POST?

Або операції, що не стосуються CRUD, повністю виходять за рамки REST?


5
Якщо ви змінюєте колір автомобіля, було б краще використовувати PATCH /api/car/123і надіслати кольоровий параметр АБО використовувати PUT /api/car/123та відправити весь автомобільний об’єкт. POST може зробити висновок про те, що ви створюєте новий автомобіль і, ймовірно, ніколи не повинен містити ідентифікатор в кінці URL
RonnyKnoxville,

Відповіді:


65

Подумайте про придбання як суб’єкт господарювання чи ресурс у словнику RESTful. За словами, покупка - це фактично створення нового ресурсу. Так:

POST /api/purchase

оформить нове замовлення. Дані (користувач, автомобіль тощо) повинні посилатися на id (або URI) всередині вмісту, надісланого на цю адресу.

Не має значення, що замовлення автомобіля - це не просто ВСТАНОВЛЕННЯ в базі даних. Власне, REST не полягає у викритті таблиць вашої бази даних як операціях CRUD. З логічної точки зору ви створюєте замовлення (покупку), але сторона сервера вільна зробити стільки кроків обробки, скільки хоче.

Ви можете навіть зловживати протоколом HTTP ще більше. Використовуйте Locationзаголовок, щоб повернути посилання на новостворене замовлення, обережно виберіть коди відповідей HTTP, щоб повідомити користувачів про проблеми (на сервері чи клієнті) тощо.


3
REST - це маніпулювання станом ресурсів, і кожна бізнес-операція повинна бути віднесена до стану CRUD-операцій. Якщо вам потрібна складна семантика ділових операцій, вам доведеться пройти шлях SOAP (SOAP насправді передає повідомлення, але, як правило, організовується в операціях з відповіддю на запит).
Томаш Нуркевич

23
Дизайн "покупка як ресурс" виглядає акуратно. Що робити, якщо ресурс - це "пиво" .. і я хочу, щоб сервер його випив .. (це було для мене, я б точно отримав його;)) .. чи слід розглядати "випиваючу дію" як ресурс ?! .. чи це "пити пиво", важка ділова операція ?! Більш серйозно, чи РЕЗЕЛЬНА конструкція щодо розгляду дій як ресурсів?! ..
Myobis

2
Як би ви піддавали "схвалення замовлення на купівлю" через послугу REST? Я думаю, що @TomaszNurkiewicz має рацію в тому, що все, що неможливо акуратно зробити CRUD-способом, потребує оперативної семантики, наданої SOAP. Якщо "затвердження замовлення на купівлю" не є власною моделлю / об'єктом. Наприклад, POST / po-затвердження (з деталями PO у запиті).
mydoghasworms

2
З точки зору клієнта REST, "схвалити замовлення на купівлю" повинно бути лише ще одним оновленням замовлення. Наприклад, змініть "Затверджено" на "Істинне" та надішліть оновлення на сервер. Сервер, ймовірно, повинен зробити купу перевірок, і, ймовірно, йому знадобиться оновити / створити купу інших ресурсів. Але це проблема серверів, і вона не повинна бути помітна клієнту.
AVee

2
@antinome: "Припустимо, клієнт знає щось із цього", якщо це так, якщо ви не робите REST (можливо, все-таки це дійсне, розумне програмне забезпечення!). REST був розроблений так, щоб можна було створювати клієнтів, які цього не знають, створювати клієнтів, які все ще працюють, якщо поведінка сервера змінюється. Те, що ви намагаєтеся зробити, це класичний RPC, вам або потрібно переглянути свій підхід, щоб він відповідав REST, або прийняти, що ви робите RPC, і використовувати протокол, призначений для RPC, як SOAP. REST дуже намагається не бути RPC, тому це ніколи не буде добре підходити, коли хочеш / потребуєш RPC.
AVee

15

НАЙКРАЩИЙ спосіб, наскільки я розумію, це те, що вам не потрібні нові дієслова HTTP, десь є іменник, який буде означати, що вам потрібно зробити.

Придбати машину? Ну не це

POST /api/order

2
Чи не використовується PUT для оновлення ресурсів, оскільки він ідентичний? Це означає, що ви можете зателефонувати йому стільки разів, скільки вам потрібно, але важливим є лише перший / останній дзвінок. З іншого боку, POST використовується для створення ресурсів, а виклик його два рази фактично повинен створити два.
Томаш Нуркевич

1
@Tomas, так, друкарня. Принцип важливий, хоча ми маємо справу з новою річчю, наказом, немає потреби у новому дієслові.
djna

5

Те, що ви насправді робите, - це створення замовлення. Тож додайте ще один ресурс для замовлення та публікації та поставте його під час процесу замовлення.

Подумайте з точки зору ресурсів, а не з викликів методів.

Для завершення замовлення ви, ймовірно, POST / api / order // завершуєте чи щось подібне.


3

Я думаю, що API REST допомагають набагато більше способів, ніж просто надання семантики. Тому не можна вибирати стиль RPC лише через деякі дзвінки, які, здається, мають більше сенсу в стилі роботи RPC. Прикладом є програми Google Maps api, щоб знайти напрямки між двома місцями. Виглядає так: http://maps.googleapis.com/maps/api/directions/json?origin=Jakkur&destination=Hebbal

Вони могли назвати це "findDirections" (дієсловом) і трактували це як операцію. Швидше вони робили "направлення" (іменник) як ресурс і трактували пошук напрямів як запит на ресурс напрямків (Хоча внутрішньо не могло бути реального ресурсу, який називається напрямом, і його можна було реалізувати за допомогою бізнес-логіки для пошуку напрямків на основі парам).


Це поганий приклад. У цьому випадку напрямки (усі можливі напрямки, нескінченна їх кількість) є ресурсом, а параметри - це лише фільтри. Але ви не можете зробити "покупку" з цим, оскільки фільтри мають сенс лише отримати операції та оформити замовлення або скасувати це операції, які змінюють дані
Tseng

2
покупка буде POST для / замовлення з json в тілі, щоб вказати, що замовлення створено. Скасувати буде PUT для / замовлення з json, що містить зміну стану замовлення, щоб вказати, що це ідентичне потенційне оновлення. Я все ще натрапляю на операцію, яка не може бути виражена у форматі ресурсу. Тож хотілося б побачити подібний приклад
Маруті
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.