подвергая операции над ресурсами RESTful - перегруженный POST против PUT против ресурсов контроллера - PullRequest
16 голосов
/ 15 марта 2012

Скажем, у вас есть ресурс Person, и часть его представления включает в себя значение Location, которое может иметь такие значения, как «дома», «в школе» и «на работе». Как бы вы НАСТОЯТЕЛЬНО разоблачали такие действия, как «иди домой», «иди на работу», «иди в школу» и т. Д.? Для обсуждения давайте оговорим, что эти действия занимают время, поэтому они выполняются асинхронно, и существуют различные способы, которыми они могут потерпеть неудачу (нет доступных средств транспортировки, поломка транспорта во время путешествия, другой стихийный бедствие и т. Д.) , Кроме того, ресурс Person имеет другие атрибуты и связанные операции, которые влияют на эти атрибуты (например, атрибут = уровень энергии, операции = питание / сон / тренировка).

Опция 1 : Перегрузка POST для ресурса Person, предоставляя входной параметр, указывающий, что вы хотите, чтобы человек сделал (например, action = go-to-school). Верните 202 из сообщения POST и предоставьте атрибуты состояния незавершенного действия в представлении Person, которые клиент может ПОЛУЧИТЬ, чтобы наблюдать за прогрессом и успехом / неудачей.

Преимущества: делает все просто.

Недостатки: равносильно туннелированию. Происходящее действие скрывается в полезной нагрузке, а не отображается в URI, глаголе, заголовках и т. Д. У глагола POST в этом ресурсе нет единого семантического значения.

Вариант 2 : Используйте PUT, чтобы установить местоположение человека в том состоянии, в котором вы хотите, чтобы он находился. Верните 202 из PUT и предоставьте атрибуты незавершенного действия для опроса статуса через GET.

Преимущества : Не уверен, что я вижу.

Недостатки : действительно, это просто туннелирование с другим глаголом. Кроме того, в некоторых случаях это не работает (как сон, так и прием пищи увеличивают уровень энергии, поэтому перевод значения энергии на более высокое значение неоднозначен с точки зрения того, какое действие вы хотите выполнить для ресурса).

Опция 3 : предоставить общий ресурс контроллера, который работает с объектами Person. Например, создайте ресурс PersonActivityManager, который принимает запросы POST с аргументами, которые идентифицируют целевой объект Person и запрошенное действие. POST может возвратить ресурс PersonActivity, чтобы представить текущее действие, которое клиент может ПОЛУЧИТЬ, чтобы отслеживать прогресс и успех / сбой.

Преимущества : выглядит немного чище, если отделить активность и ее статус от ресурса Person.

Недостатки : Теперь мы переместили туннелирование на ресурс PersonActivityManager.

Вариант 4 : Установите отдельные ресурсы контроллера для каждого поддерживаемого действия, например, ресурс ToWorkTransporter, который принимает запросы POST с аргументом (или элементом URI), который идентифицирует Person, плюс ToHomeTransporter, ToSchoolTransporter, MealServer, Sleeper и Exerciser. Каждый из них возвращает соответствующий ресурс мониторинга задач (Commute, Meal, Slumber, Workout) из своего метода POST, который клиент может отслеживать с помощью GET.

Преимущества : ОК, мы наконец-то устранили туннелирование. Каждый POST означает только одну вещь.

Недостатки : Теперь говорилось о большом количестве ресурсов (возможно, мы могли бы объединить транспортеры в один Транспортер, который принимает аргумент назначения). И некоторые из них довольно семантически придуманы (Спящий?). Это может быть более RESTful, но это практично?

1 Ответ

18 голосов
/ 21 марта 2012

ОК, я изучал и размышлял об этом около недели. Поскольку никто не ответил, я опубликую результаты того, что я узнал.

Тим Брей, в RESTful Casuistry , рассказывает о передаче поля состояния против POST-контроллеру контроллеру, который выполнит операцию, влияющую на это состояние. Он использует пример виртуальной машины и как RESTful выставить функцию «кнопки перезагрузки». Он говорит

"Если я хочу обновить некоторые поля в существующем ресурсе, я склонен думать о PUT. Но это не работает, потому что это должно быть Идемпотент, и перезагрузка сервера точно не. Ну хорошо, сделай это с ПОСТ я думаю; нет, бигги.

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

Итак, чем больше я думаю об этом, тем больше я думаю, что эти ресурсы как кнопки, только с одной определенной операцией: нажать. Люди были ныть о «ресурсах только для записи», но у меня нет проблем с потому что это кажется точным. Кнопки перезагрузки и остановки не работают действительно есть какое-либо состояние, так что вы не должны ожидать ничего полезного от GET. "

Тим, похоже, находится где-то между моими вариантами # 3 и # 4, выставляя несколько ресурсов контроллера, но отступая от "перегрузки" и имея отдельные ресурсы контроллера для всего.

Пост Тима привел к другому Рой Филдинг ( Можно использовать POST ), в котором он говорит, что для ситуаций, когда существует состояние контролируемой сущности и действие, чтобы потенциально изменить это состояние, он склонен использовать POST, а не PUT. В ответ на предложение комментатора выставить отслеживаемое состояние в качестве отдельного ресурса с возможностью PUT, он говорит

"мы используем PUT, только когда действие обновления идемпотентно и представление завершено. Я думаю, что мы должны определить дополнительный ресурс всякий раз, когда мы думаем, что ресурс может быть полезен для других в изоляции и использовать методы GET / PUT для этого ресурса, но Я не думаю, что мы должны определять новые ресурсы только ради избегая POST. "

Наконец, Билл де Хора, в Просто используйте POST , обсуждает конкретный случай использования PUT и POST для обновления состояния ресурса коллекции и компромиссы в нем.

...