Curso de Spring Boot

En aplicaciones profesionales no es buena práctica devolver directamente las entidades de la base de datos.

En su lugar se usan DTOs.

DTO significa:

Data Transfer Object

Son objetos diseñados específicamente para enviar o recibir datos en la API.


10.1 Problema de devolver entidades directamente

Supongamos esta entidad:

1@Entity
2public class User {
3
4    @Id
5    @GeneratedValue
6    private Long id;
7
8    private String name;
9
10    private String email;
11
12    private String password;
13
14}

Si devolvemos esto directamente:

1@GetMapping("/users")
2public List<User> getUsers() {
3    return repository.findAll();
4}

La respuesta sería:

1[
2  {
3    "id": 1,
4    "name": "Ana",
5    "email": "ana@email.com",
6    "password": "123456"
7  }
8]

⚠️ Problema: estamos enviando la contraseña.

Esto es muy peligroso.


10.2 Qué es un DTO

Un DTO es una clase que contiene solo los datos que queremos exponer.


Ejemplo

1public class UserDTO {
2
3    private Long id;
4
5    private String name;
6
7    private String email;
8
9}

Ahora no existe el campo password.


10.3 Usar DTO en el Controller

1@GetMapping("/users")
2public List<UserDTO> getUsers() {
3
4    List<User> users = repository.findAll();
5
6    return users.stream()
7            .map(user -> new UserDTO(
8                    user.getId(),
9                    user.getName(),
10                    user.getEmail()
11            ))
12            .toList();
13}

Resultado

1[
2  {
3    "id": 1,
4    "name": "Ana",
5    "email": "ana@email.com"
6  }
7]

La contraseña ya no aparece.


10.4 DTO para crear usuarios

También podemos usar DTOs para recibir datos.


Ejemplo

1public class CreateUserDTO {
2
3    private String name;
4
5    private String email;
6
7    private String password;
8
9}

Controller

1@PostMapping("/users")
2public User createUser(@RequestBody CreateUserDTO dto) {
3
4    User user = new User();
5
6    user.setName(dto.getName());
7    user.setEmail(dto.getEmail());
8    user.setPassword(dto.getPassword());
9
10    return repository.save(user);
11
12}

10.5 Tipos de DTO comunes

En proyectos grandes suele haber varios DTO.


Ejemplo

1UserDTO
2CreateUserDTO
3UpdateUserDTO
4UserResponseDTO

Ejemplo

1public class UpdateUserDTO {
2
3    private String name;
4
5}

10.6 Problema del mapeo manual

Si tenemos muchas entidades, convertir manualmente puede ser pesado.

Ejemplo:

1UserDTO dto = new UserDTO(
2        user.getId(),
3        user.getName(),
4        user.getEmail()
5);

Si hay muchas entidades esto se vuelve repetitivo.


10.7 Usar MapStruct

Para solucionar esto se usa MapStruct.

MapStruct genera automáticamente el código de conversión.


10.8 Añadir dependencia MapStruct

En pom.xml:

1<dependency>
2   <groupId>org.mapstruct</groupId>
3   <artifactId>mapstruct</artifactId>
4   <version>1.5.5.Final</version>
5</dependency>

10.9 Crear un mapper

1@Mapper(componentModel = "spring")
2public interface UserMapper {
3
4    UserDTO toDTO(User user);
5
6    User toEntity(CreateUserDTO dto);
7
8}

Spring generará automáticamente el código.


10.10 Usar el mapper

1@Service
2public class UserService {
3
4    private final UserRepository repository;
5    private final UserMapper mapper;
6
7    public UserService(UserRepository repository, UserMapper mapper) {
8        this.repository = repository;
9        this.mapper = mapper;
10    }
11
12    public List<UserDTO> getUsers() {
13
14        return repository.findAll()
15                .stream()
16                .map(mapper::toDTO)
17                .toList();
18
19    }
20
21}

10.11 Ejemplo completo arquitectura

1Controller
23Service
45Repository
67Entity

DTOs se usan entre:

1Controller ↔ Service

10.12 Flujo completo

Cliente envía JSON:

1{
2  "name": "Ana",
3  "email": "ana@email.com",
4  "password": "123456"
5}

Flujo:

1JSON → CreateUserDTO → Entity → Database

Respuesta:

1Entity → UserDTO → JSON

10.13 Buenas prácticas con DTO

No devolver entidades

Siempre usar DTO.


Separar DTO de entrada y salida

Ejemplo:

1CreateUserDTO
2UserResponseDTO

Validar DTO

Ejemplo:

1public class CreateUserDTO {
2
3    @NotBlank
4    private String name;
5
6    @Email
7    private String email;
8
9}

Usar mappers

Evita escribir conversiones manualmente.


10.14 Ventajas de usar DTO

ventajaexplicación
seguridadno expones campos sensibles
flexibilidadAPI independiente de DB
controldecides qué enviar
mejor diseñoarquitectura limpia
  • Loading...