RESTful способ создания нескольких элементов в одном запросе


122

Я работаю над небольшой клиент-серверной программой для сбора заказов. Я хочу сделать это "REST (полностью) способом".

Что я хочу сделать:

Соберите все строки заказа (продукт и количество) и отправьте полный заказ на сервер

На данный момент я вижу два варианта сделать это:

  1. Отправьте каждую строку заказа на сервер: POST qty и product_id

На самом деле я не хочу этого делать, потому что хочу ограничить количество запросов к серверу, поэтому вариант 2:

  1. Соберите все строки заказов и сразу отправьте их на сервер.

Как реализовать вариант 2? У меня есть пара идей: оберните все строки заказа в объект JSON и отправьте его на сервер или используйте массив для публикации строк заказа.

Является ли реализация варианта 2 хорошей идеей или хорошей практикой, и если да, то как мне это сделать.

Что такое хорошая практика?

rest  post 

Ответы:


74

Я считаю, что еще один правильный подход - создать еще один ресурс, представляющий вашу коллекцию ресурсов. Например, представьте, что у нас есть такая конечная точка, /api/sheep/{id}и мы можем выполнить POST /api/sheepдля создания ресурса овцы.

Теперь, если мы хотим поддерживать массовое создание, мы должны рассмотреть новый ресурс стада /api/flock(или /api/<your-resource>-collectionесли у вас нет более значимого имени). Помните, что ресурсы не нужно сопоставлять с вашей базой данных или моделями приложений . Это распространенное заблуждение.

Ресурсы - это представление более высокого уровня, не связанное с вашими данными. Работа с ресурсом может иметь значительные побочные эффекты, такие как запуск предупреждения для пользователя, обновление других связанных данных, запуск долгоживущего процесса и т. Д. Например, мы могли бы сопоставить файловую систему или даже команду unix psкак REST API.

Я думаю, можно с уверенностью предположить, что использование ресурса может также означать создание нескольких других сущностей в качестве побочного эффекта.


Я согласен с этим. Вы должны абстрагироваться от концепции коллекции вашего ресурса и рассматривать ее как ресурс. Это также даст вам больше гибкости в будущем, когда вы захотите начать выполнять операции с этим и т. Д.
— villy393

Это правильный подход. Это не нарушает запрос на сбор POST. Поскольку он используется для публикации одного объекта. Отправка массового запроса с «отдельным массовым объектом» - правильный подход.
— Sorter

2
Мне так нравится, как вы называете конечную точку api с помощью овец и стад! С некоторой степенью абстракции это почти имеет библейское упоминание: «У меня есть другие овцы, которые не из этого загона; Я должен привести и их, и они услышат Мой голос; и станут одним стадом с одним пастырем». Иоанна 10:16.
— Евгений

1
Интересно, что люди рекомендуют использовать форму множественного числа (коллекции) в URL-адресе, когда вы хотите создать один ресурс, например: отправьте POST в / api / books для создания книги. Но затем, когда вы хотите создать 100 книг (в одном запросе как json), по какому URL-адресу вы разместите коллекцию из 100 книг? вот где начинается беспокойство.
— code4kix

@ code4kix, который вы могли бы использовать /api/book-group, /api/book-collectionили что-то подобное.
— miguelcobain

47

Хотя массовые операции (например, пакетное создание) необходимы во многих системах, формально они не рассматриваются в архитектурном стиле RESTful.

Я обнаружил, что POSTing коллекции, как вы предложили, в основном работает, но проблемы возникают, когда вам нужно сообщить об ошибках в ответ на такой запрос. Такие проблемы усугубляются, когда происходит несколько сбоев по разным причинам или когда сервер не поддерживает транзакции. Я предлагаю вам, если нет проблем с производительностью, например, когда поставщик услуг находится в локальной сети (не в глобальной сети) или данные относительно малы, стоит отправить 100 запросов POST на сервер. Будьте проще, начните с отдельных запросов, а если у вас есть проблемы с производительностью, попробуйте оптимизировать.


3
Вы сами нашли решение ошибок при дозировании? Отправка 100 почтовых запросов по мобильному соединению для отображения стыков страницы - плохая идея.
— Thomas Ahle

Я добавляю ошибки в массив, перенаправляю пользователя на страницу с ошибкой 419 Conflict (и возвращаю эту ошибку клиенту) и отображаю массив ошибок. См. Мой ответ ниже для более подробной информации.
— Эрик Фуллер,

5
Это нонсенс. Речь идет об отправке заказа на многие товары, которые, как многие сказали, вы можете просто отправить в сущность одного запроса POST. Другое дело, как сервер это обрабатывает. В этом случае я не вижу проблем с созданием заказа, заполнением того, что вы можете для этого заказа, а также заполнением деталей, которые не могли быть выполнены. Таким образом, пользователь может увидеть свой заказ и увидеть, что все, кроме N товаров, были добавлены в заказ, но некоторые из них отсутствуют на складе или система не знает, что с ними делать. Еще один более простой, но менее удобный вариант - отклонить все,
— thecoshman

