REST API - DTO или нет? [закрыто]

154

В настоящее время я создаю REST-API для проекта и читаю статью за статьей о лучших практиках. Многие, кажется, против DTO и просто выставляют модель предметной области, в то время как другие, кажется, думают, что DTO (или пользовательские модели или как вы хотите это называть) - плохая практика. Лично я думал, что эта статья имеет большой смысл.

Однако я также понимаю недостатки DTO со всем дополнительным кодом отображения, модели доменов, которые могут быть на 100% идентичны их DTO-аналогам, и так далее.

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

Дело в том, что мы можем не захотеть предоставлять все данные домена другим пользователям клиента. Большая часть данных будет иметь смысл только в нашем собственном веб-приложении. Кроме того, мы можем не захотеть раскрывать все данные об объекте во всех сценариях, особенно об отношениях с другими объектами и так далее. Например, если мы представляем список определенного объекта, мы не обязательно хотим раскрывать всю иерархию объектов; так что дочерние объекты не будут выставлены, но могут быть обнаружены через ссылки (hateoas).

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

benbjo
источник
9
Не удивляйтесь, если этот вопрос закроется. Это больше вопрос, основанный на обсуждении, что означает, что нет четкого правильного ответа. Спросите разных людей, и вы получите другой ответ.
Бен Терли
2
Ссылка на эту статью ( ibm.com/developerworks/community/blogs/barcia/entry/… ) не работает.
Pinkpanther
7
@pinkpanther Отличная статья, и жаль, что она больше не доступна. Вот кэшированная версия веб-архива .
Кассиомолин

Ответы:

252

Почему вы должны использовать DTO в вашем REST API

DTO расшифровывается как D ata T transfer O bject .

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

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

Пока ваш сервисный уровень работает над моделями домена / персистентности, ваши контроллеры API должны работать с другим набором моделей. Например, по мере развития моделей вашего домена / персистентности для поддержки новых бизнес-требований вы можете захотеть создать новые версии моделей API для поддержки этих изменений. Вы также можете отказаться от старых версий API по мере выпуска новых версий. И это вполне возможно достичь, когда вещи отделены.


Просто упомяну несколько преимуществ предоставления DTO вместо моделей постоянства:

  • Отсоедините модели персистентности от моделей API.

  • DTO могут быть адаптированы к вашим потребностям, и они хороши, когда вы выставляете только набор атрибутов ваших постоянных сущностей. Вам не понадобятся аннотации, такие как @XmlTransientи, @JsonIgnoreчтобы избежать сериализации некоторых атрибутов.

  • Используя DTO, вы избежите адских аннотаций в ваших персистентных сущностях, то есть ваши персистентные сущности не будут раздуты аннотациями, не связанными с персистентностью.

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

  • Если вы используете Swagger , вы можете использовать @ApiModelи @ApiModelPropertyаннотации для документирования ваших моделей API, не портя ваши персистентные сущности.

  • Вы можете иметь разные DTO для каждой версии вашего API.

  • У вас будет больше гибкости при отображении отношений.

  • Вы можете иметь разные DTO для разных типов медиа.

  • Ваши DTO могут иметь список ссылок для HATEOAS . Такого рода вещи не следует добавлять к объектам персистентности. При использовании Spring HATEOAS вы можете расширить классы DTO RepresentationModel(ранее известные как ResourceSupport) или обернуть их EntityModel(ранее известные как Resource<T>).

Работа с шаблоном кода

Вам не нужно будет привязывать ваши персистентные сущности к DTO и наоборот вручную . Есть много картографических фреймворков, которые вы можете использовать для этого. Например, посмотрите на MapStruct , который основан на аннотациях и работает как обработчик аннотаций Maven. Он хорошо работает как в CDI, так и в Spring-приложениях.

Вы можете также рассмотреть вопрос о Ломбках для создания геттеров, сеттеров, equals(), hashcode()и toString()метод для вас.


Связанный: чтобы дать лучшие имена вашим классам DTO, обратитесь к этому ответу .

cassiomolin
источник
2
Если бы я пошел по пути DTO, вы бы сопоставили все доменные объекты с DTO или только те, которые не были бы идентичными? Кроме того, как бы вы решили проблему раскрытия данных на основе различных сценариев / контекстов? Несколько DTO на объект домена?
Бенджо
6
@benbjo Тебе решать. Я обычно сопоставляю только самые сложные сущности с DTO, сущности, для которых я не хочу раскрывать все атрибуты, и сущности с множеством взаимосвязей. DTO дают мне возможность иметь список ссылок для использования в HATEOAS. Такого рода вещи я бы не добавил к своим объектам постоянства.
Кассиомолин
2
@Molin большое спасибо за информацию и предложения. Я обязательно проверю MapStruct. На первый взгляд, это выглядит очень хорошо для моих нужд.
benbjo
6
Уважаемый downvoter, не могли бы вы хотя бы объяснить причину вашего downvote?
Кассиомолин
8
Существует также архитектурная причина использования DTO вместо доменных сущностей в REST API. REST API не должен меняться, чтобы не сломать существующих клиентов. Если вы используете модель домена непосредственно в API, вы создаете нежелательную связь между API и моделью домена. В соответствии с принципом проектирования «Слабая связь по сервису», контракт на обслуживание не должен быть тесно связан с логикой обслуживания или деталями реализации.
Пауло Мерсон
25

Когда ваш API общедоступен, и вы должны поддерживать несколько версий, вы должны использовать DTO.

С другой стороны, если это частный API и вы управляете клиентом и сервером, я склонен пропускать DTO и выставлять модель домена напрямую.

Дэвид Сиро
источник
Я согласен с вами в последней части, и я обычно делаю это, но это мой первый публичный API. Я рассмотрю то, что вы говорите об использовании DTO для публичной части. Возможно, частные и публичные части API действительно должны быть разделены, даже если хороший принцип - «есть собачью еду».
benbjo
11

Я склонен использовать DTO.

Мне не нравятся недостатки, но кажется, что другие варианты еще хуже:

Экспозиция объектов домена может привести к проблемам безопасности и утечке данных. Может показаться, что аннотации Джексона решают проблему, но слишком легко ошибиться и раскрыть данные, которые не следует раскрывать. При разработке класса DTO совершить такую ​​ошибку гораздо сложнее.

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

ArgB32
источник
9

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

Это в основном верно для ответной стороны json / rest api. Я даже написал аддон Джексона, чтобы избежать написания многих представлений / фильтров json для этих случаев: https://github.com/Antibrumm/jackson-antpathfilter

С другой стороны, DTO - хорошая вещь на стороне ввода данных таких API. Работать напрямую с сущностями может быть довольно сложно, например, принимая во внимание двунаправленные отношения. Кроме того, вы действительно не хотите, чтобы вызывающая сторона изменяла атрибут «создатель», например. Таким образом, вам нужно будет запретить определенные поля при отображении таких запросов.

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