Я пишу сервис RESTful для системы управления клиентами и пытаюсь найти лучший способ частичного обновления записей. Например, я хочу, чтобы вызывающая сторона могла читать полную запись с помощью запроса GET. Но для его обновления разрешены только определенные операции с записью, например, изменение статуса с ENABLED на DISABLED. (У меня есть более сложные сценарии, чем это)
Я не хочу, чтобы вызывающий абонент отправлял всю запись только с обновленным полем из соображений безопасности (это также выглядит как перебор).
Есть ли рекомендуемый способ построения URI? При чтении книг REST вызовы в стиле RPC кажутся недовольными.
Если следующий вызов возвращает полную запись о клиенте с идентификатором 123
GET /customer/123
<customer>
{lots of attributes}
<status>ENABLED</status>
{even more attributes}
</customer>
как мне обновить статус?
POST /customer/123/status
<status>DISABLED</status>
POST /customer/123/changeStatus
DISABLED
...
Обновление : чтобы дополнить вопрос. Как включить «вызовы бизнес-логики» в API REST? Есть ли согласованный способ сделать это? Не все методы CRUD по своей природе. Некоторые из них являются более сложными, например ' sendEmailToCustomer (123) "," mergeCustomers (123, 456) "," countCustomers () "
POST /customer/123?cmd=sendEmail
POST /cmd/sendEmail?customerId=123
GET /customer/count
POST
от самого Роя Филдинга: roy.gbiv.com/untangled/2009/it-is-okay-to-use-post, где основная идея такова: если нет Это метод (например,GET
илиPUT
), идеально подходящий для вашей операции использованияPOST
.Ответы:
У вас есть два варианта:
Используйте
PATCH
(но обратите внимание, что вы должны определить свой собственный тип медиа, который определяет, что именно произойдет)Используйте
POST
для подресурса и верните 303 См. Другое с заголовком Location, указывающим на основной ресурс. Цель 303 - сообщить клиенту: «Я выполнил ваш POST, и в результате был обновлен какой-то другой ресурс. См. Заголовок Location, для которого этот ресурс был». POST / 303 предназначен для итеративных дополнений к ресурсам для создания состояния некоторого основного ресурса и идеально подходит для частичных обновлений.источник
Вы должны использовать POST для частичных обновлений.
Чтобы обновить поля для клиента 123, сделайте POST для / customer / 123.
Если вы хотите обновить только статус, вы также можете PUT в / customer / 123 / status.
Как правило, запросы GET не должны иметь побочных эффектов, а PUT предназначен для записи / замены всего ресурса.
Это следует непосредственно из HTTP, как показано здесь: http://en.wikipedia.org/wiki/HTTP_PUT#Request_methods
источник
/customer/123
должен создать очевидную вещь, которая логически соответствует потребителю 123. Может быть, заказ? PUT,/customer/123/status
кажется, имеет больше смысла, предполагая, что POST/customers
неявно создалstatus
(и предполагая, что это законный REST).POST
запросы не должны быть неидемпотентными . И, как уже упоминалось,PUT
должен заменить весь ресурс.Вы должны использовать PATCH для частичных обновлений - либо используя документы json-patch (см. Http://tools.ietf.org/html/draft-ietf-appsawg-json-patch-08 или http://www.mnot.net/ blog / 2012/09/05 / patch ) или структура исправлений XML (см. http://tools.ietf.org/html/rfc5261 ). На мой взгляд, json-patch лучше всего подходит для ваших бизнес-данных.
Патч с документами патчей JSON / XML имеет очень прямолинейную семантику для частичного обновления. Если вы начнете использовать POST с измененными копиями исходного документа, для частичных обновлений вы вскоре столкнетесь с проблемами, когда вы хотите, чтобы пропущенные значения (или, скорее, нулевые значения) представляли либо «игнорировать это свойство», либо «установите для этого свойства значение «Пустое значение» - и это ведет к кроличьей норе взломанных решений, что в итоге приведет к вашему виду формата патчей.
Вы можете найти более подробный ответ здесь: http://soabits.blogspot.dk/2013/01/http-put-patch-or-post-partial-updates.html .
источник
Я сталкиваюсь с подобной проблемой. PUT для подресурса, кажется, работает, когда вы хотите обновить только одно поле. Тем не менее, иногда вы хотите обновить несколько вещей: подумайте о веб-форме, представляющей ресурс с возможностью изменения некоторых записей. Отправка пользователем формы не должна приводить к нескольким PUT.
Вот два решения, которые я могу придумать:
сделать PUT со всем ресурсом. На стороне сервера определите семантику, согласно которой PUT со всем ресурсом игнорирует все значения, которые не изменились.
сделать PUT с частичным ресурсом. На стороне сервера определите семантику этого как слияние.
2 - это просто оптимизация пропускной способности, равная 1. Иногда 1 - единственный вариант, если ресурс определяет, что некоторые поля являются обязательными полями (например, прото-буферы).
Проблема обоих этих подходов заключается в том, как очистить поле. Вам нужно будет определить специальное нулевое значение (особенно для протобуферов, поскольку нулевые значения не определены для протобуферов), которое приведет к очистке поля.
Комментарии?
источник
Для изменения статуса я думаю, что подход RESTful состоит в том, чтобы использовать логический подресурс, который описывает состояние ресурсов. Это IMO довольно полезно и чисто, когда у вас уменьшенный набор статусов. Это делает ваш API более выразительным, не заставляя существующие операции для вашего ресурса клиента.
Пример:
Служба POST должна вернуть только что созданного клиента с идентификатором:
GET для созданного ресурса будет использовать местоположение ресурса:
GET / клиент / 123 / неактивный должен вернуть 404
Для операции PUT без предоставления объекта Json он просто обновит статус
Предоставление сущности позволит вам обновлять содержимое клиента и обновлять статус одновременно.
Вы создаете концептуальный подресурс для своего клиентского ресурса. Это также согласуется с определением ресурса Роя Филдинга: «... ресурс - это концептуальное отображение набора сущностей, а не сущности, которая соответствует сопоставлению в любой конкретный момент времени ...». В этом случае концептуальное сопоставление активный клиент-клиент со статусом = ACTIVE.
Операция чтения:
Если вы выполняете эти вызовы сразу после того, как другой из них должен вернуть статус 404, успешный вывод может не включать статус, поскольку он неявный. Конечно, вы все равно можете использовать GET / customer / 123? Status = ACTIVE | INACTIVE для прямого запроса ресурса клиента.
Операция DELETE интересна, так как семантика может сбивать с толку. Но у вас есть возможность не публиковать эту операцию для этого концептуального ресурса или использовать ее в соответствии с вашей бизнес-логикой.
Это может привести вашего клиента к статусу DELETED / DISABLED или к противоположному статусу (ACTIVE / INACTIVE).
источник
Вещи, чтобы добавить к вашему дополненному вопросу. Я думаю, что вы часто можете идеально разработать более сложные деловые действия. Но вы должны отказаться от метода / метода мышления и больше думать о ресурсах и глаголах.
отправка почты
Реализация этого ресурса + POST будет отправлять почту. при необходимости вы можете предложить что-то вроде / customer / 123 / outbox, а затем предложить ссылки на ресурсы для / customer / mails / {mailId}.
количество клиентов
Вы можете обращаться с ним как с поисковым ресурсом (включая метаданные поиска с разбивкой по страницам и информацией, найденной по номеру, которая дает вам количество клиентов).
источник
Используйте PUT для обновления неполного / частичного ресурса.
Вы можете принять jObject в качестве параметра и проанализировать его значение для обновления ресурса.
Ниже приведена функция, которую вы можете использовать в качестве справки:
источник
Относительно вашего обновления.
Я считаю, что концепция CRUD вызвала некоторую путаницу в отношении дизайна API. CRUD - это общий низкоуровневый концепт для базовых операций над данными, а HTTP-глаголы - это просто методы запроса ( создано 21 год назад ), которые могут отображаться или не отображаться в операции CRUD. На самом деле, попробуйте найти наличие аббревиатуры CRUD в спецификации HTTP 1.0 / 1.1.
Очень хорошо объясненное руководство, которое применяет прагматическое соглашение, может быть найдено в документации API облачной платформы Google . В нем описываются концепции, лежащие в основе создания API на основе ресурсов, который выделяет большое количество ресурсов по сравнению с операциями, и включает описываемые вами варианты использования. Хотя это просто условный дизайн для их продукта, я думаю, что это имеет большой смысл.
Базовая концепция здесь (и та, которая вызывает много путаницы) - это отображение между «методами» и HTTP-глаголами. Одна вещь состоит в том, чтобы определить, какие «операции» (методы) будет выполнять ваш API над какими типами ресурсов (например, получить список клиентов или отправить электронное письмо), а другой - глаголами HTTP. Должно быть определение как методов, так и глаголов, которые вы планируете использовать, и между ними. .
Он также говорит , что, когда операция точно не карты со стандартным методом (
List
,Get
,Create
,Update
,Delete
в данном случае), то можно использовать «Пользовательские методы», какBatchGet
, который извлекает несколько объектов на основе нескольких входного идентификатора объекта, илиSendEmail
.источник
В RFC 7396 : исправление слияния JSON (опубликовано через четыре года после публикации вопроса) описываются лучшие практики для PATCH с точки зрения формата и правил обработки.
В двух словах, вы отправляете HTTP PATCH целевому ресурсу с помощью приложения / merge-patch + json типом носителя MIME и телом, представляющим только те части, которые вы хотите изменить / добавить / удалить, а затем следуйте приведенным ниже правилам обработки.
правила :
Пример тестовых случаев, которые иллюстрируют приведенные выше правила (как видно в приложении к этому RFC):
источник
Проверьте http://www.odata.org/
Он определяет метод MERGE, поэтому в вашем случае это будет примерно так:
status
Обновляется только свойство, а остальные значения сохраняются.источник
MERGE
действительным глагол HTTP?MERGE was used to do PATCH before PATCH existed. Now that we have PATCH, we no longer need MERGE.
См. Docs.oasis-open.org/odata/new-in-odata/v4.0/cn01/…Это не важно С точки зрения REST, вы не можете сделать GET, потому что он не кэшируется, но это не имеет значения, если вы используете POST или PATCH или PUT или что-то еще, и не имеет значения, как выглядит URL. Если вы выполняете REST, важно, чтобы, когда вы получаете представление своего ресурса с сервера, это представление могло предоставить опции перехода состояния клиента.
Если ваш ответ GET имеет переходы состояний, клиенту просто нужно знать, как их читать, и сервер может изменить их, если это необходимо. Здесь обновление выполняется с использованием POST, но если оно было изменено на PATCH или URL-адрес изменился, клиент все еще знает, как сделать обновление:
Вы можете зайти так далеко, чтобы перечислить обязательные / необязательные параметры, которые клиент может вернуть вам. Это зависит от приложения.
Что касается бизнес-операций, это может быть другой ресурс, связанный с ресурсом клиента. Если вы хотите отправить электронное письмо клиенту, возможно, эта служба является собственным ресурсом, к которому вы можете POST, поэтому вы можете включить в ресурс клиента следующую операцию:
Вот несколько хороших видео и пример архитектуры REST докладчика. Stormpath использует только GET / POST / DELETE, что хорошо, поскольку REST не имеет никакого отношения к тому, какие операции вы используете или как должны выглядеть URL-адреса (за исключением того, что GET должен кэшироваться):
https://www.youtube.com/watch?v=pspy1H6A3FM ,
https://www.youtube.com/watch?v=5WXYw4J4QOU ,
http://docs.stormpath.com/rest/quickstart/
источник