Как описать архитектурный сдвиг, который намеренно нарушает стандарты REST?

37

Я предлагаю внести изменения в очень плохо спроектированный программный проект, который страдает от множества проблем. На высоком уровне проект использует Angular на внешнем интерфейсе и использует различные API REST; что все замечательно (я не вижу необходимости менять нашу технологию или инструменты). Проблема заключается в том, что база кода непропорционально больше в пользовательском интерфейсе, чем на стороне сервера API. Большая часть бизнес-логики живет в пользовательском интерфейсе, а API-интерфейсы REST являются простыми интерфейсами базы данных CRUD с уровнем пользовательского интерфейса.

Например, POST для клиента создаст запись о клиенте, а PUT изменит этого клиента. Не намного больше и не намного меньше. Однако наша бизнес-логика более требовательна, чем эта. Общий процесс создания клиента делает гораздо больше, чем просто вставка 1 записи в базу данных. Он будет предоставлять данные в других необходимых таблицах, выполнять определенные проверки и вычисления и т. Д. Я бы предпочел сделать один вызов POST / PUT, который инкапсулирует все это поведение, облегчая нагрузку на потребляющего клиента.

Поэтому я считаю, что эта всеобъемлющая оркестровка должна жить на сервере (где у нас есть полный контроль, журналы и т. Д.), А не в пользовательском интерфейсе, но один контраргумент состоит в том, что этот подход больше не будет RESTful. Поэтому я не уверен, как лучше описать этот подход, когда я рекомендую продолжить работу с существующим технологическим стеком, но осуществить фундаментальные сдвиги в местах, где принадлежит код.

Бен Харрисон
источник
44
Ограничение вашего API для вызовов CRUD ради того, чтобы сделать его "RESTful", является плохим компромиссом.
Роберт Харви
38
@EsbenSkovPedersen: лучший друг навсегда?
Роберт Харви
5
Вместо того чтобы беспокоиться о том, соответствует ли ваш сервис REST (iirc, почти никто не делает), я бы больше беспокоился о соответствии спецификации HTTP . Большинство API, с которыми я работал, также не соответствуют спецификации, но это более достижимая и стоящая цель.
аааааа
7
@aaaaaa, причина, по которой сервисы почти не соответствуют REST, заключается в том, что никто не может решить, что такое REST. Единственная точка согласия, которую я нашел, это «все остальные делают это неправильно».
Марк
16
- «Как описать архитектурный сдвиг, который намеренно нарушает стандарты REST?» - неуважение . ( Извините за непрофессиональный комментарий, он был сильнее меня. )
luk32

Ответы:

49

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

Service oriented architecture,

Вы предлагаете изменить структуру вашей системы, чтобы ваши бизнес-правила и ваши данные были в одном месте. Это фактически определение сервиса ; см. выступление Уди Даана о поиске границ обслуживания .

Боковая панель: как отметил Эрик, это не имеет ничего общего с «ОТДЫХОМ». Нет абсолютно никаких причин, по которым вы не можете поставить REST API (то есть API, который удовлетворяет ограничениям архитектурного стиля REST ) перед вашим сервисом. Но это может быть неочевидным для людей, которые понимают, что REST означает отображение операций базы данных на методы HTTP.

Это может или не может стоить инвестировать в изменение понимания REST вашей аудиторией.

VoiceOfUnreason
источник
32
Также не стоит инвестировать в REST вообще. Если вы читаете диссертацию Роя Филдинга (или « Как я объяснил REST моей жене )», истинная цель REST - предоставить каноническое представление ресурсов в Интернете, чтобы разрозненные машины через Интернет имели стандартный способ управления этими ресурсами. , Частное приложение может даже не нуждаться в этой возможности.
Роберт Харви
29

Отдых не CRUD. Этот «контраргумент» основан на глубоко ошибочном понимании того, что такое REST. Я не видел в вашем посте ничего, что указывало бы на то, что ваше изменение сделает ваш API более или менее RESTful.

