ReST - PUT против PATCH, чтобы минимизировать связь между клиентом и API при добавлении новых свойств - PullRequest
1 голос
/ 22 апреля 2020

Мы создаем набор новых API REST.

Допустим, у нас есть ресурс /users со следующими полями:

{
  id: 1
  email: "test@user.com"
}

Клиенты реализуют этот API и могут затем обновить его ресурс, отправив новое представление ресурса в PUT /users/1.

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

{
  id: 1
  email: "test@user.com"
  name: "test user"
}

Если моделирует существующие клиенты Вы используете вызов API, который не обновляется, затем вызовы PUT /users/1 удаляют новое свойство name, поскольку предполагается, что PUT заменит ресурс. Я знаю, что клиенты могут работать напрямую с необработанным json, чтобы гарантировать, что они всегда получают любые новые свойства, добавленные в API, но это большая дополнительная работа, и при нормальных обстоятельствах клиенты собираюсь создать свои собственные модельные представления ресурсов API на их стороне. Это означает, что каждый раз, когда добавляется любое новое свойство, все клиенты должны обновлять код / ​​модели на своей стороне, чтобы убедиться, что они случайно не удаляют свойства. Это создает ненужную связь между системами.

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

Как другие решают эту проблему? Была ли здесь лучшая практика?

Ответы [ 2 ]

0 голосов
/ 23 апреля 2020

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

Таким образом, вы можете поддерживать более старые версии, и PUT будет вполне законным.

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

0 голосов
/ 22 апреля 2020

Переключение с PUT на PATCH не решит вашу проблему, ИМО. Причина root, IMO, заключается в том, что клиенты уже считают, что возвращаемые данные для представления соответствуют определенному типу. Согласно Филдингу

API REST никогда не должен иметь «типизированных» ресурсов, значимых для клиента.
( Источник )

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

Подумайте о веб-странице производителя автомобиля где вы можете получить данные из вашего предпочтительного автомобиля. Вы, как человек, легко можете определить, что на данных изображен типичный автомобиль. Однако тип носителя, в который вы, вероятнее всего, получили данные (HTML), по своему синтаксису или семантике элементов не указывает, что данные описывают автомобиль, если не присутствуют некоторые атрибуты или элементы аннотации semanti c, хотя вы можете обновить данные или использовать данные в другом месте.

Это возможно, поскольку HTML поставляется с богатой спецификацией его элементов и атрибутов, таких как Веб-формы , которые описывают не только поддерживаемые или ожидаемые входные параметры, но также URI, куда следует отправлять данные, формат представления, используемый при отправке (неявно заданный application/x-www-form-urlencoded; может быть перезаписан атрибутом enctype, хотя) или метод HTTP использовать, для которого установлено значение GET или POST в HTML. Благодаря этому сервер может обучить клиента тому, как должен быть построен запрос. Как следствие, клиенту не нужно знать ничего другого, кроме необходимости понимать спецификации HTTP, URI и HTML.

Поскольку веб-страницы, как правило, заполнены всевозможными несвязанными материалами, такими как добавления, информация о стилях или скрипты, а также синтаксис XML (- как), который не всем нравится, так как он может увеличиваться При небольшом размере реальной полезной нагрузки большинство так называемых API REST хотят обмениваться документами JSON. Хотя обычный JSON не является идеальным форматом представления, поскольку он вообще не поставляется с поддержкой ссылок, он очень популярен. В некоторых дополнениях, таких как JSON Гипер-схема (application/schema+json hyper-schema) или JSON Язык приложений гипертекста (HAL) (application/hal+json), добавлена ​​поддержка ссылок и ссылок. связь. Их можно использовать для визуализации данных, полученных с сервера как есть . Однако, если вы хотите, чтобы ответ автоматически управлял состоянием вашего приложения (т. Е. Для динамического рисования GUI с обработанными данными), необходим более конкретный формат представления c, который может быть проанализирован вашим клиентом и действовать соответственно так, как он понимает, что сервер хочет от него сделать (= уступчивость ). Если вы хотите указать клиенту, как создать поддержку запросов для других типов носителей, таких как hal-формы или ion , необходимо поддерживать. Кроме того, некоторые типы носителей позволяют использовать концепцию, называемую профилями, которая позволяет аннотировать ресурс с типом semanti c. HAL JSON т.е. поддерживает что-то подобное, где заголовок Content-Type может теперь содержать значение, такое как application/hal+json;profile=http://schema.org/Car, которое намекает процессору медиа-типа, что полезная нагрузка соответствует определению данного профиля и Таким образом, могут применяться дополнительные проверки достоверности.

