Ресурс RESTful - принимает список объектов - PullRequest
11 голосов
/ 08 июля 2010

Я создаю коллекцию ресурсов RESTful, которые работают следующим образом: (я буду использовать «людей» в качестве примера):

    GET /people/{key}
      - returns a person object (JSON)
    GET /people?first_name=Bob
      - returns a list of person objects who's "first_name" is "Bob" (JSON)
    PUT /people/{key}
      - expects a person object in the payload (JSON), updates the person in the 
        datastore with the {key} found in the URL parameter to match the payload.
        If it is a new object, the client specifies the key of the new object.

Пока что я чувствую себя довольно комфортно с дизайном (хотя приветствуются любые замечания / замечания).

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

    PUT /people
      - expects a list of objects in JSON form with keys included in the object
        ("key":"32948").  Updates all of the corresponding objects in the datastore.

Эта операция будет идемпотентной, поэтому я бы хотел использовать «PUT». Однако это нарушает правило, потому что запрос GET к этому же ресурсу не будет возвращать эквивалент того, что клиент просто PUT, а скорее вернет все объекты "люди" (так как в запросе не будет фильтров). Я подозреваю, что есть также несколько других правил, которые могут быть нарушены здесь.

Кто-то упоминал об использовании запроса «PATCH» в моем предыдущем вопросе: Ресурс REST со свойством List

"PATCH" звучит фантастически, но я не хочу его использовать, потому что он еще не широко используется и еще не совместим со многими программами и API.

Я бы предпочел не использовать POST, потому что POST подразумевает, что запрос не идемпотентен.

У кого-нибудь есть комментарии / предложения?

Последующие действия :::

Хотя я не решался использовать POST, потому что он представляется наименьшим общим знаменателем, всеобъемлющим для операций RESTful и многое другое можно сказать об этой операции (в частности, что она идемпотентна), PUT не может быть использован, поскольку его требования слишком узки В частности: ресурс переписывается не полностью, а эквивалентный ресурс не отправляется обратно из запроса GET к тому же ресурсу. Использование PUT со свойствами, выходящими за пределы его спецификаций, может вызвать проблемы, когда приложения, API и / или программисты пытаются работать с ресурсом и сталкиваются с неожиданным поведением ресурса.

В дополнение к принятому ответу у Даррела Миллера было отличное предложение, если операция обязательно должна быть PUT, и это должно было добавить UUID в конец пути ресурса, чтобы эквивалентный запрос GET возвратил эквивалентный ресурс.

Ответы [ 4 ]

8 голосов
/ 08 июля 2010

POST указывает общее действие, отличное от GET, PUT и DELETE (общие действия с хэш-таблицей).Поскольку общие действия с хеш-таблицами неуместны, используйте POST.Семантика POST определяется ресурсом, к которому относится объект POST ed.Это не похоже на семантику общих методов хеширования, которые хорошо известны.

POST /people/add-many HTTP/1.1
Host: example.com
Content-Type: application/json

[
  { "name": "Bob" },
  { "name": "Robert" }
]
3 голосов
/ 08 июля 2010

Использование PUT - определенно неправильный глагол в этом случае.POST предназначен для того, чтобы делать именно то, что вы просите.Из спецификации HTTP :

Принципиальное различие между запросами POST и PUT отражается в различном значении Request-URI.URI в запросе POST идентифицирует ресурс, который будет обрабатывать вложенный объект.Этот ресурс может быть процессом приема данных, шлюзом к другому протоколу или отдельным объектом, принимающим аннотации.Напротив, URI в запросе PUT идентифицирует объект, заключенный в запросе - пользовательский агент знает, для чего предназначен URI, и сервер НЕ ДОЛЖЕН пытаться применить запрос к другому ресурсу ...

Таким образом, если вы хотите обновить несколько ресурсов за один вызов, у вас есть для использования POST.

Просто потому, что PUT должен быть идемпотентным, а POST нет,не означает, что POST не может быть идемпотентом.Ваш выбор HTTP-глагола должен основываться не на этом, а на зависимости между запрашиваемым ресурсом и ресурсом, на который действовали.Если ваше приложение непосредственно обрабатывает запрошенный ресурс, используйте PUT.Если он действует на какой-либо другой ресурс (или ресурсы, как в вашем случае), используйте POST.

2 голосов
/ 08 июля 2010

Я действительно не вижу простого способа использовать 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.

0 голосов
/ 09 июля 2010

Что касается предложения Даррена Миллера использовать PUT для GUID (я не могу комментировать ...), смысл использования PUT будет заключаться в достижении идемпотентности для операции. Лакмусовый тест, если идемпотентность будет этим диалогом между клиентом и сервером:

  1. PUT /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
  2. 204 NO CONTENT (указывает, что все прошло хорошо)
  3. клиент теряет соединение и не видит 204
  4. клиент автоматически повторяет попытку
  5. PUT /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}

Как сервер будет различать два? Если, так сказать, «израсходован» GUID, то сервер должен будет ответить 404 или 410. Это вводит чуть-чуть разговорного состояния на сервере, чтобы запомнить все использованные GUID.

Думаю, два клиента часто видят одно и то же из-за кэширования или просто хранения устаревших ответов.

Я думаю, что разумным решением является использование POST для создания (изначально пустой, недолгой) области хранения для ресурса, к которому вы можете PUT, т.е. клиентам нужно POST для создания ресурса GUID вместо обнаружения его по ссылке :

  1. POST /PeopleList/CreateHoldingArea
  2. 201 CREATED и Location: /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
  3. PUT /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}

Это будет означать, что потерянная идемпотентность не приведет к большим накладным расходам; клиенты просто создают новые идентификаторы GUID (посредством POSTing), если они не видели начальный ответ 201 CREATED. «Крошечным разговорным состоянием» теперь будут только созданные, но еще не использованные области ожидания.

Идеальное решение, конечно, не требует разговорного состояния на сервере, но оно ускользает от меня.

...