Aplicando el patrón DTO y mapeando objetos con AutoMapper en un Web API con NET Core
Aprende a aplicar el patrón DTO y a mapear como un pro en un proyecto real, es en la cancha donde se aprende 😉

Seguramente ya sabes qué es el patrón DTO y si no lo sabes puedes aprenderlo aquí. Entonces ya tienes claro que se deben manejar distintas clases para comunicarnos con el cliente, por ejemplo no utilizar la misma clase para guardar un nuevo registro que para mostrar información al usuario, genial, eso quedó clarísimo entonces.

Pues bien eso implica estar a cada rato convirtiendo un objeto de un tipo a otro, veamos este sencillo ejemplo:

Tienes la siguiente entidad Autor

Su clase sería algo así

    public class Autor
    {
        [Key]
        public int Id { get; set; }

        [Required]
        [StringLength(maximumLength:120)]
        public string Nombre { get; set; }


    }

Muy bien esa es la entidad, es decir la clase que se corresponderá con una tabla en la base de datos, por eso estamos incluyendo la propiedad Id.

Pero cuando desde un cliente (podría ser web, móvil o cualquier cosa) queremos guardar un nuevo Autor, no es necesario que le enviemos un Id, de hecho estaría mal hacerlo por dos motivos:

  • Dejamos de cumplir el principio I de SOLID, concretamente el ISP (Interface segregation principle) porque estamos entregando más información de la necesaria.
  • el mensaje transmitido por la red es mayor de forma innecesaria, tu dirás pero es solo una propiedad, pero recuerda que estamos haciendo un ejemplo simplificado y que lo que ahora es un entero, podría ser en otro contexto un campo de tipo archivo.

Como ya sabemos aplicar el patrón DTO entonces en nuestro proyecto creamos una carpeta llamada DTO

Y creamos dos clases llamadas AutorDTO y AutorCreacionDTO

    public class AutorDTO
    {
        [Key]
        public int Id { get; set; }
        [Required]
        [StringLength(maximumLength:120)]
        public string Nombre { get; set; }
        
    }
    public class AutorCreacionDTO
    {
        [Required]
        [StringLength(maximumLength: 120)]
        public string Nombre { get; set; }
    }

Ahora sí tenemos dos clases cada una para su funcionalidad y no trabajamos directamente con la entidad, genial! 😉

A continuación compararemos las dos formas de trabajar los mapeos en un controlador:

Controlador con mapeo manual

Ahora que tenemos la entidad y sus DTO creadas, es momento de codificar el controlador al cual llamaremos AutoresController

Pero primero veamos cómo serían los endpoint Get y Post de Autores controller si no usáramos AutoMapper

        [HttpGet]
        public async Task<List<AutorDTO>> Get()
        {
            var autores = await context.Autores.ToListAsync();//autores traídos desde la BD
            var autoresDTO = new List<AutorDTO>();//lista DTO de retorno
            foreach(var autor in autores)
            {
                autoresDTO.Add(new AutorDTO { Id = autor.Id, Nombre = autor.Nombre });//mapeo manual por cada iteración
            }
            return autoresDTO;
        }

En el caso del endpoint Post tendríamos algo así:

        [HttpPost]
        public async Task<ActionResult> Post([FromBody] AutorCreacionDTO autorCreacionDTO)
        {
            var autor = new Autor { Nombre = autorCreacionDTO.Nombre };//mapeo manual
            await context.Autores.AddAsync(autor);
            await context.SaveChangesAsync();
            return Ok();
        }

Manejar el mapeo de forma manual trae dos inconvenientes:

  • Más código y trabajo repetitivo
  • Por si el motivo anterior te pareció insuficiente, también es inseguro, porque al tener que estar mapeando en cada método de todos tus controladores, cuando hagas cambios en las entidades va a implicar que tendrás que actualizar todos y cada uno de los mapeos en los muchos métodos que tengas y Ay de ti si te olvidas jaja...

Manejemos los mapeos de forma centralizada mejor, empecemos a configurar AutoMapper

Configurando AutoMapper

Estamos trabajando en un Web API con .Net Core así que vamos a Nuget e instalaremos

AutoMapper.Extensions.Microsoft.DependencyInjection

Vamos a la clase Startup.cs y en el método ConfigureServices agregamos esto:

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddAutoMapper(typeof(Startup));

            //...

            services.AddControllers();
        }

Crearemos los perfiles de AutoMapper para esto creamos una carpeta llamada Utils y la clase llamada AutoMapperProfiles que hereda de Profile (AutoMapper.Profile)

    public class AutoMapperProfiles : Profile
    {
        public AutoMapperProfiles()
        {
            CreateMap<Autor, AutorDTO>().ReverseMap();//mapea desde Autor hacia AutorDTO y viceversa
            CreateMap<AutorCreacionDTO, Autor>();//mapea desde AutorCreacionDTO hacia Autor
        }
    }

Si las propiedades entres las clases a mapear tienen el mismo nombre con esto basta, si fuesen distintos desde esta misma clase la puedes configurar con el método .ForMember la sintaxis sería así:

Mapper.CreateMap<Autor, AutorDTO>()
    .ForMember(dest => dest.NombreCompleto, opt => opt.MapFrom(src => src.Nombre));

Con eso ya tenemos todo configurado, ahora veamos como quedan los controladores usando Automapper

Controlador con AutoMapper

        [HttpGet]
        public async Task<List<AutorDTO>> Get()
        {
            var autores = await context.Autores.ToListAsync();
            return mapper.Map<List<AutorDTO>>(autores);//Aquí se hace el mapeo
        }

Ahora veamos el endpoint de guardado

        [HttpPost]
        public async Task<ActionResult> Post([FromBody] AutorCreacionDTO autorCreacionDTO)
        {
            var autor = mapper.Map<Autor>(autorCreacionDTO);//aquí se hace el mapeo
            await context.Autores.AddAsync(autor);
            await context.SaveChangesAsync();
            return Ok();
        }
Lo hicimos! Photo by Niklas Ohlrogge on Unsplash

Y bueno mis cracks! eso es todo, y quería compartirlo con ustedes, recuerden que Automapper funciona con varias tecnologías no sólo con .Net, aquí vimos el ejemplo con .NET porque soy net lover 💙 y me da pa comer 🤣 pero visita la documentación de AutoMapper en https://automapper.org/ y verifica mucho más cosas que tiene.

Un gran abrazo a todos y si te gustó esta entrada ya sabes que hacer crack, comparte! Y sígueme en Linkedin, hasta la vista baby dev 😎

8 comentarios en «Aplicando el patrón DTO y mapeando objetos con AutoMapper en un Web API con NET Core»

  1. Buen aporte, fácil y sencillo.

    Entiendo que Automapper ayuda y reduce mucho las líneas de Código, pero Tambien tienen sus desventajas al momento del debug.

    Creo que automapper estaria bien usarlo cuando ya se tiene cierto conocimiento y experiencia.

    1. Hola estimado Pablo, así es, como todo en la vida, tiene sus pro y contras, sin embargo considero que sus ventajas superan por mucho a las desventajas, y por ello siempre debe usarse desde que uno hace sus primeros desarrollos para acostumbrarse a las buenas prácticas. Quizá no deba usarse sólo en sistemas muy pequeñitos y monolíticos. Saludos y vuelve pronto, comparte!

  2. Muy buen aporte, claro y sencillo. Me ayudaste mucho. Tenia dudas sobre como configurar el automapper cuando los campos se llaman distinto
    Muchas gracias!

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *