Представлять действия (глаголы) в REST URI

16

У меня есть операция печати для моих документов клиента. Мне нужны и другие стандартные операции, такие как добавление, обновление, удаление. Итак, у меня есть следующее:

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

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

Но у меня не может быть глагола "Print" в моем URI. Какой лучший способ сделать это? Я думал о / customer / document / {id} как URI ... но я столкнусь с той же проблемой. У меня были бы операции CRUD над «документом». Итак, я снова исчерпал то, что использовал бы для «печати». Пожалуйста, порекомендуйте.

Нитья Маха
источник
2
Печать обычно выполняется на стороне клиента, поэтому мне любопытно - как ваши настройки требуют, чтобы вы отправляли команду на сервер REST?
Шона
2
@Shauna Не обязательно, URI может быть запросом к серверу для дружественной для печати версии ресурса (то есть другого представления).
Эван Плейс
1
@EvanPlaice - ярмарка достаточно, хотя это по- прежнему оставляет акт о печати на стороне клиента (который, даже после загрузки на стороне сервера печати версией файла, затем решить , что устройство для печати на и отправить саму команду печати, даже если команда отправляется на сервер печати). Запрос на получение версии ресурса для печати логически будет ... ну ... ПОЛУЧИТЬ.
Шона
@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 обычно означает создание / вставку, тогда как put обычно означает обновление, сохранение / обновление. Вот как это определяется в REST, даже если это не так, как обычно используется в HTML.
Эван Плейс
2
@EvanPlaice HTTP-спецификация имен PUT в качестве глагола create / update (вместо более знакомого create + retrieve + update используется модель create + update), а POST - глагол «обработка данных», а также глагол «append» , Рой Филдинг в своем блоге назвал POST глаголом, который нужно использовать, когда вы не хотите стандартизировать операцию. POST использует семантику «создания», когда вы рассматриваете добавление нового элемента в коллекции элементов. В этом случае Tragedian ударил ноготь по голове, используя POST для обработки или добавления задания на печать.
Роб
@RobY Хорошо, это имеет смысл. Например, PUT может использоваться для представления SPROC, предназначенного для ввода данных в базу данных. Принимая во внимание, что POST может составлять промежуточные этапы и мутации, необходимые для сбора / подготовки этих данных. Дизайн операции POST может изменяться или заменяться по мере развития проекта, но операции PUT представляют модель, которая (в идеале) не должна изменяться. Я бы обновил свой ответ, но этот уже отлично объясняет разницу.
Эван Плейс
4

Я сделал это раньше. Чтобы напечатать документ, я просто возвращаю PDF-версию ресурса. Клиенту нужно только отправить GET-запрос на ресурс с помощью заголовка Accept application / pdf.

Это также позволяет избежать создания нового URI для временного ресурса, такого как задание на печать. Использование HTTP-заголовка также является частью REST и поддерживает чистоту URI.

imel96
источник
3

Просто добавьте параметр в GET текущего URI

Довольно типично использовать URI для нескольких действий.

Если вы говорите об одном и том же ресурсе, но о другом действии, вы должны определить его как параметр.

/ Клиент / {идентификатор}? = Печать верно

Затем, где вы определяете свой метод GET, вы обнаруживаете наличие параметра печати и обрабатывает его по-другому.

REST определяется следующим образом:

  • POST - Создать запись, актив или ресурс
  • PUT - обновление, запись, актив или ресурс
  • УДАЛИТЬ - Удалить, запись, актив или ресурс

GET, с другой стороны, предназначен для использования несколькими способами, потому что обычно существует множество различных форм, которые ресурс может быть извлечен. Вот почему GET-запросы представлены в виде строки запроса. Если бы вы работали с ресурсом базы данных, вы бы в буквальном смысле извлекали представление через запрос, но REST преднамеренно абстрагируется до более высокого уровня, поскольку он предназначен для работы со многими различными типами ресурсов.

Спецификация REST довольно дальновидна, хотя API только начинает интенсивно ее использовать.

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


Обновить:

@Shauna указал на интересную дыру в моих рассуждениях. Там нет истинно правильного пути, и многие формы считаются приемлемыми. Я подумал об этом еще немного, и, поскольку вы планируете использовать для преобразования данных в другое представление, имеет смысл определить преобразование как новый MIME-тип.

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

/customer/{id}+print

Где вы можете установить тип содержимого ответа text / html + print. Таким образом, у вас также будет возможность определить больше преобразований в будущем.

Например:

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

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

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

В сторону: позвольте мне уточнить, так как, кажется, есть некоторая путаница. Параметр запроса «печать» и / или тип содержимого используется для указания того, как преобразуется ресурс. Не как запустить физическое задание на печать. Из соображений безопасности доступ на аппаратном уровне всегда предоставляется пользователю / клиенту / браузеру.

Эван Плейс
источник
Чтобы добавить - В качестве альтернативы использованию строки запроса ( ?print=true), вы также можете использовать параметры URI (т.е. - /customer/{id}/printable). Какой из них вы используете, во многом будет зависеть от стандарта, который ваша система (CMS, фреймворк, код в целом) настроена для обработки. Оба считаются действительными и приемлемыми .
Шона
@Shauna Технически, наилучшим подходом было бы использование MIME-типа, специфичного для печати, с URI '/ customer / {id} + print' и ответным MIME-типом text / html + print. Преимущество такого подхода заключается в том, что вы можете создавать преобразования для многих MIME-типов (например, text / html, text / x-markdown, application / json и т. Д.) Для одного и того же URI. Недостаток предлагаемого вами решения заключается в том, что вам необходимо создать дополнительный URI (и определить другой маршрут) для каждого отдельного MIME-типа. Это своего рода побеждает цель использования REST.
Эван Плейс
(продолжение) Я бы сказал, что URI-хаки являются анти-паттерном, введенным в основном сообществом ROR, но это не значит, что они бесполезны. С появлением более качественных низкоуровневых HTTP-серверов становится все проще внедрить REST таким образом, чтобы полностью использовать его потенциал. Вещи прошли долгий путь со времен, когда Apache и маршрутизация всего через index.html были единственным вариантом.
Эван Плейс
2
GET не должен вносить изменения в состояние или иметь побочные эффекты. Учтите, что GET является идемпотентом, а это означает, что промежуточное ПО может повторить запрос, если он не видит, что он прошел. В этом случае каждая повторная попытка приведет к новой, только что напечатанной копии документа. ;)
Роб
@RobY Я предполагал, что действие «печать» не будет обрабатывать процесс физической печати документа, так как это будет лучше обслуживаться браузером и драйвером печати. Скорее, вывод мультимедиа / печати вернул бы «дружественное к печати» представление документа. Следовательно, идемпотентность сохраняется. Хорошо, что отправка заданий на печать через Интернет без сохранения состояния была бы плохим временем.
Эван Плейс