Эрик Стейн
источник
6
Ну, нет, это не идеальное отображение CRUD, но оно действительно ходит, разговаривает и поет очень похоже на CRUD, по крайней мере, так, как его интерпретирует большинство людей.
Роберт Харви
11
@RobertHarvey Я думаю, что это (неправильное) понимание, что проблема здесь.
JimmyJames
4
@JimmyJames: это распространенное недоразумение. Существует сильное стремление сделать вещи «спокойными», когда большинство людей даже не понимают, что это за преимущества или как эти преимущества будут применяться к ним.
Роберт Харви
4
@RobertHarvey Я думаю, что вы говорите, что если делать это неправильно, то REST не должен быть целью. Хорошо, но, как я понимаю, называть это «НЕ ОТДЫХОМ» - это чушь собачья, и я большой сторонник того, чтобы называть ерунду чушь собачью. Слова нуждаются в общепринятом значении, чтобы быть полезным.
JimmyJames
5
@RobertHarvey Конечно, но этого не произойдет, пока есть достаточно людей, которые готовы исправить эти неправильные выражения. Я не готов бросить полотенце.
JimmyJames
24

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

Это означает, что, например, в то время как ваше угловое приложение может проверять, имеет ли клиент допустимый возрастной диапазон и гарантирует, что законные пользователи получают правильную обратную связь, любой, кто знает URL вашего API, может сделать запрос POST, содержащий некоторые недопустимые значения, которые больше не будет подтверждено.

Поэтому я предлагаю перенести ваши бизнес-правила в API, позволить ему проверять ввод и возвращать соответствующие ошибки (или, возможно, просто коды, указывающие, что пошло не так) в теле ответа. Эти коды могут затем использоваться вашим клиентским приложением, чтобы указать, что пошло не так.

mrsmn
источник
5
Это, безусловно, самый полезный ответ: API - это поверхность атаки, а не входные данные для клиента. Любой запрос API может быть подделан. Таким образом, все, что можно сделать с помощью чистого API, - это то, что может сделать бездарный зловредный сценарист. Клиентское программное обеспечение может использоваться для обеспечения лучшего взаимодействия с пользователем, но именно сервер должен обеспечивать соблюдение правил.
начальник
10

Чтобы добавить к другим хорошим ответам здесь:

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

Одним из основных преимуществ использования услуг является то, что детали реализации могут быть изменены без необходимости что-либо делать клиентам. Из того, что вы описали, похоже, что нет реального уровня абстракции. Детали реализации были представлены через HTTP. Ничто в REST не говорит о том, что это необходимо, полезно или желательно. На самом деле, я думаю, что я могу утверждать, что некоторые части определения REST означают, что это на самом деле реализация без RESTful.

То, что вы предлагаете, это то, как должен быть разработан надлежащий уровень обслуживания. Если кто-то говорит вам, что вы не можете сделать это, потому что это не RESTful, это прискорбно. Вы можете быть уверены, что кто-то, кто говорит вам, что почти ничего не знает о REST.

Исходя из вашего вопроса, у вас есть ресурс под названием клиент. Все, что требуется для создания действительного ресурса клиента, может и должно обрабатываться в POSTбазовом ресурсе клиента (или, альтернативно / необязательно, в PUT для конкретного ресурса клиента, если он не существует). REST ничего не говорит о том, сколько записи базы данных, которые нужно создать по заданному вызову. Как прокомментировал Колин Янг, база данных вообще не нужна, совершенно неважно, как сервисы реализуются с точки зрения REST.

JimmyJames
источник
3
REST ничего не говорит о записях в базе данных, не говоря уже о том, сколько. Я мог бы создать службу REST, которая контролировала бы водный клапан и выставляла бы водный клапан, водоснабжение и ресурсы уровня бака. Вы могли бы утверждать, что сами физические объекты - это «базы данных», которые немного растягивают вещи.
Колин Янг
@ColinYoung Да, спасибо за помощь в разъяснении.
JimmyJames
3

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

