Представляють дії (дієслова) в URI REST


16

У мене є операція друку для виконання документів для клієнта. Мені потрібні й інші стандартні операції, які можна виконати, як-от додавання, оновлення, видалення. Отже, у мене є наступне:

  • Для створення нового клієнта:
    URI = / customer / {id}, введіть = POST, Name Name = CreateCustomer ()
  • Для оновлення:
    URI: / customer / {id}, введіть = PUT, method = UpdateCstomer ()
  • Для видалення клієнта:
    URI = / customer / {id}, введіть = DELETE, ім'я методу = DeleteCustomer ()
  • Для перегляду:
    URI: / customer / {id}, введіть = GET, method = GetCustomer ()

Тепер, якщо мені потрібно роздрукувати документ для цього замовника, мені потрібна функція друку. Мій URI може виглядати так: / customer / {id}, type = POST, method = PrintCustomer (). Але я використав цей тип URI та POST для CreateCustomer. Я хотів, щоб URI виглядав так: / customer / Print / {id}, type = POST, method = PrintCustomer ().

Але я не можу мати в своєму URI дієслово "Друк". Який найкращий спосіб зробити це? Я думав про / customer / document / {id} як URI ... але я зіткнуся з тією ж проблемою. У мене були б операції CRUD над "документом". Отже, знову закінчується те, що я використовував би для «друку». Порадьте, будь ласка.


2
Друк - це звичайно операція на стороні клієнта, тому мені цікаво - як ваша установка така, що вимагає від вас відправити команду на сервер REST?
Шауна

2
@Shauna Не обов'язково URI може бути запитом до сервера для друкованої версії ресурсу (тобто іншого вигляду).
Еван Плейс

1
@EvanPlaice - досить справедливо, хоча це все ще залишає акт друку клієнту (який, навіть після отримання зручної для сервера версії для друку, потім вирішить, на який пристрій надрукувати та відправити команду друку, навіть якщо це команда переходить до сервера друку). Запит на отримання зручної для друку версії ресурсу тоді логічно був би ... ну ... GET.
Шауна

@Shauna Запуск завдання друку лише з HTTP-запиту було б неможливим через захист браузера. Запит на зручну для друку версію - це лише GET-запит, але все ще потрібен спосіб вказати, що браузер повинен надавати версію для друку. Ви можете вказати іншу URL-адресу, але це порушило б принципи REST, оскільки ви насправді не вимагаєте іншого ресурсу, а лише іншого перетворення того ж ресурсу. Звідси причина визначення перетворення через запит-параметр та / або тип вмісту.
Еван Плейс

У мене немає достатньої кількості представників для публікації як відповідь, але мені здається цікавим, що tyk.io/rest-never-crud стверджує, що POST /customers/123/printце дійсно.
jlh

Відповіді:


9

POSTне означає "створити", це означає "обробити". Ви можете створити новий ресурс, розмістивши відповідний запит на вже наявному ресурсі (наприклад, повідомлення /customersдля створення нового клієнта). Але ви також POSTможете заповнити всі інші дії, які не відповідають чіткій парадигмі CRUD.

Що стосується друку, ви повинні розглядати акт друку як сам ресурс. Ви просите систему створити для вас "завдання друку". Це означає, що ви можете мати prints/ресурс, який виконує функцію контейнера для всіх запитів, які вимагаються. Коли ви хочете надрукувати щось, що ви POSTдокумент, на цей ресурс, який містить всю інформацію про роздруківку, яку ви хочете створити, ідентифікуючи ресурси, які ви бажаєте роздрукувати, за допомогою посилань на них.

Як документ JSON, це може виглядати так:

{
   contents: ["http://site/customers/12345"],
   paper-size: "A4",
   duplex: "true"
}

Очевидно, вам потрібно налаштувати це так, щоб відповідати тому, що ви хочете зробити. Найголовніше - ви визначаєте інші ресурси для друку, вказуючи їх URL.

У відповідь на запит ви можете просто повернути a 200 OKчи a 204 No-Contentі розглянути його як процес пожежі та забуття. Однак, якщо ви хочете його покращити, ви можете повернутись 201 Createdі вказати URL новоствореного завдання друку, наприклад /prints/12345.

Потім користувач може виконати GETна ресурсі, щоб побачити статус своєї завдання друку (очікує на розгляд, незавершений процес тощо), або може попросити скасувати завдання, видавши а DELETE.

Коли ви перефразовуєте проблему з точки зору ресурсу, дизайн RESTful повинен вийти природним чином і дати вам можливість розширюватись і вдосконалюватись способами, які ви, можливо, не відразу розглянули.


2
POST зазвичай означає створити / вставити, тоді як ставити зазвичай означає збереження / оновлення оновлення. Ось як це визначено в REST, навіть якщо це не так, як зазвичай використовується в HTML.
Еван Плейс

2
@EvanPlaice специфікація HTTP називає PUT як дієсловом створення / оновлення (він використовує модель create + update замість більш звичного create + retrieve + update), а POST - дієслово "обробка даних", а також дієслово "додавати" . Рой Філдінг у своєму блозі описав POST як дієслово, яке слід використовувати, коли ви не хочете стандартизувати операцію. POST набуває "створення" семантики, коли ви вважаєте, що додає новий елемент до колекції предметів. У цьому випадку трагедієць вдарив цвяхом по голові, використовуючи POST для обробки або додавання завдання друку.
Роб

