tl; dr
Вам будет хорошо с одной конечной точкой, поддерживающей PATCH
, если вы все сделаете правильно.
Полезная нагрузка запроса PATCH
должна содержать набор инструкций для изменения целевого ресурса. Подходящими форматами для представления этого набора инструкций являются JSON Patch и JSON Merge Patch (и они допускают модификации для вложенных значения в целевом документе JSON).
Выполнение изменений состояния ресурса
Для выполнения изменений ресурса можно использовать PUT
или PATCH
(или обе). Однако разница между этими методами отражается в способе обработки сервером полезной нагрузки запроса для изменения целевого ресурса:
В запросе PUT
полезная нагрузка составляет измененная версия ресурса, хранящегося на сервере. И клиент запрашивает, чтобы сохраненная версия была заменена новой версией. Поэтому он может быть не совсем подходящим для частичных модификаций.
В запросе PATCH
полезная нагрузка запроса содержит набор инструкций описание того, как ресурс, хранящийся в данный момент на сервере, должен быть изменен для создания новой версии. Это означает, что это наиболее подходящий подход для выполнения частичных модификаций ресурса.
Чтобы прояснить ситуацию, я собрал несколько примеров ниже.
Использование PUT
Рассмотрим, например, вы создаете API для управления контактами. На сервере у вас есть ресурс, который может быть представлен следующим документом JSON:
{
"id": 1,
"name": "John Appleseed",
"work": {
"title": "Engineer",
"company": "Acme"
},
"phones": [
{
"phone": "0000000000",
"type": "mobile"
}
]
}
Допустим, Джон назначен старшим инженером, и вы хотите, чтобы ваш список контактов обновлялся. Мы могли бы изменить этот ресурс с помощью запроса PUT
, как показано ниже:
PUT /contacts/1 HTTP/1.1
Host: example.org
Content-Type: application/json
{
"id": 1,
"name": "John Appleseed",
"work": {
"title": "Senior Engineer",
"company": "Acme"
},
"phones": [
{
"phone": "0000000000",
"type": "mobile"
}
]
}
При PUT
полное представление нового состояния ресурса должно быть отправлено на сервер, даже когда вам нужно изменить одно поле ресурса, что может быть нежелательно в некоторых ситуациях.
Из RF C 7231 :
4.3.4. PUT
Метод PUT
запрашивает, чтобы состояние целевого ресурса было создано или заменено на состояние, определенное представлением, включенным в полезную нагрузку сообщения запроса. […]
Использование PATCH
Определение метода PATCH
, однако, не предусматривает никакого формата для полезной нагрузки запроса, кроме упоминания о том, что полезная нагрузка запроса должна содержать набор инструкций, описывающих, как ресурс будет изменен, и этот набор инструкций идентифицируется типом носителя (который определяет, как сервер должен применять PATCH
).
Из RF C 5789 :
2. Метод PATCH
Метод PATCH
запрашивает, чтобы набор изменений, описанный в объекте запроса, был применен к ресурсу, идентифицированному Request-URI. Набор изменений представлен в формате, называемом «документ патча», идентифицируемый типом носителя. […]
Некоторые подходящие форматы для описания такого набора изменений перечислены ниже:
JSON Патч
Выражает последовательность операций, которые должны быть применены к документу JSON. Он определен в RF C 6902 и идентифицируется типом носителя application/json-patch+json
.
Документ исправления JSON представляет массив объектов, а каждый объект представляет отдельный операция, которая будет применена к целевому документу JSON.
Оценка документа JSON Patch начинается с целевого документа JSON, и операции применяются последовательно в порядке их появления в массиве. Каждая операция в последовательности применяется к целевому документу, а результирующий документ становится целью следующей операции. Оценка продолжается до тех пор, пока все операции не будут успешно применены или пока не возникнет условие ошибки.
Объекты операций должны иметь ровно один элемент op
, значение которого указывает операцию, которую необходимо выполнить:
add
: добавляет значение в целевое местоположение; если значение существует в указанном местоположении, оно заменяется. remove
: удаляет значение в целевом местоположении. replace
: Заменяет значение в целевом местоположении. move
: удаляет значение в указанном местоположении и добавляет его в целевое местоположение. -
copy
: копирует значение в указанном месте в целевое местоположение. test
: проверяет, что значение в целевом местоположении равно указанному значению.
Любые другие значения считаются ошибками.
Сказав это, запрос на изменение названия должности Джона может быть:
PATCH /contacts/1 HTTP/1.1
Host: example.org
Content-Type: application/json-patch+json
[
{ "op": "replace", "path": "/work/title", "value": "Senior Engineer" }
]
JSON Merge Patch
Это формат, который описывает изменения, которые должны быть внесены в целевой документ JSON с использованием синтаксиса, который близко имитирует изменяемый документ. Он определен в RF C 7396 и идентифицируется типом носителя application/merge-patch+json
.
Сервер, обрабатывающий документ JSON Merge Patch, определяет точный набор изменений запрашивается путем сравнения содержимого предоставленного исправления с текущим содержимым целевого документа:
- Если исправление слияния содержит элементы, которые не отображаются в целевом документе, эти элементы добавляются.
- Если цель содержит элемент, значение заменяется.
null
значения в патче слияния указывают, что существующие значения в целевом документе должны быть удалены. - Другое значения в целевом документе останутся без изменений.
При этом запрос на изменение названия должности Джона может быть следующим:
PATCH /contacts/1 HTTP/1.1
Host: example.org
Content-Type: application/merge-patch+json
{
"work": {
"title": "Senior Engineer"
}
}
Нижняя строка
Когда Что касается изменения состояния ресурса, то использование PUT
и PATCH
в конечном итоге зависит от ваших потребностей. Выберите один, другой или оба. Но придерживайтесь стандартов при их поддержке:
Если вы решите поддерживать PUT
, полезная нагрузка запроса должна быть новым представлением ресурса (поэтому сервер заменит состояние ресурса).
Если вы решите поддерживать PATCH
, используйте стандартный формат для полезной нагрузки, такой как JSON Patch или JSON Merge Патч (содержит набор инструкций, которые сообщают серверу, как изменить состояние ресурса).
Существует множество библиотек для разбора JSON Патч документы, так что не изобретай велосипед. Если вы считаете, что JSON Patch слишком сложен для ваших нужд, используйте JSON Merge Patch. Если вам удобны оба формата, то ничто не мешает вам поддерживать оба формата.
И, так как оба формата позволяют вам изменять вложенные значения в вашем документе JSON, вам будет хорошо с одной конечной точкой для PATCH
даже если вам нужно разрешить изменение вложенных значений или вашего ресурса.
Проверка состояния ваших ресурсов
Если вы беспокоитесь о том, как сохранить согласованность после применения PATCH
к вашим ресурсам, я рекомендую взглянуть на этот ответ . Короче говоря, вам рекомендуется отделить модели, представляющие ваши ресурсы API, от моделей, представляющих ваш домен.
Итак, при обработке запроса PATCH
:
- Извлечение экземпляра модели домена, который вы собираетесь обновить.
- Преобразование модели домена в соответствующую модель ресурсов API.
- Применение исправления к модели ресурсов API.
- Преобразование модели ресурсов API с обновлениями обратно в модель домена.
- Проверка состояния модели домена:
- Если состояние действительно, примите запрос и сохраните изменения, внесенные в модель домена.
- В противном случае отклоните запрос.
Вы может также захотеть обратиться к RF C 5789 за подробностями о обработке ошибок при обработке PATCH
запроса.
Дальнейшее чтение (особенно если вы используете Java и Spring)
В случае, если вы используете Java и Spring, вы можете посмотреть это сообщение из моего блога. Если вы не используете Java или Spring, соображения, касающиеся изменения ресурсов с помощью PUT
или PATCH
, в первой части поста могут по-прежнему вас интересовать (хотя я неплохо суммировал основную идею в этом ответе) .