Поскольку формат представления должен быть достаточно обобщенным c, чтобы получить широкое использование, а сами URI не должны также намекать клиенту, какие данные ожидать, другой механизм должен быть использован. Имена отношений ссылок в основном представляют собой аннотации для URI, которые сообщают клиенту о назначении определенной ссылки. Размещаемая на странице коллекция может возвращать ссылки, отмеченные first, prev, next и last, что довольно очевидно, что они делают. Другие ссылки могут указывать на prefetch, что намекает клиенту на то, что ресурс может быть загружен сразу после завершения загрузки текущего ресурса, так как очень вероятно, что клиент получит этот ресурс следующим. Однако такие типы носителей должны быть либо стандартизированными (определенными в предложении или RF C и зарегистрированными в IANA), либо следовать схеме, предложенной Веб-связью (т.е. как используется Dublin Core ). Клиент, который просто использует URI для вызванного имени отношения ссылки, будет по-прежнему работать в случае, если сервер изменяет свою схему URI вместо попытки проанализировать некоторые параметры из самого URI.

В отношении де / связи в В распределенной системе должно существовать определенное количество связей, иначе стороны вообще не смогут общаться. Хотя суть здесь в том, что связывание должно основываться на четко определенных и стандартизированных форматах, которые может поддерживать множество клиентов, вместо того, чтобы обмениваться заданными c форматами представления, только очень ограниченное число клиентов поддерживает (в худшем случае только собственный клиент) , Вместо прямой связи с API и использования неопределенного синтаксиса на основе JSON (возможно, с внешней документацией семантики соответствующих полей) теперь должно происходить соединение с типами носителей, которые могут использовать стороны для обмена форматом. Здесь задается не вопрос, какой тип носителя поддерживать, а сколько вы хотите поддержать. Чем больше медиа-типов поддерживает ваш клиент или сервер, тем выше вероятность взаимодействия с другими одноранговыми узлами в распределенной системе. В общем, вы хотите, чтобы сервер мог обслуживать множество клиентов, в то время как один клиент должен иметь возможность взаимодействовать (в лучшем случае) с каждым сервером без необходимости постоянного внедрения.

Итак, если вы действительно хотите отделить клиентов от серверов, вам следует поближе познакомиться с тем, как на самом деле работает Интернет, и попытаться имитировать c свою модель взаимодействия на уровне вашего приложения. Как "Дядя Боб" Роберт C. Мартин упомянул

Архитектура о намерениях! ( Source )

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


Все хорошо в теории, но до сих пор все остальные API, с которыми я сталкивался в своей карьере, были предопределенные контракты, которые изменились с течением времени.

Проблема здесь заключается в том, что почти все из так называемых "REST API" являются службами RP C, которые не следует называть "REST" для начала, хотя это проблема сообщества. Обычно такие API поставляются с внешней документацией (например, Swagger ), которая просто повторяет те же проблемы, от которых страдают классические решения RP C, такие как CORBA, RMI или SOAP. Документация может рассматриваться как IDL в этом процессе без строгой необходимости в каркасных классах, хотя большинство «каркасов» используют какие-то классы типизированных данных, которые либо игнорируют недавно введенное поле (в лучшем случае), либо полностью разрушаются при вызове.

Одна из проблем, с которой страдает REST, заключается в том, что большинство людей не читают тезис Филдинга и поэтому не видят общей картины, которую REST пытается установить sh, но утверждает, что знает, что такое REST, и поэтому смешивает поднимать вещи и вызывать их службы RESTful, что приводит к ситуации, когда REST! ​​= REST. Те, кто указывает на то, что такое архитектура REST и как одна могла бы ее достичь, называются мечтателями и потусторонними, когда те, кто провозглашает неправильный термин (RP C over HTTP = REST), продолжают делать это, добавляя к путанице особенно тех, кто только изучает весь вопрос.

Я признаю, что разработка настоящей архитектуры REST действительно очень трудна, поскольку слишком просто ввести некоторую форму связи. Следовательно, необходимо сделать очень тщательный проект, который требует времени, а также стоит денег. Деньги, которые многие компании не могут или не хотят тратить, особенно в области, где новые технологии постоянно развиваются, и те, кто отвечает за разработку таких решений, часто покидают компанию до завершения всего процесса.

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

Ну, как часто вам приходилось менять браузер, поскольку он не мог взаимодействовать с сетью страница? Я не говорю о CSS -материалах или браузер-специфических c CSS или JS материалах. Как часто нужно, чтобы Интернет менялся в последние 2-3 десятилетия? Подобно Интернету, архитектура REST предназначена для долгосрочных приложений на долгие годы, что поддерживает естественную эволюцию по замыслу. Для простых систем frontend-2-backend это наверняка излишне. Он начинает сиять, особенно в тех случаях, когда вы можете взаимодействовать с несколькими равноправными партнерами.

...