REST Messages And Data Transfer Objects
In Patterns of Enterprise Application Architecture, Martin Fowler defines a Data Transfer Object (DTO) as:
An object that carries data between processes in order to reduce the number of method calls.
Note that a Data Transfer Object is not the same as a Data Access Object (DAO), although they have some similarities. A Data Access Object is used to hide details from the underlying persistence layer.
REST Messages Are Serialized DTOs
In a RESTful architecture, the messages sent across the wire are serializations of DTOs.
This means all the best practices around DTOs are important to follow when building RESTful systems.
For instance, Fowler writes:
…encapsulate the serialization mechanism for transferring data over the wire. By encapsulating the serialization like this, the DTOs keep this logic out of the rest of the code and also provide a clear point to change serialization should you wish.
In other words, you should follow the DRY principle and have exactly one place where you convert your internal DTO to a message that is sent over the wire.
In JAX-RS, that one place should be in an entity provider. In Spring, the mechanism to use is the message converter. Note that both frameworks have support for several often-used serialization formats.
Following this advice not only makes it easier to change media types (e.g. from plain JSON or HAL to a more mature media type like Siren, Mason, or UBER). It also makes it easy to support multiple media types.
This in turn enables you to switch media types without breaking clients.
You can continue to serve old clients with the old media type, while new clients can take advantage of the new media type.
Introducing new media types is one way to evolve your REST API when you must make backwards incompatible changes.
DTOs Are Not Domain Objects
Domain objects implement the ubiquitous language used by subject matter experts and thus are discovered. DTOs, on the other hand, are designed to meet certain non-functional characteristics, like performance, and are subject to trade-offs.
This means the two have very different reasons to change and, following the Single Responsibility Principle, should be separate objects. Blindly serializing domain objects should thus be considered an anti-pattern.
That doesn’t mean you must blindly add DTOs, either. It’s perfectly fine to start with exposing domain objects, e.g. using Spring Data REST, and introducing DTOs as needed. As always, premature optimization is the root of all evil, and you should decide based on measurements.
The point is to keep the difference in mind. Don’t change your domain objects to get better performance, but rather introduce DTOs.
DTOs Have No Behavior
A DTO should not have any behavior; it’s purpose in life is to transfer data between remote systems.
This is very different from domain objects.
There are two basic approaches for dealing with the data in a DTO.
The first is to make them immutable objects, where all the input is provided in the constructor and the data can only be read.
This doesn’t work well for large objects, and doesn’t play nice with serialization frameworks.
The better approach is to make all the properties writable. Since a DTO must not have logic, this is one of the few occasions where you can safely make the fields public and omit the getters and setters.
Of course, that means some other part of the code is responsible for filling the DTO with combinations of properties that together make sense.
Conversely, you should validate DTOs that come back in from the client.
Reference: | REST Messages And Data Transfer Objects from our JCG partner Remon Sinnema at the Secure Software Development blog. |