API RESTful: где я должен кодировать свой рабочий процесс?

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

В настоящее время у меня есть настройка api в следующих слоях:

  • Уровень HTTP
  • Уровень ресурсов
  • Модель домена/бизнес-логика
  • Уровень доступа к данным/репозитория
  • Постоянное хранилище/уровень БД

Проблема, с которой я столкнулся в данный момент, - где мне нужно разместить объекты/менеджеры рабочего процесса? По рабочим процессам я имею в виду код, который оценивает, что следующий шаг требуется конечному пользователю. Например, рабочий процесс электронной торговли. Пользователь добавляет товар в корзину, затем проверяет, затем заполняет личные данные, а затем платит. Рабочий процесс будет отвечать за принятие решения о следующих шагах, а также о том, какие шаги НЕ допускаются. Например, пользователь не мог вызвать ошибки в API, пытаясь оплатить, прежде чем они ввели личные данные (возможно, они напомнят URI для платежей и попытаются пропустить шаг). Рабочий процесс будет проверять, чтобы все предыдущие шаги были завершены, если нет, не разрешат оплату.

В настоящее время моя логика рабочего процесса находится в Уровне ресурсов. Я использую гипермедиа-ссылки для представления рабочего процесса пользователю, например. обеспечивая ссылку "следующего шага". Проблема, с которой я сталкиваюсь, заключается в том, что уровень ресурсов является слоем верхнего уровня и более согласован с презентацией. Я считаю, что ему нужно слишком много знать о базовой модели домена, чтобы эффективно оценивать рабочий процесс, то есть ему нужно было знать, что он должен проверить объект personal_detail до разрешения оплаты.

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

Но теперь проблема заключается в том, что для завершения их логических процессов требуется знание нескольких объектов домена. Теперь он чувствует себя хорошо, что, возможно, идет в своем собственном слое? Между ресурсом и уровнем домена?

  • Уровень HTTP
  • Уровень ресурсов
  • Уровень рабочего процесса
  • Модель домена/бизнес-логика
  • Уровень доступа к данным/репозитория
  • Постоянное хранилище/уровень БД

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

Ссылки на статьи или блоги, которые охватывают это, будут очень признательны. Любите читать разные версии.

ИЗМЕНИТЬ

Чтобы уточнить, я выпускаю, что HATEOAS позволяет клиенту перемещаться по "рабочему процессу", но в моем API должно быть что-то, что знает, какие ссылки показывать, то есть он действительно определяет рабочий процесс, который разрешен. Он представляет связанные с рабочим процессом ссылки в ресурсе, но дополнительно проверяет, что запросы синхронизируются с рабочим процессом. Хотя я согласен с тем, что клиент, возможно, будет следовать только ссылкам, предоставленным в ресурсе, опасностью (и красотой) отдыха, является то, что его URI управляется, поэтому нет ничего, что останавливало бы вредного клиента, пытающегося "пропустить" шаги в рабочем процессе делая образованную догадку в URI. API должен определить это и вернуть ответ 302.

Ответ 1

Ответ на этот вопрос дал мне довольно много исследований, но в основном часть "workflow" не имеет ничего общего с REST и больше относится к прикладному уровню.

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

Ответ 2

REST поощряет вас создавать словарь существительных (пользователей, продуктов, тележек покупок) против установленного набора глаголов (GET, POST, PUT, DELETE). Если вы придерживаетесь этого правила, то в вашем примере рабочий процесс действительно определяется набором взаимодействий, которые пользователь имеет с вашим сайтом. Это то, как пользователь использует ваше приложение, которое действительно определено пользовательским интерфейсом. Ваши службы REST должны соответствующим образом реагировать на недопустимые запросы штата, такие как попытка проверки с пустой тележкой, но пользовательский интерфейс может также предотвращать такие запросы, используя script, который является необязательной характеристикой REST.

Например, пользовательский интерфейс, который отображает продукт для пользователя, также может отображать ссылку, которая позволит пользователю добавить этот продукт в свою корзину (POST shoppingcart/{productId}). Сервер действительно не должен заботиться о том, как пользователь дошел до этого POST, только чтобы он добавил этот продукт в корзину пользователя и возвратил обновленное представление корзины пользователю. Затем пользовательский интерфейс может использовать javascript для определения того, показывать ли ссылку на проверку, только если в корзине есть один или несколько элементов.

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

Ответ 3

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

В приложениях REST не должно быть состояния сеанса, сохраненного на стороне сервера. Вместо этого он должен полностью обрабатываться клиентом.

Итак, если на сервере есть состояние сеанса, это не REST.

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

Вы говорили о вредных пользователях, угадывающих URL-адреса. Это всегда вызывает беспокойство, и ваша безопасность должна решаться. Если URL-адрес для удаления пользователя DELETE /user/3782... они могут легко угадать, как удалить всех пользователей. Но вы не должны полагаться только на обфускацию URL-адресов. У вас должны быть реальные проверки безопасности и доступа внутри ваших конечных точек, проверяющих, действительно ли каждый запрос.

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

Ответ 4

Возможно, вы захотите переориентировать свою архитектуру в соответствии с DDD (Domain Driven Design) и, возможно, использовать MSA, таким образом вы можете перейти от организованного рабочего процесса к EDA и хореографии микропроцессов.