Опрос использования DTO с отдыхом и извлечением поведения из обновления - PullRequest
12 голосов
/ 15 августа 2011

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

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

  • ChangeDueDate(DateTime date)
  • ChangeDescription(string description)
  • AddTags(params string[] tags)
  • Complete()

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

Возвращаясь к REST Service, как я вижу, есть 3 варианта:

  1. Создание URL-адресов в стиле RPC, например http://127.0.0.1/api/tasks/{taskid}/changeduedate
  2. Разрешить отправку множества команд одной конечной точке, например:
    • URL: http://127.0.0.1/api/tasks/{taskid}/commands
    • Это примет список команд, чтобы я мог отправить следующее в том же запросе:
      • ChangeDueDate команда
      • ChangeDescription команда
  3. Сделайте действительно глагол RESTful доступным, и я создаю доменную логику, чтобы извлечь изменения из DTO и, в свою очередь, перевести в соответствующие требуемые события, например:
    • URL: http://127.0.0.1/api/tasks/{taskid}
    • Я бы использовал глагол PUT для отправки DTO-представления задачи
    • После получения я могу передать DTO фактическому объекту домена задачи с помощью вызываемого метода UpdateStateFromDto
    • Затем он проанализирует dto и сравнит соответствующие свойства с его полями, чтобы найти различия, и может иметь соответствующее событие, которое должно быть запущено, когда он обнаружит разницу с определенным свойством.

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

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

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

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

Ответы [ 2 ]

5 голосов
/ 15 августа 2011

Я бы сказал вариант 1. Если вы хотите, чтобы ваш сервис был RESTful, тогда вариант 2 не вариант, вы будете туннелировать запросы.

POST /api/tasks/{taskid}/changeduedate легко реализовать, но вы также можете сделать PUT /api/tasks/{taskid}/duedate.

Вы можете создать ресурсы контроллера, если хотите сгруппировать несколько процедур в одну, например, POST /api/tasks/{taskid}/doThisAndThat, я бы сделал это на основе шаблонов использования клиента.

Вам действительно нужно предоставить возможность вызывать любое количество «поведений» в одном запросе? (имеет ли значение заказ?)

Если вы хотите использовать опцию 3, я бы использовал PATCH /api/tasks/{taskid}, чтобы клиенту не нужно было включать в запрос все элементы, а только те, которые нужно изменить.

0 голосов
/ 26 сентября 2014

Давайте определим термин: operation = command or query с точки зрения домена, например, ChangeTaskDueDate(int taskId, DateTime date) - это операция.

С помощью REST вы можете отобразить операции на пары ресурсов и методов.Таким образом, вызов операции означает применение метода к ресурсу.Ресурсы идентифицируются URI и описываются существительными, такими как задача или дата и т. Д. ... Методы определены в стандарте HTTP и являются глаголами, такими как get, post, put и т. Д. Структура URI на самом деле нечто-то значит для клиента REST, так как клиент связан с машиночитаемыми материалами, но для разработчиков это упрощает реализацию маршрутизатора, генерацию канала, и вы можете использовать его, чтобы проверить, привязаны ли URI к ресурсам, а не к таким операциям, какRPC делает.
Таким образом, в нашем текущем примере ChangeTaskDueDate(int taskId, DateTime date) глагол будет change, а существительные task, due-date.Таким образом, вы можете использовать следующие решения:

  • PUT /api{/tasks,id}/due-date "2014-12-20 00:00:00" или вы можете использовать
  • PATCH /api{/tasks,id} {"dueDate": "2014-12-20 00:00:00"}.

разница в том, что патч предназначен для частичных обновлений и не является необходимым идемпотентом.

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

Возвращаясь к службе REST, как я вижу, есть 3 варианта:

  1. СделатьURL-адреса в стиле RPC, например, http://example.com/api/tasks/{taskid}/changeduedate
  2. Разрешить отправку множества команд в одну конечную точку, например:
    • URL: http://example.com/api/tasks/{taskid}/commands
    • Принимает список командчтобы я мог отправить следующее в том же запросе:
      • команда ChangeDueDate
      • команда ChangeDescription
  3. Сделать действительно успокоительный глаголдоступно, и я создаю доменную логику, чтобы извлечь изменения из dto и, в свою очередь, перевести в соответствующие требуемые события, например:
    • URL: http://example.com/api/tasks/{taskid}
    • Я бы использовал глагол PUT для отправки DTOпредставление задачи
    • После получения я могу передать DTO фактическому объекту домена задачи с помощью вызываемого метода UpdateStateFromDto
    • . Затем он проанализирует dto и сравнит соответствующие свойства с его полями.найти днайдены ifferences и могут иметь соответствующее событие, которое должно быть вызвано, когда обнаруживается разница с определенным свойством.
  1. URIструктура ничего не значит.Мы можем говорить о семантике, но REST сильно отличается от RPC. У него есть некоторые очень специфические ограничения, которые вы должны прочитать, прежде чем что-либо делать.

  2. Это та же проблема, что и в вашем первом ответе.Вы должны сопоставить операции с методами HTTP и URI.Они не могут перемещаться в теле сообщения.

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

...