REST API - DTOs or not? [closed]

2019-01-01 15:03发布

问题:

I am currently creating a REST-API for a project and have been reading article upon article about best practices. Many seem to be against DTOs and simply just expose the domain model, while others seem to think DTOs (or User Models or whatever you want to call it) are bad practice. Personally, I thought that this article made a lot of sense.

However, I also understand the drawbacks of DTOs with all the extra mapping code, domain models that might be 100% identical to their DTO-counterpart and so on.

Our API is mostly created so that other clients may consume data, however if we do it right we would also like to use it for our own web GUI if possible.

The thing is that we might not want to expose all the domain data to the other client users. Much of the data will only make sense in our own web application. Also, we might not want to expose all data about an object in all scenarios, especially relationships to other objects and so on. For example, if we expose a list of a particular object we would not necessarily want to expose the entire object hierarchy; so that the object\'s children will not be exposed, but can be discovered through links (hateoas).

How should I go about solving this problem? I was thinking about using Jackson mixins on our domain models to control what data would be exposed given different scenarios. Or should we just use DTOs all the way - even given its drawbacks and controversy?

回答1:

Why you should use DTOs in your REST API

DTO stands for Data Transfer Object.

This pattern was created with a very well defined purpose: transfer data to remote interfaces, just like web services. This pattern fits very well in a REST API and DTOs will give you more flexibility in the long run.

REST resources representations don\'t need to have the same attributes as the persistence models: you may need to omit, add or rename attributes.

Just to mention a few benefits of exposing DTOs instead of persistence models:

  • DTOs can be tailored to your needs and they are great when exposing only a set of attributes of your persistence entities. You won\'t need annotations such as @XmlTransient and @JsonIgnore to avoid the serialization of some attributes.
  • By using DTOs, you will avoid a hell of annotations in your persistence entities, that is, your persistence entities won\'t be bloated with non persistence related annotations;
  • You will have full control over the attributes you are receiving when creating or updating a resource;
  • If you are using Swagger, you can use @ApiModel and @ApiModelProperty annotations to document your API models without messing your persistence entities;
  • You can have different DTOs for each version of your API;
  • You\'ll have more flexibility when mapping relationships;
  • You can have different DTOs for different media types;
  • Your DTOs can have a list of links for HATEOAS. That\'s the kind of thing that shouldn\'t be added to persistence objects.

Mapping frameworks

You won\'t need to map your persistence entities to DTOs and vice versa mannually. There are many mapping frameworks you can use to do it. For instance, have a look at MapStruct, which is annotation based and works as a Maven Annotation Processor. It also works in CDI and Spring-based applications.


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



回答2:

When your API is public and you have to support multiple versions, you have to go with DTOs.

On the other hand, if it\'s private API and you control both client and server, I tend to skip the DTOs and expose directly domain model.



回答3:

I tend to use DTOs.

I don\'t like the drawbacks but it seems that the other options are even worse:

Exposition of domain objects may lead to security issues and data leak. Jackson annotations may seem to solve the problem but it\'s too easy to make a mistake and expose data which should not to be exposed. When designing a DTO class it\'s much harder to make such a mistake.

On the other side the drawbacks of DTO approach can be reduced with things like object to object mapping and Lombok for less boilerplate.



回答4:

As you already stated yourself, this is clearly an opinion related question. I myself am more drawn to the No-DTOs approach, simply because of all the boilerplate code you need.

This is mainly true for the response side of a json/rest api. I even wrote a jackson addon to avoid writing many json views / filters for these cases: https://github.com/Antibrumm/jackson-antpathfilter

On the other hand DTOs are a good thing on the request input side of such APIs. Working directly on entities can be pretty hard taking into account bidirectional relations for example. Also you dont really want to let a caller modify a \"creator\" attribute for example. So you would need to dissallow certain fields during the mapping of such requests.