@RobY Добре, це має сенс. Як приклад, PUT може бути використаний для представлення SPROC, призначеного для введення даних у базу даних. В той час, як POST може скласти проміжні кроки та мутації, необхідні для збору / підготовки цих даних. Дизайн операції POST може змінюватися або замінюватися в міру розвитку дизайну, але операції PUT являють собою модель, яка (в ідеалі) не повинна змінюватися. Я б оновив свою відповідь, але цей вже чудово справляється з поясненням різниці.
Еван Плейс

4

Я робив це раніше. Для друку документа я просто повертаю pdf-версію ресурсу. Клієнту потрібно лише надіслати GET-запит на ресурс із програмою Accept header / pdf.

Це також уникає створення нового URI для тимчасових ресурсів, таких як завдання друку. Використання заголовка HTTP також є частиною REST, і він підтримує чистий URI.


3

Просто додайте параметр до GET поточного URI

Досить типово використовувати URI для декількох дій.

Якщо ви говорите про один і той же ресурс, але про іншу дію, ви визначите його як параметр.

/ customer / {id}? print = true

Тоді, де ви визначаєте свій метод GET, ви виявляєте наявність параметра друку та обробляєте його по-різному.

REST визначається наступним чином:

  • POST - Створення запису, об’єкту або ресурсу
  • PUT - оновлення, запис, актив або ресурс
  • DELETE - Видаліть, записуйте, об’єкт або ресурс

З іншого боку, GET призначений для використання декількома способами, оскільки зазвичай існує багато різних форм, з яких ресурс може бути отриманий. Ось чому запити GET представлені у вигляді рядка запиту. Якщо ви працювали з ресурсом бази даних, ви буквально отримували б представлення даних за допомогою запиту, але REST навмисно абстрагується на більш високий рівень, оскільки він призначений для обробки багатьох різних типів ресурсів.

Специфікація REST є досить перспективною, хоча API лише недавно починають активно її використовувати.

Якщо вам цікаво дізнатися більше про протоколи REST, я настійно пропоную вам прочитати " Haters Gonna Hate HATEOAS ".


Оновлення:

@Shauna вказав на цікаву дірку в моїх міркуваннях. Не існує справжнього правильного шляху, і багато форм вважаються прийнятними. Я дещо подумав над цим, і оскільки ваше призначення призначене для перетворення даних у інше представлення, має сенс визначити перетворення як новий тип MIME.

Наприклад, ви можете представити URI як:

/customer/{id}+print

Де ви могли встановити відповідь Content-Type на текст / html + print. Таким чином, ви також матимете можливість визначити більше перетворень у майбутньому.

Наприклад:

// for application/json
/customer/{id}+json

// for application/atom+xml
/customer/{id}+atom

У будь-якому випадку всі форми прийнятні. Реалізація, яку ви вирішите, більше залежить від особистих переваг та можливостей вашого сервера.

У бік: Дозвольте уточнити, оскільки, здається, існує деяка плутанина. Параметр запиту 'print' та / або тип вмісту використовується для визначення способу перетворення ресурсу. Не як запустити фізичне завдання друку. З міркувань безпеки доступ на апаратному рівні завжди залишається користувачеві / клієнту / браузеру.


Щоб додати - як альтернатива використанню рядка запиту ( ?print=true), ви також можете використовувати параметри URI (тобто - /customer/{id}/printable). Те, яке ви використовуєте, багато в чому залежатиме від стандартної системи (CMS, фреймворк, код взагалі), створеної для обробки. Обидва вважаються дійсними та прийнятними .
Шауна

@Shauna Технічно кращим підходом було б використання типу MIME, специфічного для друку з URI '/ customer / {id} + print' та MIME-тип відповіді text / html + print. Перевагою такого підходу є те, що ви можете створити перетворення для багатьох типів MIME (ex text / html, text / x-markdown, application / json тощо) для одного і того ж URI. Недоліком рішення, яке ви представляєте, є те, що вам потрібно створити додатковий URI (і визначити інший маршрут) для кожного іншого типу MIME. Це якось перемагає мету використання REST.
Еван Плейс

(продовжую) Я стверджую, що URI-хаки є анти-шаблоном, запровадженим головним чином спільнотою ROR, але це не означає, що вони не корисні. З появою кращих низькорівневих серверів HTTPd просто стає легше впроваджувати REST таким чином, що повністю використовує його потенціал. Все минуло далеко з тих часів, коли Apache та маршрутизація всього через index.html була єдиною можливістю.
Еван Плейс

2
GET не повинен вносити змін у стан або мати побічні ефекти. Вважайте, що GET ідентичний, тобто середнє програмне забезпечення може повторно спробувати запит, якщо воно не побачило його. У цьому випадку кожне повторне повторення призведе до нової, щойно надрукованої копії документа. ;)
Роб

@RobY Я припускав, що дія "друк" не буде справлятися з процесом фізичного друку документа, тому що краще послужить браузером та драйвером друку. Швидше за все, випуск засобів масової інформації / друку повертав би документ "дружнє до друку". Тому ідемпотенція зберігається. Добре, що надсилати завдання друку через Інтернет без громадянства було б поганим часом.
Еван Плейс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.