REST API - DTO или нет?

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

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

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

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

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

Ответ 1

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

DTO означает D ata T перевод 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-приложениях.

Вы также можете рассмотреть возможность использования Lombok методов получения, установки, TG48, TG49 и TG410.


Related: To give better names to your DTO classes, refer to this answer.

Ответ 2

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

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

Ответ 3

Я использую DTO.

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

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

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

Ответ 4

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

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

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