Efficient Data Transfer in REST APIs: A Deep Dive into the DTO Pattern with Spring Boot and MySQL

In this article, I explore various techniques to enhance security, ensure data integrity, optimize network traffic, and improve flexibility in your applications. The Data Transfer Object (DTO) pattern plays a vital role in managing sensitive user information and controlling the data clients receive.
If you haven’t read my previous article(Step-by-Step Guide: Developing a Bookstore API with Spring Boot and MySQL for CRUD Operations), I recommend checking it out as it sets the foundation for this piece. Here, I delve deeper into the practical implementation of the DTO pattern, providing step-by-step guidance. Throughout the article, you’ll discover how to effectively leverage the DTO pattern to streamline client-server communication, minimize network payload, and safeguard sensitive data. I share best practices and techniques for designing efficient DTOs that prioritize security and privacy.
Join me on this journey as we unlock the potential of the DTO pattern to build robust and secure applications. Your valuable feedback and insights are greatly appreciated as we support each other in our pursuit of software excellence.
Problem: Data Exposure
In this case, the REST API includes three methods: createUser(), getAllUsers(), and getUserById(). When a user is created, a password is added. Now, imagine if someone calls the getAllUsers() or getUserById() methods. They would receive the complete raw information about the user, including the password. However, for obvious reasons, we don’t want to send the password back. To see how this is handled, take a look at the Postman screenshots that demonstrate the response a user would receive.


Solution: DTO(Data Transfer Object) Pattern
- In Spring Boot, the DTO (Data Transfer Object) pattern is essential for transferring data between different layers or components of an application.
- DTOs encapsulate and organize data, making communication between layers more efficient.
- They separate the internal representation of data (entities or domain objects) from the data exposed to the external world (APIs, views, etc.).
- DTOs provide a clear and consistent data structure for communication purposes.
- When data needs to be transferred between layers or components, DTOs package the relevant data and facilitate its transmission.
- This approach avoids exposing unnecessary internal details and reduces the amount of data being transferred.
- DTOs can be used with mapping frameworks (e.g., ModelMapper, MapStruct) to automatically convert entities or domain objects into DTOs and vice versa.
- This simplifies the process of transforming data between different representations.
- The advantages of using the DTO pattern include decoupling the internal data model from the external representation, improving performance by reducing data transfer, enhancing security by controlling data exposure, and providing flexibility in modifying the data structure without affecting external interfaces.

Ways to implement the DTO Pattern
There are several ways to implement the DTO (Data Transfer Object) pattern in a Spring Boot application. Here are two common approaches:
Manual Mapping:
- Create separate DTO classes that mirror the structure of your domain entities or objects.
- Manually map the fields from the entities to the corresponding fields in the DTOs.
- Use getter and setter methods in the DTOs to access and modify the data.
- Perform the mapping between entities and DTOs in the service layer or a dedicated mapping class.
Mapping Frameworks:
- Utilize mapping frameworks like ModelMapper, MapStruct, or Dozer.
- Configure the mapping framework to automatically map fields between entities and DTOs based on naming conventions or explicit mappings.
- The mapping framework will handle the conversion of complex object structures and nested properties.

Manual Mapping
Create a package called dto inside your folder structure for better organization. Then create a class called UserDto.
@Getter
@Setter
public class UserDto {
private Long id;
private String firstName;
private String lastName;
private String email;
}
The UserDto class itself represents a Data Transfer Object (DTO) for transferring user data. It encapsulates the data fields id, firstName, lastName, and email, providing a structured representation of user information.
The purpose of using this DTO is to separate the internal representation of user data (e.g., in the database or business logic) from the data exposed to external clients or systems.
By using a DTO, you can define a clear contract for the data structure and its fields, making it easier to manage and transfer data between different layers or components of your application. For example, in the UserController class, the UserDto is used as the return type for API endpoints such as getAllUsers and getUserById. This ensures that only the necessary user data is exposed to clients.