2
@thecoshman сильно изменился за 3,25 года. Вероятно, вам стоит опубликовать полностью сформулированный ответ на вопрос.
— dlamblin

3
@dlamblin да, мне, наверное, нужно сделать много вещей ... Возможно, я доберусь до этого на каком-то этапе ...
— thecoshman

9

Facebook объясняет, как это сделать: https://developers.facebook.com/docs/graph-api/making-multiple-requests

Простые пакетные запросы

Пакетный API принимает массив логических HTTP-запросов, представленных в виде массивов JSON - каждый запрос имеет метод (соответствующий HTTP-методу GET / PUT / POST / DELETE и т. Д.), Relative_url (часть URL-адреса после graph.facebook. com), необязательный массив заголовков (соответствующий заголовкам HTTP) и необязательный текст (для запросов POST и PUT). Пакетный API возвращает массив логических HTTP-ответов, представленных в виде массивов JSON - каждый ответ имеет код состояния, необязательный массив заголовков и необязательное тело (которое представляет собой строку в кодировке JSON).


1
Это очень интересная ссылка, предлагаемое решение мне кажется полезным. В любом случае, в StackOverflow предпочтительный ответ объясняет концепцию решения в теле ответа, поскольку ссылки могут измениться или исчезнуть.
— Ян Влцинский

7
Это действительно способ сделать это Facebook, не обязательно RESTful, как попросил OP
— 0cd,

Я думаю, что пакетный API (от Google, Facebook и т. Д. - @PuneetArora) более полезен при группировании нескольких несвязанных запросов вместе. Создание запроса, который создает один элемент, а затем группирование всех этих запросов вместе для отправки коллекции элементов - это «безумие» (Эйнштейн). Просто создайте запрос, который передает коллекцию элементов.
— tfmontague 01

8

Мне ваша идея кажется верной. Реализация - дело ваших предпочтений. Вы можете использовать JSON или просто параметры для этого (массив "order_lines []") и сделать

POST /orders

Поскольку вы собираетесь создать больше ресурсов одновременно в одном действии (порядке и его строках), жизненно важно проверять каждый из них и сохранять их только в том случае, если все они проходят проверку, т.е. вы должны сделать это в транзакции.



5

Я действительно боролся с этим в последнее время, и вот над чем я работаю.

Если POST, который добавляет несколько ресурсов, завершается успешно, верните 200 OK (я рассматривал 201, но пользователь в конечном итоге не попадает на ресурс, который был создан) вместе со страницей, которая отображает все добавленные ресурсы, либо в режиме чтения -только или редактируемый мод. Например, пользователь может выбрать и отправить несколько изображений в галерею, используя форму, содержащую только один входной файл. Если запрос POST завершается успешно, пользователю предоставляется набор форм для каждого созданного представления ресурса изображения, что позволяет ему указать более подробную информацию о каждом (имя, описание и т. Д.).

Если не удается создать один или несколько ресурсов, обработчик POST прерывает всю обработку и добавляет каждое отдельное сообщение об ошибке в массив. Затем возвращается Конфликт 419, и пользователь перенаправляется на страницу ошибки 419 Конфликт, которая представляет содержимое массива ошибок, а также обратный путь к отправленной форме.


-2

Вы не захотите отправлять заголовки HTTP для 100 строк заказа. Вы также не хотите создавать больше запросов, чем необходимо.

Отправьте весь заказ в одном объекте JSON на сервер: server / order или server / order / new. Верните то, что указывает на: server / order / order_id

Также рассмотрите возможность использования CREATE PUT вместо POST


Я полагаю, это метод HTTP POST. Не существует такой вещи, как метод CREATE HTTP.
— Милан Новота, 04

Нет? Ой, подождите, не было. Вместо этого были PUT.
— Cheery

22
Зачем вам использовать PUT для создания контента? Именно для этого и предназначен метод HTTP POST.
— thecoshman

8
Вы используете PUT для создания ресурсов, когда хотите, чтобы клиент указывал URI ресурса, как в webdav. Я не согласен с использованием плаката PUT, но он имеет место в создании ресурсов, хотя это место может быть ограничено по объему.
— user602525

2
Примечание: POST-запрос объекта должен привести к тому, что объект станет подчиненным по отношению к ресурсу, указанному в запросе, и не будет идемпотентным. PUT заменяет объект по адресу и является идемпотентным. Идемпотентность (слово?) - важное ожидание потребителей.
— Люк Пуплетт 05
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.