Data Transfer Objects (DTOs) & Mapping
Relevant source files
The following files were used as context for generating this wiki page:
- Back/Alumnos/Api/Comun/Utilidades/MapeoDtos.cs
- Back/Alumnos/Api/Comun/Modelos/Usuarios/CrearUsuarioDto.cs
- Back/Alumnos/Api/Controllers/UsuariosController.cs
- Back/Alumnos/Api/Controllers/ProductoController.cs
- Back/Alumnos/Api/Controllers/CategoriaController.cs
- Back/Alumnos/Api/Comun/Modelos/Categorias/CrearCategoriaDto.cs
- Back/Alumnos/Api/Comun/Modelos/Categorias/ModificarCategoriaDto.cs
- Back/Alumnos/Api/Comun/Modelos/Usuarios/ModificarUsuarioDto.cs
The project utilizes Data Transfer Objects (DTOs) as a structured way to transfer data between the API controllers and the persistence layer. This pattern decouples the internal database entities from the external API contracts, ensuring that only necessary information is exposed to the client or accepted for creation and modification operations.
Mapping is handled through a centralized utility class that provides extension methods to convert database entities into their respective DTO counterparts. This ensures consistency across the application when returning data to the frontend or processing incoming requests.
Architecture and Data Flow
The architecture follows a standard flow where incoming requests are received by controllers as DTOs, processed, and then persisted as entities. Conversely, when retrieving data, entities are fetched from the database and mapped to "Search" or "Result" DTOs before being sent to the client.
Request-Response Mapping Flow
The following diagram illustrates the typical lifecycle of data as it moves between the client, the API controllers, and the database using DTOs.
The flow ensures that entities like Usuario, Producto, or Categoria are never directly exposed to the network.
Sources: Back/Alumnos/Api/Controllers/UsuariosController.cs, Back/Alumnos/Api/Comun/Utilidades/MapeoDtos.cs
DTO Categorization
DTOs in this project are categorized based on their intent: creation, modification, or data retrieval (Search).
Creation DTOs
These objects are used to capture the minimum required fields to create a new record. They often include validation attributes.
| DTO Name | Purpose | Key Fields |
|---|---|---|
CrearUsuarioDto | Registering new users | Nombre, ApellidoPaterno, Contraseña, Habilitado |
CrearCategoriaDto | Creating new categories | Nombre, Descripcion, Slug |
CrearProductoDto | Publishing new products | Nombre, Precio, CategoriaSlug, UsuarioSlug |
Sources: Back/Alumnos/Api/Comun/Modelos/Usuarios/CrearUsuarioDto.cs:5-18, Back/Alumnos/Api/Comun/Modelos/Categorias/CrearCategoriaDto.cs:3-9
Modification DTOs
These are used for updates and typically require an identifier (like an ID or Slug) to locate the resource.
| DTO Name | Purpose | Target Entity |
|---|---|---|
ModificarUsuarioDto | Updating profile info | Usuario |
ModificarCategoriaDto | Updating category details | Categoria |
ModificarProductoDto | Updating product info | Producto |
Sources: Back/Alumnos/Api/Comun/Modelos/Usuarios/ModificarUsuarioDto.cs:5-16, Back/Alumnos/Api/Comun/Modelos/Categorias/ModificarCategoriaDto.cs:3-10
Mapping Logic
The MapeoDtos static class serves as the central hub for entity-to-DTO conversion. It uses C# extension methods to provide a clean syntax (e.g., entity.ConvertirDto()) within the controllers.
Mapping Utility Class Diagram
The following diagram represents the mapping structure provided by the utility class.
Implementation Example: Usuario Mapping
The mapping logic explicitly selects which properties from the internal Usuario entity are safe to return to the UI, excluding sensitive fields like hashed passwords.
public static BuscarUsuariosDto ConvertirDto(this Usuario usuario)
{
return new BuscarUsuariosDto()
{
Slug = usuario.Slug,
Nombre = usuario.Nombre,
ApellidoPaterno = usuario.ApellidoPaterno,
ApellidoMaterno = usuario.ApellidoMaterno,
NombreUsuario = usuario.NombreUsuario,
Habilitado = usuario.Habilitado,
};
}
Sources: Back/Alumnos/Api/Comun/Utilidades/MapeoDtos.cs:12-22
Controller Integration
Controllers utilize DTOs for both input parameters and return types. For collection results, the ConvertAll method is frequently used in conjunction with the mapping extensions.
Retrieval Logic in Controllers
When fetching a list of categories, the controller queries the database via the context, retrieves the entity list, and converts each item:
[HttpGet]
public async Task<List<BuscarCategoriaDto>> ObtenerCategorias(string? nombre)
{
var query = _contexto.Categoria.AsQueryable();
// ... filtering logic ...
var lista = await query.ToListAsync();
return lista.ConvertAll(x => x.ConvertirDto());
}
Sources: Back/Alumnos/Api/Controllers/CategoriaController.cs:22-34
Creation Logic in Controllers
Incoming DTOs are manually mapped to new Entity instances before being added to the DbSet.
[HttpPost]
public async Task<int> CrearCategoria([FromBody] CrearCategoriaDto categoriaDto, CancellationToken cancelacionToken)
{
var nuevaCategoria = new Categoria
{
Nombre = categoriaDto.Nombre,
Descripcion = categoriaDto.Descripcion,
Slug = categoriaDto.Slug
};
await _contexto.Categoria.AddAsync(nuevaCategoria, cancelacionToken);
await _contexto.SaveChangesAsync(cancelacionToken);
return nuevaCategoria.CategoriaID;
}
Sources: Back/Alumnos/Api/Controllers/CategoriaController.cs:46-60
Conclusion
The DTO and Mapping system in this project provides a robust layer of abstraction. By centralizing mapping logic in MapeoDtos.cs and enforcing the use of specialized DTOs for different operations (Create, Modify, Search), the system maintains a clear separation of concerns between the data persistence layer and the API communication layer. This architecture facilitates easier maintenance and prevents the accidental exposure of sensitive internal data.