Create a package called mapper inside your folder structure for better organization. Then create a class called UserMapper.
public class UserMapper {
public static UserDto convertEntityToDto(User user) {
UserDto userDto = new UserDto();
userDto.setId(user.getId());
userDto.setFirstName(user.getFirstName());
userDto.setLastName(user.getLastName());
userDto.setEmail(user.getEmail());
return userDto;
}
}
The convertEntityToDto method takes a User object as input and creates a new UserDto object. It then retrieves the properties from the User object (such as id, firstName, lastName, and email) and sets them on the corresponding fields of the UserDto object using the setter methods.
By using this UserMapper class, you can easily convert User entities into UserDto objects and vice versa. This helps decouple the internal entity representation from the external DTO representation and provides a clear separation of concerns.
For example, you might use this mapper in your service layer or controller to convert User entities retrieved from the database into DTOs before returning them in API responses. This ensures that the API only exposes the necessary data fields defined in the UserDto class, providing a controlled and consistent representation of user data to the clients.

Now you can use it in UserImplementation Class
@Service
public class UserImplementation implements UserService {
@Autowired
private UserRepository userRepository;
@Override
public User createUser(User user) {
return userRepository.save(user);
}
@Override
public List<UserDto> getAllUsers() {
List<User> userList = userRepository.findAll();
List<UserDto> userDtoList = new ArrayList<>();
for(User user:userList) {
// Custom Mapper
UserDto userDto = UserMapper.convertEntityToDto(user);
userDtoList.add(userDto);
}
return userDtoList;
}
@Override
public UserDto getUserById(Long userId) {
Optional<User> optionalUser = userRepository.findById(userId);
// Custom Mapper
return UserMapper.convertEntityToDto(optionalUser.get());
}
}
Mapping Frameworks
- Add ModelMapper to Maven Dependency, use Maven Repository Model Mapper
- Configure ModelMapper class a Spring Bean
@SpringBootApplication
public class DemoDtoApplication {
@Bean
public ModelMapper modelMapper(){
return new ModelMapper();
}
public static void main(String[] args) {
SpringApplication.run(DemoDtoApplication.class, args);
}
}
- Inject and use it in UserImplementation Class
@Service
public class UserImplementation implements UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private ModelMapper modelMapper;
@Override
public User createUser(User user) {
return userRepository.save(user);
}
@Override
public List<UserDto> getAllUsers() {
List<User> userList = userRepository.findAll();
List<UserDto> userDtoList = new ArrayList<>();
for(User user:userList) {
// ModelMapper
UserDto userDto = modelMapper.map(user, UserDto.class);
userDtoList.add(userDto);
}
return userDtoList;
}
@Override
public UserDto getUserById(Long userId) {
Optional<User> optionalUser = userRepository.findById(userId);
// ModelMapper
return modelMapper.map(optionalUser.get(), UserDto.class);
}
}



Get the repo of the app: https://github.com/LuisSalas94/SpringBoot-User-DTO
Thank you for taking the time to read my article until the end. I sincerely hope that you have gained valuable insights and knowledge from it. If you found the article enjoyable and informative, I kindly ask you to share it with your friends and colleagues.
I will continue my Java/Spring journey, further exploring and expanding my knowledge of these technologies.
Once again, thank you for your time and support. Stay tuned for more articles and updates as I embark on this exciting Java and Spring adventure.
Thank you for reading until the end. Please consider following the writer and this publication. Visit Stackademic to find out more about how we are democratizing free programming education around the world.
💖 Say 👋 to me!
Fernando Salas
Email: luisfernandosalasg@gmail.com
LinkedIn: https://www.linkedin.com/in/luisfernandosalasgave/
GitHub: https://github.com/LuisSalas94
Check out my other articles:
- Coding Pattern: Cyclic Sort
- Coding Pattern: Two-Pointers
- Coding Pattern: Sliding Window
- 3 Non-Technical Books that will make you a better programmer
- Step-by-Step Guide: Developing a Bookstore API with Spring Boot and MySQL for CRUD Operations
Stackademic 🎓
Thank you for reading until the end. Before you go:
- Please consider clapping and following the writer! 👏
- Follow us X | LinkedIn | YouTube | Discord
- Visit our other platforms: In Plain English | CoFeed | Differ
- More content at Stackademic.com