Подтвердить что ты не робот

Как поддерживать команду в REST при одновременном выполнении REST, CQRS и EventSourcing?

Рассмотрим следующий грубозернистый REST apis для ресурса контакта

POST          /api/contacts                             
GET           /api/contacts                             
GET           /api/contacts/:id                         
PUT           /api/contacts/:id                         
DELETE        /api/contacts/:id                         

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

CreateContactCommand -> | Contact("john", "doe", 25) | -> ContactCreatedEvent
FirstNameChangeCommand -> | Contact("jane", "doe", 25) | -> FirstNameChangedEvent
LastNameChangeCommand -> | Contact("jane", "dear", 25) | -> LastNameChangedEvent
AgeChangeCommand -> | Contact("jane", "doe", 30) | -> AgeChangedEvent

Теперь, комбинируя REST и EventSourcing как.

Выполнение REST, как клиент взаимодействует с вышеуказанными стандартными API-интерфейсами REST для изменений на уровне поля для генерации команд на конечной точке REST на стороне сервера?

Основной вопрос: как создать REST API так, чтобы он также мог поддерживать команды, в конечном счете поддерживающие eventourcing?

Если кто-нибудь может пролить свет на это, помощь будет принята с благодарностью.

4b9b3361

Ответ 1

CQRS и событие Sourcing не является ни принципом разработки API, ни его архитектура верхнего уровня. Тем не менее, если вы хотите "разоблачить" ваш API как API на основе задач, вы можете открыть ссылки как часть ресурса контакта.

GET /contacts/1234

Ответ

200 OK
<contact>
  <atom:link href="/contacts/1234/first-name" rel="first-name" />
  <atom:link href="/contacts/1234/last-name" rel="last-name" />
  <atom:link href="/contacts/1234/age" rel="age" />
  <first-name>Jane</first-name>
  <last-name>Doe</last-name>
  <age>25</age>
</contact>

Предполагается, что вы меняете API на true уровень 3 API REST.

Кроме того, /contacts/1234 будет принимать запросы GET и DELETE (not PUT). Если клиент хочет изменить, например. первое имя контакта, оно должно следовать за ссылкой с типом отношения first-name и сделать запрос PUT к этому ресурсу:

PUT /contacts/1234/first-name
<first-name>John</first-name>

Все, кроме поля first-name PUT здесь, должно быть проигнорировано или отклонено.

Таким образом, когда услуга получает PUT от ресурса с именем, это команда для изменения первого имени контакта.

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

Ответ 2

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

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

Следовательно, строгое взаимно однозначное соответствие между командами, которые имеют смысл в вашем домене и пара (ресурс, глагол), не всегда желательно или адекватно. Вы можете пойти дальше и разработать свой собственный протокол приложений домена для клиентов REST, чтобы разговаривать с сервером в соответствии с более тонкими правилами. DAP отражается в ссылках гиперссылки и отношениях для переходов, как отметил Марк, но вы также можете использовать настраиваемые типы контента для лучшего описания типа полезной нагрузки в запросах или ответах. Например, они могут содержать тип команды домена, которую вы отправляете.

Если вы посмотрите эту статью, вы увидите, что пара (POST, api/inventoryItem/{id}) не уникальна в диаграмму в разделе "Ресурсы". Он может использоваться для переноса либо RemoveItemsFromInventoryCommand, либо CheckInItemsToInventoryCommand. Как вы указываете, что на уровне HTTP-запроса используется заголовок настраиваемого типа контента: Content-Type:application/json;domain-model=RemoveItemsFromInventoryCommand или Content-Type:application/json;domain-model=CheckInItemsToInventoryCommand.