Ресурс RESTful - принимает список объектов
Я создаю коллекцию ресурсов RESTful, которые работают следующим образом: (я буду использовать "людей" в качестве примера):
GET / people / {key} - возвращает объект person (JSON)
ПОЛУЧИТЬ / люди? First_name=Bob - возвращает список объектов person, имя которых "first_name" равно "Bob" (JSON)
PUT / people / {key} - ожидает объект человека в полезной нагрузке (JSON), обновляет человека в хранилище данных с {ключом}, найденным в параметре URL, чтобы соответствовать полезной нагрузке. Если это новый объект, клиент указывает ключ нового объекта.
Я до сих пор чувствую себя довольно комфортно с дизайном (хотя любые комментарии / комментарии приветствуются).
Я также хотел бы иметь возможность выставить список людей, однако я не уверен в RESTfulness моего дизайна. Вот что я имею в виду:
PUT / люди - ожидает список объектов в форме JSON с ключами, включенными в объект ("Ключ":"32948"). Обновляет все соответствующие объекты в хранилище данных.
Эта операция будет идемпотентной, поэтому я бы хотел использовать "PUT". Однако это нарушает правило, потому что запрос GET к этому же ресурсу не будет возвращать эквивалент того, что клиент просто PUT, а скорее вернет все объекты "люди" (поскольку в запросе не будет фильтров). Я подозреваю, что есть также несколько других правил, которые могут быть нарушены здесь.
Кто-то упомянул об использовании запроса "PATCH" в моем предыдущем вопросе: ресурс REST со свойством List.
"PATCH" звучит фантастически, но я не хочу его использовать, потому что он еще не широко используется и еще не совместим со многими программами и API.
Я бы предпочел не использовать POST, потому что POST подразумевает, что запрос не идемпотентен.
У кого-нибудь есть какие-либо комментарии / предложения?
Следовать за:::
Хотя я не решался использовать POST, потому что он кажется наименьшим общим знаменателем, универсальным для операций RESTful и многое другое можно сказать об этой операции (в частности, что она идемпотентна), PUT не может использоваться, потому что его требования слишком узки, В частности: ресурс переписывается не полностью, а эквивалентный ресурс не отправляется обратно из запроса GET к тому же ресурсу. Использование PUT со свойствами, выходящими за пределы его спецификаций, может вызвать проблемы, когда приложения, API и / или программисты пытаются работать с ресурсом и сталкиваются с неожиданным поведением ресурса.
В дополнение к принятому ответу у Даррела Миллера было отличное предложение, если операция обязательно должна быть PUT, и это должно было добавить UUID в конец пути ресурса, чтобы эквивалентный запрос GET возвратил эквивалентный ресурс.
4 ответа
POST
указывает на общее действие, кроме GET
, PUT
, а также DELETE
(общие хеш-таблицы действий). Поскольку общие хеш-таблицы не подходят, используйте POST
, Семантика POST
определяются ресурсом, к которому относится POST
редактор Это не похоже на семантику общих методов хеширования, которые хорошо известны.
POST /people/add-many HTTP/1.1
Host: example.com
Content-Type: application/json
[
{ "name": "Bob" },
{ "name": "Robert" }
]
Использование PUT - определенно неправильный глагол в этом случае. POST предназначен для того, чтобы делать именно то, что вы просите. Из спецификации HTTP:
Принципиальное различие между запросами POST и PUT отражается в различном значении Request-URI. URI в запросе POST идентифицирует ресурс, который будет обрабатывать вложенную сущность. Этот ресурс может быть процессом приема данных, шлюзом к другому протоколу или отдельным объектом, который принимает аннотации. Напротив, URI в запросе PUT идентифицирует объект, заключенный в запросе - пользовательский агент знает, для чего предназначен URI, и сервер НЕ ДОЛЖЕН пытаться применить запрос к другому ресурсу...
Таким образом, если вы хотите обновить несколько ресурсов за один вызов, вы должны использовать POST.
То, что PUT обязан быть идемпотентным, а POST нет, не означает, что POST не может быть идемпотентным. Ваш выбор HTTP-глагола должен основываться не на этом, а на взаимосвязи запрашиваемого ресурса и ресурса, на который действовали. Если ваше приложение непосредственно обрабатывает запрошенный ресурс, используйте PUT. Если он действует на каком-то другом ресурсе (или ресурсах, как в вашем случае), используйте POST.
Я действительно не вижу простого способа использовать PUT для создания произвольного набора людей. Если вы не готовы, чтобы клиент сгенерировал GUID и сделал что-то вроде:
PUT /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
На стороне сервера вы можете взять людей из списка и добавить их в /People
ресурс.
Небольшое отклонение от этого подхода заключается в том, чтобы сервер включал ссылку, такую как
<link rel="AddList" href="/PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}"/>
в ресурсе People. Клиент должен знать, что ему нужно ПОСТАВИТЬ список людей на AddList
ссылка на сайт. Сервер должен убедиться, что каждый раз, когда он отображает ресурс /People, он создает новый URL для ссылки AddList.
Что касается предложения Даррена Миллера использовать PUT для GUID (я не могу комментировать...), то смысл использования PUT будет заключаться в достижении идемпотентности для операции. Лакмусовый тест, если идемпотентность была бы этим диалогом между клиентом и сервером:
PUT /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
204 NO CONTENT
(указывает, что все прошло хорошо)- клиент теряет связь и не видит
204
- клиент автоматически повторяет попытку
PUT /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
Как сервер будет различать два? Если, так сказать, "израсходован" GUID, то сервер должен будет ответить 404
или же 410
, Это вводит чуть-чуть разговорного состояния на сервере, чтобы запомнить все GUID, которые были использованы.
Я думаю, два клиента часто видят одно и то же из-за кэширования или просто хранения устаревших ответов.
Я думаю, что разумным решением является использование POST для создания (изначально пустой, недолговечной) области хранения для ресурса, к которому вы можете PUT, т.е. клиентам нужно POST для создания ресурса GUID вместо обнаружения его по ссылке:
POST /PeopleList/CreateHoldingArea
201 CREATED
а такжеLocation: /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
PUT /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
Это будет означать, что потерянная идемпотентность не приведет к большим накладным расходам; клиенты просто создают новые GUID (посредством POSTing), если они не видели начальный 201 CREATED
ответ. "Крошечное состояние разговора" теперь будет только созданными, но еще не используемыми областями ожидания.
Идеальное решение, конечно, не требует какого-либо разговорного состояния на сервере, но оно ускользает от меня.