it-swarm.com.ru

ОТДЫХ: Обновление нескольких ресурсов с помощью одного запроса - это стандарт или его следует избегать?

Простой REST API:

  • GET: items/{id} - возвращает описание элемента с заданным идентификатором.
  • PUT: items/{id} - обновляет или создает элемент с заданным идентификатором
  • DELETE: items/{id} - удаляет элемент с указанным идентификатором.

Теперь об API-расширении идет речь:

  • GET: items? Filter - возвращает все идентификаторы элементов, соответствующие фильтру
  • PUT: items - обновляет или создает набор элементов, как описано в полезной нагрузке JSON.
  • [[УДАЛИТЬ: элементы - удаляет список элементов, описанных полезной нагрузкой JSON]] <- Неправильно

Теперь меня интересуют функции утилизации операций DELETE и PUT, к которым легко получить доступ через PUT/DELETE items/{id}. 

Вопрос: распространено ли предоставлять такой API?

Альтернатива: в эпоху одиночных подключений множественные запросы выдача нескольких запросов обходится дешево и будет работать более атомарно, поскольку изменение либо завершается успешно, либо не удается, но в эпоху базы данных NOSQL изменение в списке уже могло произойти, даже если обработка запроса заканчивается внутренний сервер или что-то по той или иной причине.

[Обновление]

После рассмотрения Веб-стандартов Белого дома и Википедии: REST Примеры теперь намечается следующий Пример API:

Простой REST API:

  • GET: items/{id} - возвращает описание элемента с заданным идентификатором.
  • PUT: items/{id} - обновляет или создает элемент с заданным идентификатором
  • DELETE: items/{id} - удаляет элемент с указанным идентификатором.

Топ-ресурс API:

  • GET: items? Filter - возвращает все идентификаторы элементов, соответствующие фильтру
  • POST: items - обновляет или создает набор элементов, как описано в полезной нагрузке JSON.

PUT и DELETE on/items не поддерживаются и запрещены.

Использование POST, по-видимому, позволяет создать новые элементы во вложенном ресурсе, не заменяя, а добавляя.

Семантика HTTP POST Читает:

Расширение базы данных с помощью операции добавления

Где методы PUT потребуют заменить полную коллекцию, чтобы вернуть эквивалентное представление, указанное в HTTP Semantics PUT :

Успешное PUT данного представления предполагает, что последующее GET на том же целевом ресурсе приведет к тому, что эквивалентное представление будет возвращено в ответе 200 (ОК).

[ОБНОВЛЕНИЕ2]

Альтернативой, которая кажется еще более последовательной для аспекта обновления нескольких объектов, является метод PATCH. Разница между PUT и PATCH описана в проекте RFC 5789 как:

Разница между запросами PUT и PATCH отражается в способе, которым сервер обрабатывает вложенный объект для изменения ресурса, идентифицируемого Request-URI. В запросе PUT вложенный объект считается модифицированной версией ресурса, хранящегося на сервере-источнике, и клиент запрашивает замену сохраненной версии. Однако с помощью PATCH вложенный объект содержит набор инструкций, описывающих, как ресурс, находящийся в данный момент на сервере Origin, должен быть модифицирован для создания новой версии. Метод PATCH влияет на ресурс, идентифицируемый Request-URI, и он также МОЖЕТ иметь побочные эффекты на других ресурсах; то есть, новые ресурсы могут быть созданы, или существующие изменены, путем применения PATCH.

Таким образом, по сравнению с POST, PATCH также может быть лучшей идеей, так как PATCH допускает ОБНОВЛЕНИЕ, когда POST позволяет только добавлять что-то, что означает добавление без возможности изменения.

Так что POST здесь не так, и нам нужно изменить предложенный нами API на:

Простой REST API:

  • GET: items/{id} - возвращает описание элемента с заданным идентификатором.
  • PUT: items/{id} - обновляет или создает элемент с заданным идентификатором
  • DELETE: items/{id} - удаляет элемент с указанным идентификатором.

Топ-ресурс API:

  • GET: items? Filter - возвращает все идентификаторы элементов, соответствующие фильтру
  • POST: items - создает один или несколько элементов, как описано в полезной нагрузке JSON.
  • PATCH: items - создает или обновляет один или несколько элементов, как описано в полезной нагрузке JSON.
43
Martin Kersten

Вы можете залатать коллекцию, например 

PATCH /items
[ { id: 1, name: 'foo' }, { id: 2, name: 'bar' } ]

Технически PATCH идентифицирует запись в URL (т. Е. PATCH /items/1, а не в теле запроса, но это кажется хорошим прагматическим решением).

