Конечная точка REST для сложных действий - PullRequest
0 голосов
/ 28 февраля 2020

У меня есть REST API, который передает данные из базы данных во внешнее приложение React и в приложение Android. API имеет несколько общих конечных точек для каждой модели:
- GET /model/<id> для извлечения одного объекта
- POST /model для создания
- PATCH /model/<id> для обновления отдельной модели
- GET /model для перечисления объектов
- DELETE /model/<id> для удаления объекта

В настоящее время я занимаюсь разработкой приложения Android и нахожу такую ​​схему, которая заставляет меня делать много дополнительных запросов к API. Например, каждый объект Order имеет запись user_creator. Итак, если я хочу удалить все заказы, созданные указанным пользователем, мне нужно
1) Список всех пользователей GET /user
2) Выберите нужный мне
3) Список всех созданных им заказов GET /order?user=user_id
4) Выберите ордер, который я хочу удалить
5) Удалите ордер DELETE /order/<id>

Мне интересно, будет ли это нормально, добавить несколько конечных точек, таких как GET /order/delete?user=user_id. Делая это, я могу избавиться от действий 4 и 5. И вся фильтрация будет выполняться на бэкэнде. Однако мне кажется, что это плохое архитектурное решение, потому что все API, которые я использовал ранее, не имеют таких методов, а все функции фильтрации, сортировки и других «украшающих» функций обычно находятся на стороне пользователя API, а не на бэкэнде.

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

Ответы [ 2 ]

0 голосов
/ 29 февраля 2020

Ваша проблема изолирована:

  • У вас есть коллекция заказов и коллекция пользователей
  • Пользователь 1 .. * Заказы
  • Вы хотите удалить все заказы для данного идентификатора пользователя

Я бы использовал следующий URI:

// delete all orders for a given user
POST /users/:id/orders/delete

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

// get all orders for a given user
GET /users/:id/orders
0 голосов
/ 28 февраля 2020

Доменом приложения HTTP является передача документов по сети. Ваш «REST API» - это фасад, который действует как хранилище документов и выполняет полезную работу в качестве побочного эффекта передачи документов. См. Джим Уэббер (2011) .

Итак, основные идиомы c в том, что мы публикуем документ или отправляем кучу правок в существующий документ, и сервер интерпретирует их изменяется и делает что-то полезное.

Таким образом, простой протокол, основанный на существующей семантике удаленной авторизации, может выглядеть как

GET /orders?user=user_id

Make local edits to the representation of that list provided by the server

PUT /orders?user=user_id

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

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

Итак, мы загружаем пустую форму в наш браузер, и мы вносим в него изменения, а затем публикуем его на ресурсе, указанном в форме.

GET /the-blank-form?user=user_id

Make changes in the form...

POST ????

Каким должен быть target-uri? Веб-браузер не волнует; он просто собирается отправить форму любой цели, указанной в представлении, которое он получил. Одним из ответов может быть отправка его обратно туда, где мы его получили:

POST /the-blank-form?user=user_id

И это прекрасно работает (если вы правильно управляете метаданными). Другая возможность - вместо этого отправить изменения в ресурс, который вы ожидаете, чтобы отразить эти изменения:

POST /orders?user=user_id

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

В настоящее время мой API удовлетворяет таблице в нижней части REST, поэтому любая дополнительная конечная точка нарушит его. Будет ли это фатальным или нет, вот в чем вопрос.

Нет, все будет хорошо - просто добавьте / расширите обработчик POST на соответствующем ресурсе для обработки новой семантики.

Более длинный ответ: таблица в Википедии - хорошее представление о распространенных практиках; но обычные практики не совсем на высоте. Частично проблема заключается в том, что REST включает единый интерфейс . Помимо прочего, это означает, что все ресурсы понимают одну и ту же семантику сообщений. Понятие «ресурсы коллекции» и «ресурсы члена» не существует в REST - семантика для них одинакова.

Другой способ сказать, что компонент общего назначения никогда не знает, является ли ресурс, с которым он разговаривает, является коллекцией или членом. Все небезопасные методы (POST / PUT / PATCH / DELETE / et c) подразумевают аннулирование представлений target-uri.

Теперь POST, как это происходит, означает «делать что-то, что не было стандартизировано "- см. Fielding 2009 . Этот метод имеет наименьшее количество ограничений semanti c.

Метод POST запрашивает, чтобы целевой ресурс обработал представление, заключенное в запросе, в соответствии с собственной спецификацией семантики c ресурса. - RF C 7231

Для обработчика POST прекрасно подходит ветвление на основе содержимого полезной нагрузки запроса; если вы видите X, создайте что-то, если вы видите Y, удалите что-то еще. Это аналогично наличию двух разных веб-форм с различной семантикой, которые подчиняются одному и тому же целевому ресурсу.

...