Как разработать REST API для не-CRUD "команд", например, активировать и деактивировать ресурс?

Прежде чем я решил задать этот вопрос, я долго искал ответ, но я не нашел удовлетворительного. (например, Примеры лучших веб-интерфейсов SOAP/REST/RPC и почему они вам нравятся? И что с ними не так?)

И проблема на самом деле довольно проста. У меня есть объект/ресурс с именем Account. Мой REST API поддерживает все CRUD с GET, POST, PUT и DELETE уже с правильной обработкой ошибок, кодами состояния и т.д.

Кроме того, однако я хочу открыть API ( "команда" ) для активации и деактивации выбранного ресурса учетной записи. Даже если "isActive" является свойством учетной записи, я не хочу использовать только обновление из моего CRUD всей учетной записи.

Я знаю, что легко нарушить принципы REST и сделать дизайн стиля RPC таким дизайном, как это:

PUT/api/account/: accountId/activate

PUT/api/account/: accountId/deactivate

Итак, каково наилучшее решение для этого варианта использования?

Моя нынешняя идея - использовать PUT и DELETE глаголы, подобные этому (чтобы рассматривать его как под-ресурс), как предлагается здесь http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api#restful:

PUT/api/account/: accountId/isActive//​​для активации

DELETE/api/account/: accountId/isActive//​​для деактивации

Каковы ваши решения?

Ответ 1

Как насчет того, чтобы придумать существительное для функции, которую вы хотите изменить - "статус" в этом случае. Тогда это станет вспомогательным ресурсом родительского объекта. Поэтому для вашего случая я бы моделировал URI следующим образом:

/api/accounts/{accountId}/status

Если семантика 'update' является идемпотентной, то PUT будет наиболее подходящей, иначе это должно быть POST (например, если не задействованы и недействительны службой). Фактическая полезная нагрузка будет включать дескриптор для нового состояния.

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

Ответ 2

Метод POST создаст учетную запись ресурса. Active можно рассматривать как одно из свойств ресурса "account". Следовательно, это должен быть запрос PUT.

Я бы сказал, что даже деактивация должна быть запросом PUT, поскольку ресурс учетной записи будет существовать.

Чтобы активировать учетную запись, вы можете установить свойство на ресурсе. То есть:

/api/account/{accountId}?activate=true

Чтобы деактивировать:

/api/account/{accountId}?activate=false

Запрос GET в учетной записи возвращает JSON с активирующим значением в нем.

Запрос DELETE должен полностью удалить ресурс учетной записи.

Ответ 3

Во-первых, PUT подходит по сравнению с POST, потому что вы создаете ресурс в уже известном месте. И, я думаю, нет дилеммы о DELETE. Итак, на первый взгляд, ваш нынешний подход, по-видимому, превзошел альтернативы.

Я так же думал, пока не выполнил свой собственный REST api, в котором я хотел, чтобы администратор мог установить учетную запись в деактивированном, но не удаленном, просто "запрещенном" состоянии. Когда я немного подумал, я решил сделать это наоборот.

Позвольте мне объяснить. Мне нравится, когда ресурс activation "активирует учетную запись". Поэтому, если существует такой URL, как /account/foo/activation, это может означать, что учетная запись не активирована и, пользователь имеет право ее активировать. Если он не существует, учетная запись либо уже активирована , либо в запрещенном состоянии.

Следовательно, единственная рациональная вещь, которую нужно сделать, чтобы активировать учетную запись, - это попробовать и DELETE ресурс. И, чтобы активировать активацию, администратор должен был PUT ресурс активации.

Теперь вопрос, который приходит на ум, заключается в том, как отличить запрещенную учетную запись от уже активированной. Но поскольку запрет можно рассматривать как ресурс, вы можете создать коллекцию ресурсов /account/foo/ban. Чтобы заблокировать учетную запись, возможно, на определенный период времени, вы просто POST ресурс в этой коллекции, содержащий все детали запрета.