Поддерживать удаление, создание и обновление в одном вызове, что на самом деле не поддерживается стандартными REST соглашениями. Одной из возможностей является специальный «пакетный» сервис, который позволяет собирать вызовы вместе:

POST /batch
[
  { method: 'POST', path: '/items', body: { title: 'foo' } },
  { method: 'DELETE', path: '/items/bar' }
]

который возвращает ответ с кодами состояния для каждого встроенного запроса:

[ 200, 403 ]

Не совсем стандартно, но я сделал это, и это работает.

35
mahemoff

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

В этих примерах в Википедии они также говорят о ресурсах во множественном числе.

1
Kris

Обновление нескольких ресурсов с помощью одного запроса - это стандарт или его следует избегать?

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

Это стандарт?

Не существует общепринятого стандарта API REST, поэтому на этот вопрос сложно ответить. Но, взглянув на некоторые часто цитируемые рекомендации по разработке API, такие как jsonapi.org , restfulapi.net , Руководство по разработке API Microsoft или IBM REST Соглашения API , в которых все не упоминаются пакетные операции, можно сделать вывод, что такие операции обычно не понимаются как стандартная функция API REST.

Тем не менее, исключением является руководство по разработке API Google, в котором упоминается создание «пользовательских» методов, которые могут быть связаны через ресурс с помощью двоеточия, например, https://service.name/v1/some/resource/name:customVerb, он также явно упоминает пакетные операции как вариант использования:

Пользовательский метод может быть связан с ресурсом, коллекцией или службой. Он может принимать произвольный запрос и возвращать произвольный ответ, а также поддерживает потоковый запрос и ответ. [...] Пользовательские методы должны использовать HTTP-глагол POST, поскольку он обладает наиболее гибкой семантикой [...]. Для методов, критичных к производительности, может быть полезно предоставлять пользовательские пакетные методы для сокращения накладных расходов на запрос.

Таким образом, в приведенном вами примере вы делаете следующее в соответствии с руководством API Google:

POST /api/items:batchUpdate

Кроме того, некоторые общедоступные API решили предложить центральную конечную точку /batch, например, API gmail Google .

Более того, как упомянутый на restfulapi.net, существует также концепция ресурса «хранилище», в которой вы сохраняете и извлекаете целые списки элементов сразу через PUT - однако эта концепция не учитывается для управляемые сервером коллекции ресурсов:

Хранилище - это управляемый клиентом репозиторий ресурсов. Ресурс хранилища позволяет клиенту API вставлять ресурсы, возвращать их обратно и решать, когда их удалять. Магазин никогда не генерирует новые URI. Вместо этого каждый хранимый ресурс имеет URI, который был выбран клиентом, когда он был первоначально помещен в хранилище.


Ответив на ваши первоначальные вопросы, вот еще один подход к вашей проблеме, который еще не был упомянут. Обратите внимание, что этот подход немного необычен и выглядит не так, как типичная схема именования конечных точек API REST. Я лично не придерживаюсь этого подхода, но я все еще чувствовал, что нужно подумать :)

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

Например, рассмотрим RESTful API, который позволяет вам выполнять операции CRUD на «корпоративном» ресурсе, и вы также хотите выполнить некоторые связанные с «компанией» операции, которые не вписываются в ресурсно-ориентированную CRUD-схему, обычно связанную с API-интерфейсом restful. - такие как пакетные операции, которые вы упомянули.

Теперь вместо того, чтобы показывать свои ресурсы непосредственно под /api/companies (например, /api/companies/22), вы можете различать:

  • /api/companies/items - то есть набор ресурсов компании
  • /api/companies/ops - то есть операции, связанные с ресурсами компании

Для items применяются обычные HTTP-методы RESTful api и схемы именования ресурсов-URL (например, как обсуждалось здесь или здесь )

POST    /api/companies/items
GET     /api/companies/items
GET     /api/companies/items/{id}
DELETE  /api/companies/items/{id}
PUT     /api/companies/items/{id}

Теперь для операций, связанных с компанией, вы можете использовать префикс /api/companies/ops/ route и операции вызова через POST.

POST    /api/companies/ops/batch-update
POST    /api/companies/ops/batch-delete
POST    /api/companies/ops/garbage-collect-old-companies
POST    /api/companies/ops/increase-some-timestamps-just-for-fun
POST    /api/companies/ops/perform-some-other-action-on-companies-collection

Поскольку запросы POST не должны приводить к созданию ресурса, POST является правильным методом для использования здесь:

Действие, выполняемое методом POST, может не привести к ресурсу, который может быть идентифицирован по URI . https://tools.ietf.org/html/rfc2616#section-9.5

1
B12Toaster