Какие проверенные шаблоны проектирования существуют для пакетных операций с ресурсами в веб-службе в стиле REST?
Я пытаюсь найти баланс между идеалами и реальностью с точки зрения производительности и стабильности. Сейчас у нас есть API, где все операции извлекаются либо из ресурса списка (то есть: GET / user), либо из одного экземпляра (PUT / user / 1, DELETE / user / 22 и т. Д.).
В некоторых случаях вы хотите обновить одно поле целого набора объектов. Кажется очень расточительным отправлять полное представление для каждого объекта туда и обратно, чтобы обновить одно поле.
В API стиля RPC у вас может быть метод:
/mail.do?method=markAsRead&messageIds=1,2,3,4... etc.
Какой здесь REST-эквивалент? Или это нормально идти на компромисс сейчас и потом. Разве это разрушает дизайн, добавляя несколько определенных операций, где он действительно улучшает производительность и т. Д.? Клиент во всех случаях прямо сейчас является веб-браузером (приложение javascript на стороне клиента).
источник
PATCH
- нет необходимости в творчестве в этом случае.Совсем нет - я думаю, что эквивалент REST (или, по крайней мере, одно решение) почти точно таков - специализированный интерфейс, разработанный для выполнения операций, требуемых клиентом.
Мне вспоминается шаблон, упомянутый в книге Крейна и Паскарелло « Аякс в действии» (кстати, отличная книга - очень рекомендуется), в которой они иллюстрируют реализацию объекта типа CommandQueue , работа которого заключается в том, чтобы ставить запросы в пакеты и затем периодически отправляйте их на сервер.
Объект, если я правильно помню, по существу просто содержал массив «команд» - например, для расширения вашего примера, каждая из которых - запись, содержащая команду «markAsRead», «messageId» и, возможно, ссылку на обратный вызов / обработчик function - и затем по некоторому расписанию или по какому-либо действию пользователя объект команды будет сериализован и отправлен на сервер, а клиент будет обрабатывать последующую постобработку.
У меня нет подробностей, но похоже, что подобная очередь команд будет одним из способов решения вашей проблемы; это значительно уменьшило бы общение и абстрагировало бы интерфейс на стороне сервера таким образом, который вы могли бы найти более гибким в будущем.
Обновление : ага! Я нашел отрывок из этой самой книги в Интернете с примерами кода (хотя я все же предлагаю подобрать настоящую книгу!). Посмотрите здесь , начиная с раздела 5.5.3:
Вот две соответствующие функции - одна отвечает за добавление команд в очередь (
addCommand
), а другая отвечает за сериализацию и затем отправку их на сервер (fireRequest
):Это должно заставить вас идти. Удачи!
источник
Хотя я думаю, что @Alex идет по правильному пути, концептуально я думаю, что это должно быть наоборот того, что предлагается.
URL-адрес в действительности «ресурсы, на которые мы нацелены», следовательно:
значит получить запись из почты с идентификатором 1 и
означает исправление почтовой записи с идентификатором 1. Строка запроса является «фильтром», фильтрующим данные, возвращаемые из URL.
Поэтому здесь мы запрашиваем все письма, уже помеченные как прочитанные. Таким образом, [ПАТЧИРОВАТЬ] по этому пути можно было бы сказать «исправить записи, уже помеченные как истинные» ... что мы не пытаемся достичь
Таким образом, пакетный метод, следуя этому мнению, должен быть:
Конечно, я не говорю, что это действительно REST (который не позволяет манипулировать пакетной записью), скорее, он следует логике, уже существующей и используемой REST.
источник
[GET]
формату[PATCH] mail?markAsRead=true data: [{"id": 1}, {"id": 2}, {"id": 3}]
(или даже простоdata: {"ids": [1,2,3]}
)? Еще одно преимущество этого альтернативного подхода заключается в том, что вы не столкнетесь с ошибками «414 Request URI too long», если обновляете сотни / тысячи ресурсов в коллекции.Ваш язык, «Это кажется очень расточительным ...», для меня указывает на попытку преждевременной оптимизации. Если не будет показано, что отправка всего представления объектов является основным ударом по производительности (мы говорим неприемлемо для пользователей с> 150 мс), то нет смысла пытаться создать новое нестандартное поведение API. Помните, что чем проще API, тем проще его использовать.
Для удаления отправьте следующее, так как серверу не нужно ничего знать о состоянии объекта, прежде чем произойдет удаление.
Следующая мысль заключается в том, что если приложение сталкивается с проблемами производительности, связанными с массовым обновлением объектов, то следует рассмотреть возможность разбиения каждого объекта на несколько объектов. Таким образом, полезная нагрузка JSON является частью размера.
Например, при отправке ответа для обновления статусов «чтение» и «архивирование» двух отдельных писем вам нужно будет отправить следующее:
Я бы разделил изменяемые компоненты электронной почты (чтение, архивирование, важность, метки) на отдельный объект, так как остальные (к теме, тексту) никогда не будут обновлены.
Другой подход - использовать использование PATCH. Чтобы явно указать, какие свойства вы намереваетесь обновить и что все остальные должны игнорироваться.
Люди утверждают, что PATCH должен быть реализован путем предоставления массива изменений, содержащих: действие (CRUD), путь (URL) и изменение значения. Это может считаться стандартной реализацией, но если вы посмотрите на весь REST API, он не интуитивно понятен. Кроме того, в приведенной выше реализации GitHub реализовал PATCH .
Подводя итог, можно придерживаться принципов RESTful с пакетными действиями и при этом иметь приемлемую производительность.
источник
API Google Drive имеет действительно интересную систему для решения этой проблемы ( см. Здесь ).
В основном они группируют разные запросы в одном
Content-Type: multipart/mixed
запросе, каждый отдельный завершенный запрос разделяется определенным разделителем. Заголовки и параметры запроса пакетного запроса наследуются отдельным запросам (т. Е.Authorization: Bearer some_token
), Если они не переопределены в отдельном запросе.Пример : (взято из их документов )
Запрос:
Отклик:
источник
Я был бы соблазн в операции, подобной той, что в вашем примере, написать анализатор диапазона.
Нетрудно создать парсер, который может читать «messageIds = 1-3,7-9,11,12-15». Это, безусловно, повысит эффективность общих операций, охватывающих все сообщения, и будет более масштабируемым.
источник
Отличный пост. Я искал решение в течение нескольких дней. Я пришел к решению использовать передачу строки запроса с кучей идентификаторов, разделенных запятыми, например:
... затем передать это
WHERE IN
в мой SQL. Это прекрасно работает, но интересно, что другие думают об этом подходе.источник
DELETE /books/delete?id=1,2,3
когда книга № 3 не существует - ониWHERE IN
будут молча игнорировать записи, тогда как я обычно ожидаюDELETE /books/delete?id=3
404, если 3 не существует.С моей точки зрения, я думаю, что Facebook имеет лучшую реализацию.
Один HTTP-запрос выполняется с параметром пакета, а другой - для токена.
В пакет отправляется JSON. который содержит коллекцию «запросов». Каждый запрос имеет свойство метода (get / post / put / delete / etc ...) и свойствоlative_url (URI конечной точки), кроме того, методы post и put позволяют использовать свойство «body», в котором обновляются поля. посланы .
больше информации на: Facebook пакетного API
источник