Appearance
¿Qué es un DTO?
Un DTO (Data Transfer Object, u objeto de transferencia de datos) es una clase que define los datos que una aplicación recibe o devuelve al comunicarse con otra parte del sistema, por ejemplo, mediante una API HTTP.
Su objetivo es transportar únicamente los datos necesarios para una operación, con una estructura clara y controlada.
csharp
public class PedidoCalculoDto
{
public List<LineaPedidoDto> Lineas { get; set; } = new();
}
public class LineaPedidoDto
{
public int ProductoId { get; set; }
public int Cantidad { get; set; }
public decimal Descuento { get; set; }
}En este ejemplo, el DTO representa los datos que necesita la API para calcular un pedido. No necesita incluir todos los campos de las entidades Pedido o PedidoDetalle.
¿Por qué no reutilizar una entidad de Entity Framework?
Una entidad representa un concepto del dominio y suele estar relacionada con la persistencia en la base de datos. Un DTO, en cambio, representa los datos necesarios para una comunicación u operación específica.
Por ejemplo, una entidad PedidoDetalle podría contener:
IdPedidoIdProductoIdCantidadPrecioUnitDescuentoImpuestoPorcTotalLinea- Navegaciones como
PedidoyProducto
Pero para calcular un pedido, el cliente podría necesitar enviar solamente:
ProductoIdCantidadDescuento
Enviar la entidad completa obliga al cliente a conocer campos que no necesita y puede permitir que intente enviar valores que deberían calcularse o controlarse en el servidor.
Ventajas de usar DTOs
- Limitar los datos recibidos: el endpoint acepta solo los campos que necesita.
- No confiar en valores calculados por el cliente: por ejemplo, el servidor puede consultar el precio y el impuesto reales del producto en la base de datos, en lugar de aceptar esos valores enviados desde JavaScript o Postman.
- Separar la API de la base de datos: los cambios internos de una entidad no tienen por qué modificar automáticamente el formato de la API.
- Definir validaciones específicas: un DTO puede incluir reglas adecuadas para una operación, como una cantidad mayor que cero.
- Controlar la respuesta: una API puede devolver solo los datos útiles, sin exponer propiedades internas o relaciones innecesarias.
¿Por qué no usar un diccionario o un objeto anónimo?
Diccionario
Un Dictionary<string, object> permite representar datos con claves dinámicas, pero los nombres y tipos de los valores no quedan definidos de manera tan clara en una clase. Es más fácil introducir errores tipográficos o tener que comprobar tipos manualmente.
Es útil cuando las claves realmente son dinámicas; para una estructura conocida como las líneas de un pedido, normalmente un DTO es más claro.
Objeto anónimo
Un objeto anónimo resulta práctico para construir respuestas pequeñas dentro de un método:
csharp
return Ok(new
{
Subtotal = subtotal,
Impuestos = impuestos,
Total = total
});Sin embargo, no puede declararse como el tipo de una clase reutilizable para recibir un cuerpo JSON en el parámetro de una acción. Para una estructura de entrada conocida o una respuesta que se reutilizará, un DTO con nombre suele ser más mantenible.
¿Cuándo conviene crear un DTO?
Crea un DTO cuando una operación necesita una estructura de datos propia, distinta de la entidad completa, o cuando quieres controlar explícitamente el contrato de entrada o salida de una API.
No es obligatorio crear uno para cada objeto o método. Para una respuesta muy pequeña y puntual, un objeto anónimo puede ser suficiente. La decisión depende de la claridad, la reutilización y el control que necesites.
Ejemplo aplicado a Pedidos360
El endpoint POST /api/pedidos/calcular puede recibir un PedidoCalculoDto con una lista de líneas. Cada línea incluye ProductoId, Cantidad y Descuento.
La API consulta los productos por ID y obtiene de la base de datos los precios y porcentajes de impuesto confiables. Después calcula los importes y devuelve un resultado como Subtotal, Impuestos y Total.
Así, el DTO expresa qué información necesita la operación, mientras que las entidades representan los datos que el sistema gestiona y persiste.
Regla para recordar
Entidad: representa datos del dominio que el sistema puede persistir.
DTO: representa los datos que una operación necesita recibir o devolver.
Objeto anónimo: sirve para construir una estructura puntual sin declarar una clase con nombre.