DEV Community

Rodolpho Alves
Rodolpho Alves

Posted on • Originally published at Medium on

Cell CMS — Validando Inputs e Mapeamento Automático

Cell CMS — Validando Inputs e Mapeamento Automático

Cell-CMS, rodando no Kestrel

No último post falamos sobre o MediatR e o design pattern Mediator, implementando os endpoints com Commands e Queries. No post de hoje vamos continuar de onde paramos e adicionar validação aos nossos Commands e realizar o mapeamento automático dos Commands e seus campos para nossos Models.

Hoje faremos dois novos branches: feature/fluent-validation e feature/auto-mapper, um deles será para a instalação e configuração do FluentValidation e o outro para a instalação de configuração do AutoMapper.

Validando inputs com a sintaxe padrão

Por padrão, no universo .NET, temos os DataAnnotations para realizar a validação automática de nossos objetos. A documentação completa para eles pode ser encontrada neste link.

Utilizando estes componentes temos de, em nossas classes, adicionar alguns Attributes para realizar as validações. Por exemplo, em um Command, eu poderia realizar a validação da seguinte maneira:

https://medium.com/media/0b97caf17dadc5cb014839cb690dbf6d/href

A vantagem desta abordagem é que o .NET MVC automaticamente identifica estas anotações e as executa , permitindo que acessemos seu status através do ModelState! Desta maneira podemos, por exemplo, verificar o ModelState em nossos endpoints e retornar erros de validação como BadRequests.

https://medium.com/media/a16692cc8c37122cd620e1225ccbdb0e/href

A desvantagem desta abordagem é que estamos misturando lógicas de validação com lógicas de armazenamento de nossas classes (se você for da galera SOLID, podemos dizer que fere o Single Resposability de nossa classe). Outra desvantagem é que esta abordagem é prática apenas para validações mais simples. Se, em algum momento, você decidir realizar uma validação assincrona ou mais complexa deverá criar seu próprio Attribute.

Mas Rodolpho, existe outra maneira que possamos realizar validações sem criar nosso próprio framework ou poluir o código de execução com infinitos IFs!?

Sim! Existem alternativas prontas para utilizarmos! Uma delas é o FluentValidation!

Validando inputs com sintaxe Fluent — FluentValidation

Utilizando a biblioteca FluentValidation podemos escrever nossas validações em classes separadas , integrar estas validações com o middleware MVC e utilizar o mesmo ModelState para armazenar nossos resultados e erros de validação!

No Projeto da API adicione o NuGetFluentValidation.AspNetCore às dependências. Primeiros vamos configurar a integração com o MVC! Acesse o seu Startup.cs e realize as seguintes alterações:

https://medium.com/media/621794af1d506a884da60c4d6796ffe0/href

Agora precisamos escrever nossas regras de validação. Utilizarei o CreateFeed como exemplo. Crie uma nova classe (pode ser em um novo arquivo ou no CreateFeed.cs) chamada CreateFeedValidator e herde a classe AbstractValidator. Agora, graças ao AbstractValidator temos acesso à sintaxe Fluent dentro do Construtor da nossa classe. Com isso podemos escrever nossas regras de validação:

https://medium.com/media/98defd0c7d54db49279ec9b18cfd1ed6/href

Outras vantagens do FluentValidations são:

  • Criação de Rulesets para agrupar as validações (por exp: Ruleset para validações síncronas e assíncronas)
  • Validação condicionais (por exp: Se informar X, Y não pode ser null)
  • Validações assíncronas (por exp: Consultar no Context se existe alguém com a Propriedade X ou Y)

Por exemplo uma regra assíncrona para verificar que não existe um Content com o mesmo Nome na base de dados:

https://medium.com/media/f3f0c67e78fd87ceb07c796f20460aa0/href

A documentação completa está disponível em https://fluentvalidation.net/ e sugerido uma boa olhada! A biblioteca é bem ampla e possui várias funcionalidades úteis.

Só para não deixar passar vazio temos um exemplo da validação para uma request inválida:

https://medium.com/media/ab5dfc1ca3fd881ee8ec443921ccb36b/href

Mapeando propriedades manualmente

Atualmente realizamos a “tradução” de nossos Commands de maneira manual. Ou seja, criamos um novo Model e o preenchemos com os valores que vieram do nosso Command. Por exemplo, na atualização de uma Tag:

https://medium.com/media/600dce8952265d1131f6521cba29bd28/href

Isso, com o passar do tempo, torna-se repetitivo e meio braçal. Uma solução seria escrevermos Adaptors ou Factories (design patterns) para separar a lógica do mapeamento da lógica de execução, porém ainda temos o problema original , salvo que escrevamos algo que realiza o mapeamento através de Reflection, com base nos nomes das Propriedades de Origem e Destino.

Felizmente alguém já escreveu isto para nós! Do mesmo criador que o MediatR temos o famosíssimo AutoMapper!

Mapeando propriedades automaticamente — AutoMapper

Utilizando a biblioteca AutoMapper podemos contar com o mapeamento automático de propriedades através de padrões de nomenclatura e Reflection.

Para começarmos vamos adicionar o NuGet AutoMapper.Extensions.Microsoft.DependencyInjection à API e alterar nosso Startup.cs para registrar o AutoMapper nos services injetáveis:

https://medium.com/media/c911a184182bfb24c2616d1f2a844ae9/href

Agora precisamos criar nossos Mapeamentos. O AutoMapper, ao ser utilizado com injeção de dependência, requer que criemos “Profiles” para organizar nossos mapeamentos. Estes Profiles irão conter o “registro” para que o IMapper saiba entre quais objetos pode atuar!

Comecei criando o Profile para nossos Feeds no arquivo Features/Feeds/FeedProfile.cs:

https://medium.com/media/2417ce1e26aa2c545339673cbe8f76a5/href

Para utilizarmos o Profile basta injetar o IMapper através do construtor e utilizar os métodos Map() para delegar ao AutoMapper o trabalho de popular as propriedades!

https://medium.com/media/8f1c8241899635e2fa32d1423c30aa93/href

Assim como o FluentValidation o AutoMapper é amplamente customizável e você pode dar uma olhada na documentação completa em https://automapper.org/!

Considerações Finais

Hoje vimos duas bibliotecas bem úteis para o universo .NET, seja para o Frontend ou para o Backend estas bibliotecas nos auxiliam a manter o código limpo e organizado!

Para o próximo post a ideia será melhorarmos o processo de Log de Erros utilizando o Serilog, obter métricas automaticamente com o Application Insights e adicionarmos Healthchecks à nossa API e banco de dados!

Obrigado por lerem mais este post e até a próxima! Abraços!

Top comments (0)