The DTO Pattern (Data Transfer Objects)

Orçun Yılmaz
5 min readJul 7, 2023

Most of the programs we write nowadays are carrying massive amounts of data around, at the backend side of our precious applications. While some of the transactions are crucial for the application to reveal the data to end users — well of course the necessary ones, some great amount of unused data may be transferred between endpoints. Even in scenarios where we design our entities with fine craftsmanship and only send the necessary data to the front-end side, we may cause some unnecessary transactions around. This situation may lead to superfluous network loads, hence maybe redesigning some of our application parts to reduce the load on our servers.

In this article, we will discuss the DTO Pattern, its necessity, and how and when to use it.

DTO is an object that carries data between processes in order to reduce the number of method calls, says Michael Fowler, in his book EEA (Patterns of Enterprise Application Architecture) where he explains the details about it.

According to Martin Fowler’s explanation, it seems that DTOs are a kind of plug-and-play solution to reduce network costs or stop revealing unnecessary data to clients.

So let’s dive into the point.

Simply put, DTOs are flat data structures that contain no business logic (generally), but only contain storage, accessors, and eventually methods related to serialization or parsing.

By using a mapper component, you may get the necessary data from some domain objects, in other words, entities.

See the below illustration to understand the interactions between components.

Fowler explained that the pattern’s main purpose is to reduce roundtrips to the server by batching up multiple parameters in a single call. This reduces the network overhead in such remote operations.

As shown in the figure above, the DTO pattern approach simply represents combining some objects together, but only for the needed fields. To make it clearer, we can illustrate the above figure;

Let’s say we have a User entity that has the below variables in it.

public class User {
private String id;
private String name;
private String address;
private String password;
private List<Role> roles;
}

And we have a Role entity that has the below variables in it.

public class Role {
private String id;
private String name;
}

Let’s say we have a client request, and that request needs to have the User’s name, address, and roles.

Below is the UserDTO object example;

public class UserDTO {
private String name;
private String address;
private List<Role> roles;
}

To get this info, we may expect two different requests from the client to get the User object and Role object separately, and then wait for it to simplify the data that it got from the backend side.

What happened now?

Our client needed to make two separate requests to the backend side and then do some mapping. And it should repeat these operations whenever necessary. However, we could have done all of these on the backend for much cheaper.

Let’s give another example of DTO pattern use cases.

Let’s say we have the following hoppingly unrealistic Bank database table that contains the following variables;

public class BankAccount {
private Long id;
private String firstName;
private String lastName;
private Date birthDate;
private String accountNumber;
private String idNumber;
private Integer pinCode;
private BigInt accountBalance;
}

You don’t want to transfer all of this data around seeing that it contains sensitive data.

Let’s say our client needs firstName, lastName, and accountNumber info to expose at the front-end side of our application.

In this scenario, there would be a security leak if we transfer unnecessary data like idNumber, pinCode, or accountBalance to the front-end side. Even in the scenarios where it doesn’t a problem to pass all the data, it would be a heavily loaded request where we transfer the unnecessary data around again and again, hence leading us to an unnecessary network load.

Instead, we may create a new object for this scenario.

Below is an example DTO object which contains all the info our client needs in this scenario.

public class BankAccountDTO {
private String firstName;
private String lastName;
private String accountNumber;
}

This new data transfer object now contains no sensitive or unwanted data. This will give you the freedom to add or remove properties without breaking your database calls.

What now?

We need mapper methods/classes to map these entity objects to the necessary DTOs.

This Mapper component is going to transfer the data, making sure that both DTO and domain model don’t need to know about each other.

Here is a mapper class for the first example. It is only for mapping the User entity to the UserDTO object;

@Component
class Mapper {
public UserDTO toDto(User user) {
String name = user.getName();
String address = user.getAddress();

List<String> roles = user.getRoles().stream()
.map(Role::getName)
.collect(toList());

return new UserDTO(name, roles);
}

You may also produce the one that takes UserDTO as input and gives you the User entity as a response.

With the above mapper class/methods, we are now able to make a call from client to server, asking for some info, and getting it without heavy loading the backend side of the application. It is cheaper, safer, and cleaner than before.

When to use the DTO Pattern?

DTOs help to reduce the number of transactions that are being made all around the application.

DTOs also help when the domain model is composed of many different objects and the presentation model needs all their data at once, or they can even reduce roundtrip between client and server.

A layer of DTO isolates the domain model from the presentation, resulting in both loose coupling and optimized data transfer. So the scenario is obvious here.

With DTOs, we can build different views from our domain models, allowing us to create other representations of the same domain but optimizing them to the client’s needs without affecting our domain design. Such flexibility is a powerful tool to solve complex problems.

Furthermore, the adoption of DTO adds a good deal of flexibility to the service layer and subsequently to the design of the entire application. For example, if DTOs are used, a change in the requirements that forces a move to a different amount of data doesn’t have any impact on the service layer or even the domain. You modify the DTO class involved by adding a new property but leave the overall interface of the service layer intact.

--

--