Что использовать PATCH или POST? - PullRequest
3 голосов
/ 04 июня 2019

У меня был тихий долгий спор с моим коллегой о правильном HTTP-глаголе, который будет использоваться для одной из наших операций, которая изменяет СОСТОЯНИЕ ресурса.

Предположим, у нас есть ресурс с именем WakeUpLan, который пытается отправить событие в систему, подключенную к сети. Это своего рода универсальный конечный автомат,

{
id: 1,
retries: {
 idle: 5, // after 5 retries it went to FAILED state
 wakeup: 0,
 process: 0,
 shutdown: 0
},
status: 'FAILED',
// other attributes
}`

IDLE --> WAKEUP ---> PROCESS ---> SHUTDOWN | ----> [FAILED]

В каждом состоянии есть механизм повтора, т. Е. В случае IDLE он пытается x раз до transition до WAKEUP, а после x повторов он гаснет и переходит в состояние FAILED.

Все ресурсы FAILED могут быть снова перезапущены вручную или повторены еще раз с некоторого интерфейса.

Итак, у нас возникла путаница относительно того, какой глагол HTTP лучше всего подходит в этом случае.

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

PATCH retry/{id} {state: 'IDLE'}

Но мой коллега возражает против того, чтобы это был запрос POST, поскольку это чистое действие и должно рассматриваться как POST. Я не уверен, потому что мы не создаем какой-либо новый ресурс, а просто обновляем существующий ресурс, о котором наш REST-сервер уже знает.

Я хотел бы знать и исправить, если я здесь не прав.

Любые предложения / советы приветствуются.

Заранее спасибо.

Ответы [ 3 ]

1 голос
/ 04 июня 2019

Основы HTTP

PATCH

Что такое PATCH на самом деле? PATCH - это HTTP-метод, определенный в RFC 5789 , который похож на исправление кода в программной инженерии, где необходимо применить изменение к одному или нескольким источникам для преобразования целевого ресурса в желаемый результат. Таким образом, клиент вычисляет набор инструкций, которые целевая система должна применить полностью, чтобы сформировать запрошенный результат. Эти инструкции обычно называют «патч», в словах RFC 5789 такой набор инструкций называется «патч-документ».

RFC 5789 не определяет, в каком представлении такой патч-документ необходимо перенести из одной системы в другую. Для представлений на основе JSON можно использовать application / json-patch + json (RFC 6902) , который содержит определенные инструкции, такие как add, replace, move, copy, ... которые более или менее ясно, что они делают, но RFC также описывает каждую из доступных инструкций далее.

Еще один, основанный на JSON, но совершенно иной способ информирования системы о том, как изменить ресурс (или документ), описан в application / merge-patch + json (RFC 7386) . В отличие от json-patch, этот медиа-тип определяет набор правил по умолчанию, которые применяются при получении представления на основе JSON к фактическому целевому ресурсу. Здесь на сервер отправляется одно JSON-представление измененного состояния, которое содержит только поля и объекты, которые должны быть изменены сервером. Правила по умолчанию определяют, что поля, которые должны быть удалены из целевого ресурса, должны быть аннулированы в запросе, в то время как поля, которые должны измениться, должны содержать новое значение для применения. Поля, которые остаются неизменными, могут быть пропущены в запросе.

Если вы прочитаете RFC 5789, вы увидите, что merge-patch - это еще один взлом. По сравнению с json-patch представлению слияния-патча не хватает контроля фактической последовательности, в которой применяются инструкции, что может быть не всегда необходимо, а также отсутствие одновременного изменения нескольких различных ресурсов.

PATCH само по себе не идемпотентно. Для документа патча json-patch довольно ясно, что применение одних и тех же инструкций несколько раз может привести к разным результатам, т. Е. Если вы удалите первое поле. Документ merge-patch здесь ведет себя подобно «частичному запросу PUT», который многие разработчики выполняют из-за прагматизма, хотя фактическая операция все еще не гарантирует идемпотентность. Чтобы избежать непреднамеренного многократного применения одного и того же исправления к одному и тому же ресурсу, т. Е. Из-за сетевых ошибок при передаче документа исправления, рекомендуется использовать PATCH наряду с условными запросами (RFC 7232) . Это гарантирует, что изменения будут применены только к определенной версии ресурса, и если этот ресурс был изменен либо с помощью предыдущего запроса, либо из внешнего источника, запрос будет отклонен, чтобы предотвратить потерю данных. Это в основном оптимистичная блокировка.

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

POST

POST метод определен в RFC 7231 как:

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

Это, по сути, карта «бесплатно из тюрьмы», которая позволяет вам делать все, что вы хотите или должны делать здесь. Вы можете определить синтаксис и структуру для получения на определенной конечной точке. Большинство из этих так называемых «API-интерфейсов REST» рассматривают POST как C в CRUD, для которого он может использоваться, но это просто упрощение того, что он на самом деле может сделать для вас. HTML в основном поддерживает только операции POST и GET, поэтому запросы POST используются для отправки всех видов данных на сервер для запуска процессов поддержки, создания новых ресурсов, таких как публикации в блогах, вопросы и ответы, видео, ... но также, чтобы удалить или обновить материал.

Практическое правило: если новый ресурс создается в результате запуска запроса POST для определенного URI, код ответа должен быть 201 Created, содержащий заголовок ответа HTTP Location с URI в качестве значения. это указывает на недавно созданный ресурс. В любом другом случае POST не отображается на C (создание) стереотипа CRUD.

REST связанные

REST - это не протокол, а архитектурный стиль. Как заявил Роберт (дядя Боб) К. Мартин , архитектура имеет намерение , а намерение REST заключается в том, чтобы отделить клиентов от серверов, что позволяет последнему свободно развиваться, сводя к минимуму проблемы совместимости из-за изменения, внесенные сервером.

Это очень сильные преимущества, если ваша система все еще будет работать в ближайшие десятилетия. Однако эти преимущества, к сожалению, получить нелегко. Как указано в Fieldings диссертации , чтобы извлечь выгоду из REST, необходимо строго соблюдать упомянутые ограничения, в противном случае связи останутся, увеличивая вероятность разрыва клиентов из-за изменений. Позже Филдинг рассердился на людей, которые не читали или не поняли его диссертацию и выяснили, что REST API должен делать в двух словах .

Эта напыщенная речь может быть сведена к следующим пунктам:

  • API должен придерживаться и не нарушать базовый протокол. Хотя REST чаще всего используется через HTTP, он не ограничен этим протоколом.
  • Сильный акцент на ресурсах и их представлении через медиа-типы.
  • Клиенты не должны иметь начальных знаний или предположений о доступных ресурсах или их возвращаемом состоянии ( «типизированный» ресурс ) в API, но изучать их на лету через выданные запросы и ответы, которые обучают клиентов тому, что они могут делать дальше. Это дает серверу свободу в своем пространстве имен и перемещает все, что ему нужно, без негативного влияния на клиентов.

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

Общие типы медиа предоставляют возможность того, что система может делать с данными, полученными для этой полезной нагрузки, в то время как согласование типа контента гарантирует, что и отправитель, и получатель могут обрабатывать и пониматьполезная нагрузка правильно.Доступность может отличаться от типа носителя к типу носителя.Полезная нагрузка, полученная для image/png, может отображаться и показываться пользователю, тогда как application/vnd.acme-form+json может определять форму, в которой сервер обучает клиента элементам запроса, которые сервер поддерживает, а клиент может вводить данные и выдаватьзапросить без необходимости активно знать метод для использования или целевой URI для отправки данных, поскольку это уже задано сервером.Это не только устраняет необходимость во внеполосной (внешней) документации API, но также и необходимость для клиента анализировать или интерпретировать URI, поскольку все они предоставляются сервером, сопровождаемые link-Relations ,которые должны быть либо стандартизированы IANA , следовать общепринятым соглашениям, таким как существующие микроформаты значений Rel или онтологий типа Dublin Core , или представлять типы расширений, как определенов RFC 5988 (веб-ссылка) .

Вопрос, связанный с

Когда вступление закончено, я надеюсь, что для вопроса, подобного

Но мой коллега выступает против POST-запроса, так как эточистое действие и должно рассматриваться как POST.Я не убежден, потому что мы не создаем какой-либо новый ресурс, а просто обновляем существующий ресурс, который наш REST-сервер уже знает об этом

, ясно, что нет определенного да или нет ответ на этот квест, но больше это зависит .

Есть пара вопросов, которые можно задать, например:

  • Сколько (разных) клиентов будут использовать эту услугу?Они все под вашим контролем?Если это так, вам не нужен REST, но вы все равно можете стремиться к нему
  • Как обучают или инструктируют клиента выполнять обновление?Будете ли вы предоставлять внешнюю документацию по API?Будете ли вы поддерживать медиа-тип, который поддерживает формы, такие как HTML , hal-формы , halo + json , Ion или Hydra

В общем, если у вас несколько клиентов, особенно тех, которые не находятся под вашим контролем, вы можете не знать, какие возможности они поддерживают.Здесь согласование типа контента является важной частью.Если клиент поддерживает application/json-patch+json, он также может рассчитать документ исправления, содержащий инструкции для применения к целевому ресурсу.Вероятность того, что он также будет поддерживать PATCH, также очень высока, поскольку RFC 6902 упоминает об этом.В таком случае имеет смысл предоставить конечную точку PATCH, на которую клиент может отправить запрос.

Если клиент поддерживает application/patch-merge+json, можно предположить, что он также поддерживает PATCH, поскольку он в первую очередь предназначен для использования с методом HTTP PATCH, согласно RFC 7386. Здесь обновление со стороны клиентаперспектива довольно тривиальна, поскольку обновленный документ отправляется на сервер как есть.

В любом другом случае менее понятно, в каких форматах представления изменения будут переданы на сервер. Здесь, POST, вероятно, путь. С позиции REST обновление здесь, вероятно, должно быть похоже на обновление данных, которые редактируются в веб-форме в вашем браузере, при этом текущий контент загружается в каждый элемент формы, и клиент изменяет эти элементы формы по своему усмотрению. а затем отправляет изменения обратно на сервер в, вероятно, application/x-www-form-urlencoded (или подобной) структуре. В таком случае, однако, PUT, вероятно, будет более подходящим, поскольку в таком случае вы передадите полностью обновленное состояние ресурса обратно в службу и, следовательно, выполните полное обновление, а не частичное обновление целевого ресурса. Фактический медиа-тип, который будет отправлен формой, вероятно, определен в медиа-типе соответствующей формы. Обратите внимание, что это не означает, что вы не можете обрабатывать документы json-patch или merge-patch в POST.

Здесь будет практическое правило: чем больше форматов медиа-типов и методов HTTP вы поддерживаете, тем больше вероятность того, что разные клиенты смогут выполнить свою задачу.

1 голос
/ 04 июня 2019

Любые предложения / советы приветствуются.

Эталонная реализация REST архитектурного стиля - это всемирная паутина.Всемирная паутина построена на основе URI, HTTP и HTML - и обработка форм HTML ограничена GET и POST.

Так что POST должно быть an приемлемый ответ.В конце концов, сеть была катастрофически успешной.

PATCH, как и PUT, позволяет сообщать об изменениях в представлении ресурса.Семантика более специфична, чем POST, что позволяет клиенту лучше использовать преимущества.Поэтому, если все, что вы делаете, - это создаете сообщение, описывающее локальные изменения в представлении ресурса, тогда PATCH - отличный выбор.

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

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

POST гораздо более общий, чем "создание нового ресурса"».Исторически сложилось много путаницы вокруг этого пункта (язык в ранних спецификациях HTTP не помог).

0 голосов
/ 04 июня 2019

Я бы сказал, что вы правы, поскольку вы не создаете новый ресурс. Выделите часть с надписью «использовать», когда вы изменяете весь существующий ресурс, и использовать патч, когда вы изменяете один компонент существующего ресурса. Больше здесь https://restfulapi.net/rest-put-vs-post/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...