REST не гарантирует, что ваш API позволяет только хранить и извлекать данные. Скорее, это связано с моделированием действий как ресурсов. Ваш API должен позволять выполнять действия (в конце концов, это интерфейс прикладного программирования ). Вопрос в том, как смоделировать эти действия.

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

Давайте посмотрим на ваш объект Customer.

Проблема:

Пользовательский интерфейс отправляет клиенту, но последующие таблицы еще не были обновлены. Что если один из последующих вызовов завершится неудачно из-за ошибки в вашем коде пользовательского интерфейса (или неправильного поведения плагина браузера и т. Д.)? Теперь ваши данные находятся в противоречивом состоянии. Это может быть даже состояние, которое нарушает другие части вашего API или пользовательского интерфейса, не говоря уже о том, что оно просто недопустимо. Как вы поправляетесь? Вы должны проверить каждое возможное состояние, чтобы убедиться, что это не сломает что-то, но было бы сложно узнать, что это возможно.

Решение:

Создайте конечную точку API для создания клиентов. Вы знаете, что не хотите иметь конечную точку "/ customer / create" или даже "/ create-customer", потому что create является глаголом и нарушает REST. Так что назови это. "/ customer-creation" может работать. Теперь, когда вы размещаете свой объект CustomerCreation, он отправляет все необходимые поля для полного создания клиента. Конечная точка будет гарантировать, что данные полны и действительны (возвращая 400 или что-то, если они не проходят проверку), и могут сохраняться все, например, в одной транзакции БД.

Если вам также нужна конечная точка для объектов GET / customer, это нормально. Вы можете иметь оба. Хитрость заключается в создании конечных точек, которые обслуживают потребности потребителей.

Преимущества:

  1. Вы гарантируете, что у вас не будет плохого состояния
  2. На самом деле разработчикам пользовательского интерфейса проще, если им не нужно «знать» порядок запросов, вопросы проверки и т. Д.
  3. Это не так болтливо API, что снижает задержку сетевых запросов
  4. Проще тестировать и концептуализировать сценарии (отсутствующие / искаженные фрагменты данных из пользовательского интерфейса не распределяются по запросам, некоторые из которых могут не работать)
  5. Это позволяет лучше инкапсулировать бизнес-логику
  6. Как правило, упрощает безопасность (поскольку бизнес-логика и логика в пользовательском интерфейсе могут быть изменены пользователями)
  7. Скорее всего, уменьшит дублирование логики (более вероятно, что у вас будет более 2 потребителей API, чем 2+ API, которые предоставляют доступ к одним и тем же данным)
  8. Все еще 100% ОТДЫХ

Недостатки:

  1. Это потенциально больше работы для внутреннего разработчика (но может не быть в долгосрочной перспективе)

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

Мой собственный опыт показывает, что как только разработчики в моей команде начали реализовывать эту стратегию, они почти сразу увидели преимущества.

Дальнейшее изучение:

Эта статья от ThinkWorks действительно помогла мне получить представление о моделировании действий как объектов на практических примерах: https://www.thoughtworks.com/insights/blog/rest-api-design-resource-modeling.

Я бы также предложил почитать CQRS и Event Sourcing, так как они касаются именно такого рода вещей (то есть отделяют ваш API от фактической логики персистентности). Я не знаю, насколько готовы были бы ваши коллеги читать подобные вещи, но это может дать вам больше ясности и помочь вам объяснить это им.

Planky
источник
« потому что творить - это глагол и нарушать REST » - абсолютно правильно. Другими словами, тогда будет 47.258.346-й подход к запуску « RPC через REST ». Это то, что я бы назвал «неестественным», по крайней мере, потому что он неправильно использует и искажает подходы RESTful (у них есть свои варианты использования, но RPC не является одним из них), а также имеет тенденцию быть неэффективным.
JensG