Насколько я понимаю, в CQRS-ориентированном API, открытом через HTTP-API RESTful, команды и запросы выражаются через HTTP-глаголы, причем команды являются асинхронными и обычно возвращают 202 Accepted
, в то время как запросы получают информацию, которую вы необходимость. Кто-то спросил меня следующее: если они хотят изменить какую-то информацию, им нужно будет отправить команду, а затем запрос, чтобы получить полученное состояние, почему заставить клиента сделать два HTTP-запроса, когда вы можете просто вернуть то, что они хотят в HTTP-ответ команды в одном HTTP-запросе?
Что должно быть возвращено из API для команд CQRS?
Ответ 1
Мы провели долгую беседу в списке рассылки DDD/CRQS пару месяцев назад (ссылка). Одна часть обсуждения была "односторонняя команда", и это то, что я думаю, что вы предполагаете. Вы можете узнать, что Грег Янг против этой картины. Команда изменяет состояние и поэтому подвержена сбою, что означает, что он может выйти из строя, и вы должны это поддержать. REST API с запросами POST/PUT обеспечивает идеальную поддержку для этого, но вы не должны просто возвращать 202 Accepted, но действительно даете какой-то значимый результат. Некоторые люди возвращают 200 успешных результатов, а также некоторый объект, содержащий URL-адрес для извлечения вновь созданного или обновленного объекта. Если обработчик команды терпит неудачу, он должен вернуть 500 и сообщение об ошибке.
Наличие команд "огонь-и-забыть" опасно, поскольку оно может дать потребителю неправильные представления о состоянии системы.
Ответ 2
Недавно у моей команды также была очень горячая дискуссия об этом. Спасибо, что разместили вопрос. Я обычно был защитником команд стиля "огонь и забыть". Моя позиция всегда заключалась в том, что если вы хотите, чтобы однажды вы могли перейти к диспетчеру асинхронной команды, вы не можете позволить командам возвращать что-либо. Это может убить ваши шансы, так как команда async не имеет большого значения, чтобы вернуть значение в исходный HTTP-вызов. Некоторые из моих товарищей по команде действительно оспаривали это мышление, поэтому мне пришлось подумать, действительно ли моя позиция заслуживает защиты.
Тогда я понял, что асинхронный или не async - это просто деталь реализации. Это заставило меня понять, что, используя наши рамки, мы можем построить промежуточное программное обеспечение, чтобы выполнить то же самое, что и наши диспетчеры асинхронных задач. Таким образом, мы можем строить наши обработчики команд так, как мы хотим, возвращая то, что когда-либо имеет смысл, а затем пусть структура вокруг обработчиков имеет дело с "когда".
Пример. Моя команда создает http API в node.js в настоящее время. Вместо того, чтобы требовать, чтобы команда POST возвращала только пустой 202, мы возвращаем детали вновь созданного ресурса. Это помогает перемещаться по интерфейсу. Передняя панель отправляет виджет и открывает канал для веб-сокета сервера, используя ту же команду, что и имя канала. запрос приходит на сервер и перехватывается промежуточным программным обеспечением, которое передает его на служебную шину. Когда команда в конечном итоге обрабатывается обработчиком синхронно, она "возвращается" через веб-сокет, а интерфейс - счастлив. Средство промежуточного уровня может быть легко отключено, что делает API синхронным снова.
Ответ 3
Нет ничего, что помешало бы вам сделать это. Если вы выполняете свои команды синхронно и создаете свои прогнозы синхронно, тогда вам будет легко просто сделать запрос непосредственно после выполнения команды и вернуть этот результат. Если вы выполняете это асинхронно через rest-api, то у вас нет результата запроса для отправки назад. Если вы сделаете это асинхронно в своей системе, вы можете дождаться, когда проекция будет создана, а затем отправить ответ клиенту.
Важно то, что вы отделяете свои модели записи и чтения от классического стиля CQRS. Это не означает, что вы не можете читать по тому же запросу, что и команда. Конечно, вы можете отправить команду на сервер, а затем с помощью SignalR (или что-то еще) дождитесь уведомления о том, что ваша проекция была создана/обновлена. Я не вижу проблемы с ожиданием создания проекции на стороне сервера, а не для клиента.
Как вы это сделаете, это повлияет на вашу инфраструктуру и обработку ошибок. Кроме того, вы будете удерживать HTTP-запрос открытым дольше, если вы сразу же вернете результат.