Может ли REST возвращать контент после POST?

88

Я использую RESTlet и создал ресурс. Я обрабатываю POST методом переопределения acceptRepresentation.

Клиент должен отправить мне некоторые данные, затем я сохраняю их в БД, устанавливаю ответ на 201 (SUCCESS_CREATED), и мне нужно вернуть некоторые данные клиенту, но тип возврата acceptRepresentationесть void.

В моем случае мне нужно вернуть какой-то идентификатор, чтобы клиент мог получить доступ к этому ресурсу.

Например, если у меня есть ресурс с URL-адресом, /resourceи клиент отправляет запрос POST, я добавляю новую строку в БД, и ее адрес должен быть /resource/{id}. Мне нужно отправить {id}.

Я делаю что-то неправильно? Принципы REST позволяют вернуть что-либо после POST? Если да, как я могу это сделать, а если нет, как мне разрешить эту ситуацию?

дель-мальчик
источник
См. Ответ Тома, чтобы узнать, как установить тело ответа из acceptRepresentation ().
Avi Flax

Ответы:

96

REST просто говорит, что вы должны соответствовать единому интерфейсу. Другими словами, в нем говорится, что вы должны делать то, что должен делать POST в соответствии со спецификацией HTTP . Вот цитата из этой спецификации, которая актуальна,

Если ресурс был создан на исходном сервере, ответ ДОЛЖЕН быть 201 (Создан) и содержать объект, который описывает статус запроса и относится к новому ресурсу, и заголовок Location (см. Раздел 14.30).

Как видно из этого, у вас есть два места, где вы можете указать клиенту, где находится вновь созданный ресурс. Заголовок Location должен иметь URL-адрес, указывающий на новый ресурс, и вы также можете вернуть объект с подробностями.

Я не уверен, в чем разница между переопределением acceptRepresentation () и переопределением post (), но в этом примере показано, как вернуть ответ из POST.

Даррел Миллер
источник
2
@ del-boy: См. ответ Тома, чтобы узнать, как установить тело ответа из acceptRepresentation ().
Avi Flax
1
Цитата спецификации HTTP не запрещает ответ, если вы посмотрите в Разделе 6, это ясно: это разрешено: Request and Response messages MAY transfer an entity if not otherwise restricted by the request method or response status code. An entity consists of entity-header fields and an entity-body, although some responses will only include the entity-headers.
MikeF
@MikeF Я не собирался делать вывод, что тело ответа не разрешено. В части спецификации, которую я процитировал, конкретно говорится «и содержать объект». Я должен был быть яснее в своем тексте.
Даррел Миллер
16

Я бы отказался от отправки чего-либо в теле ответа. Просто установите Location: на (полный) URL-адрес вновь созданного ресурса.

Ваше описание предполагает, что это именно та семантика, которую вы:

  1. РАЗМЕСТИТЕ вещь, чтобы ее создать
  2. Ответьте достаточно, чтобы знать две вещи:
    1. Что сотворение произошло (201)
    2. Где найти обновку (заголовок Location)

Все остальное - лишнее.

cdent
источник
Не то, что Википедия всегда является источником хорошо, но что также претензии «[...] Для того, чтобы предоставлять информацию о местоположении вновь созданного ресурса. В таком случае, заголовок Место должно быть отправлено с кодом состояния HTTP 201 или 202 . "
Arjan
1
POST может выполнять логику, которая создает один или несколько ресурсов. Результат обработки может понадобиться клиенту. Таким образом, возвращение его в ответе позволяет избежать необходимости выполнять один или несколько вызовов GET к API. Данные, созданные / измененные методом POST, не могут быть (и часто не являются) лишними для клиента.
Пауло Мерсон
10

Два разных вопроса:

Поддерживает ли шаблон приложения REST возврат данных в POST?

Я не думаю, что REST явно запрещает это, но предпочтительное лечение указано в ответе Даррела.

Позволяет ли структура RESTlet возвращать данные в POST?

Да, даже если он возвращает void, в классе, расширяющем Resource, у вас есть полный доступ к объекту объекта Response через метод getResponse (). Таким образом, вы можете вызвать getResponse (). SetEntity () с любыми данными, которые вам нужны.

Том
источник
6

Выведите его в любом запрошенном формате. Это может быть:

<success>
    <id>5483</id>
</success>

Или:

{ "type": "success", "id": 5483 }

Это зависит от того, что вы обычно делаете. Если они не ожидают данных, они должны просто игнорировать их, но любой клиент, который хочет обработать их должным образом, должен иметь возможность.

Самир Талвар
источник
Хорошо, у меня есть два возможных формата (html и xml). Я знаю, как обрабатывать тип запрошенного формата, но не знаю, как добавлять данные в ответ. Представить метод возвращает представление, поэтому я просто возвращаю то, что хочу, но acceptRepresentation является недействительным методом, поэтому я не могу вернуть никаких данных ...
дель-мальчик
1

Если вы отвечаете 201 Created с телом объекта, а не с перенаправлением Location, то рекомендуется включить заголовок Content-Location, указывающий на ресурс, который представлен в ответе.

Это позволит избежать потенциальной путаницы, когда клиент может (оправданно) предположить, что объект ответа на самом деле представляет новое состояние «создателя», а не созданный ресурс.

> POST /collection
> ..new item..

< 201 Created
< Location: /collection/1354
< Content-Location: /collection/1354
< <div class="item">This is the new item that was created</div>
Майк
источник
3
Я думаю, Content-Location предназначен для другой цели. В спецификации HTTP говорится, что Content-Location не определено для POST и PUT. Заголовок Location используется с 201-Create. При возврате местоположения не происходит автоматического перенаправления, для этого вам потребуется код ответа 3XX.
Даррел Миллер
1
Заголовок местоположения используется (в ответе 201), чтобы указать, где находится созданный ресурс; он не имеет отношения к телу объекта ответа, который он сопровождает. Моя точка зрения заключалась в том, что - если вы хотите включить созданный ресурс в сам ответ 201 (а не направлять / перенаправлять клиента на другой URI), тогда заголовок Content-Location будет хорошей идеей. Это, вероятно, немного «искажает правила», но это более эффективно, чем требовать еще одного цикла запроса / ответа, чтобы получить состояние нового ресурса для клиента.
Майк
Для меня есть смысл. Я никогда раньше не использовал заголовок Content-Location.
Даррел Миллер,
если клиент - человек с браузером, возвращать 201 с заголовком Location не имеет смысла. Пользователь не будет знать, что с этим делать. если клиент - робот, его можно запрограммировать, чтобы он знал, как с ним справляться - как последующий GET в Location.
непререкаемый 02
3
@irreputable: я считаю, что REST был предназначен для разработки API-интерфейсов, где A не означает User Agent, который ищет какой-то HTML для рендеринга.
Hermes