DEV Community

Yuri Peixinho
Yuri Peixinho

Posted on

Fluent Validation em .NET

O FluentValidation é uma biblioteca que é utilizada para validar objetos de formas simples, expressivas e desacoplada da lógica da aplicação.

É necessário utilizar o FluentValidation quando:

  • Você quer separação de responsabilidades (validar fora da model).
  • Regras complexas ou condicionais são frequentes.
  • Precisa de reutilização e testes unitários em validações.

Dependendo do tamanho do projeto, fazer as validações de objetos em C# pode ser estressante e cansativo. Sempre que criamos uma aplicação, temos modelos que podem ser validados. Essas validações além de complexas podem se tornar incompreensíveis se forem mal escrita, o Fluent Validation é uma ferramenta disponível no mercado que simplifica a forma como fazemos nossas validações. Com ele podemos validar nossas propriedades e objetos de forma clara e de fácil compreensão, além de fáceis de se testar.

Existem várias vantagens em utilizar essa biblioteca, seus destaques são:

  • Separacão das Preocupações: A validação é separada da regra de negócio e da camada de dados.
  • Sintaxe Fluente: Sintaxe intuitiva e legível, permitindo que você escreva validações de forma clara e concisa.
  • Extensibilidade: Você pode estender a biblioteca para adicionar suas próprias regras de validação ou modificar o comportamento existente.
  • Mensagens de erros personalizadas
  • Integração com o ASP NET Core

Instalando pacote no Nuget

Para começar, é necessário instalar o pacote:

  1. Se quiser utilizar integrado com o ASP NET Core
Install-Package FluentValidation.AspNetCore
Enter fullscreen mode Exit fullscreen mode
  1. Se quiser utilizar manualmente
Install-Package FluentValidation
Enter fullscreen mode Exit fullscreen mode

Abordagens

Existem várias formas de abordar esse tipo de validação. A escolha depende da necessidade do projeto. Existem várias formas, mas as mais conhecidas são

  1. Abordagem Manual
  2. Integração com ASP.NET Core

Integração com o ASP NET Core

Quando se utiliza a abordagem de integração, ganha uma série de vantagens

1. Validação automática de modelo

Validação automática do modelo. O ASP.NET chama o validator automaticamente antes do controller ser executado e caso haja erros, já retorna 400 Bad Request

{
  "errors": {
    "Email": ["O campo é obrigatório."],
    "Idade": ["Deve ter no mínimo 18 anos."]
  }
}
Enter fullscreen mode Exit fullscreen mode

2. Menos código repetido

Você não precisa instanciar e validar manualmente o objeto em cada endpoint. Evitando códigos como esse abaixo:

var validator = new UsuarioValidator();
var resultado = validator.Validate(usuario);
Enter fullscreen mode Exit fullscreen mode

3. Integra com o ModelState do ASP.NET

Todos os erros vão para ModelState, e você pode usar normalmente, mas nem precisa — o ASP.NET já faz isso pra você com [ApiController].

if (!ModelState.IsValid) return BadRequest(ModelState);

Enter fullscreen mode Exit fullscreen mode

4. Resposta de erro padronizada e automatizada

Já vem com formatação automática (e pode ser personalizada), o que é uma boa prática para APIs RESTful.

5. Reaproveitamento de regras

Pode usar a mesma validação na API e em serviços internos. Por exemplo: mesma PessoaValidator no Controller, Service, ou BackgroundJob.

6. Testabilidade e separação de responsabilidade

Facilita testes unitários das validações de forma isolada.

var validator = new UsuarioValidator();
var resultado = validator.Validate(usuario);
Assert.False(resultado.IsValid);
Enter fullscreen mode Exit fullscreen mode

Exemplo Prático

Estrutura do projeto

Projeto
├── Controllers
   └── UsuarioController.cs
├── Models
   └── Usuario.cs
├── Validators
   └── UsuarioValidator.cs
└── Program.cs
Enter fullscreen mode Exit fullscreen mode

1. Modelo

Primeiro, vamos definir um modelo simples chamado Cliente.

public class Cliente
{
    public string Nome { get; set; }
    public string Email { get; set; }
    public int Idade { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

2. Validador

O segundo arquivo será o nosso próprio validador.

Ele estende a classe AbstractValidator<T>, onde T é o tipo que você deseja validar.

Ao herdar o AbstractValidator<T>, o NovoClienteValidator herda todas as funcionalidades da classe base, permitindo definir regras de validação específicas para o modelo Cliente

using FluentValidation;

public class NovoClienteValidator : AbstractValidator<Cliente>
{
    public NovoClienteValidator()
    {
        RuleFor(cliente => cliente.Nome)
            .NotEmpty().WithMessage("O nome é obrigatório.")
            .Length(2, 50).WithMessage("O nome deve ter entre 2 e 50 caracteres.");

        RuleFor(cliente => cliente.Email)
            .NotEmpty().WithMessage("O email é obrigatório.")
            .EmailAddress().WithMessage("O email fornecido não é válido.");

        RuleFor(cliente => cliente.Idade)
            .InclusiveBetween(18, 100).WithMessage("A idade deve estar entre 18 e 100 anos.");
    }
}

Enter fullscreen mode Exit fullscreen mode

3. Controller

Agora, vamos criar um controlador que usa o modelo Cliente e valida as solicitações de entrada.

using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/[controller]")]
public class ClientesController : ControllerBase
{
    [HttpPost]
    public IActionResult CriarCliente([FromBody] Cliente cliente)
    {
        // A validação será feita automaticamente pelo FluentValidation
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        // Lógica para adicionar o cliente no banco de dados (omita por simplicidade)
        return Ok("Cliente criado com sucesso!");
    }
}

Enter fullscreen mode Exit fullscreen mode

4. Configuração de Startup

Existem duas abordagem para configurar o Fluent API.

A. Configuração simples feita diretamente no arquivo de inicialização (Startup), que funciona bem para projetos menores.

B. Abordagem mais robusta e é usada em projetos maiores e mais complexos, oferecendo mais flexibilidade.

A. No Arquivo Startup

using AL.Manager.Validator.Conta;
using AL.WebApi.Configuration;
using CL.WebApi.Configuration;
using FluentValidation.AspNetCore;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddValidatorsFromAssemblyContaining<Program>(); // Vai registrar todos os validadores do seu projeto

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.Services.AddDataBaseConfiguration(builder.Configuration);

builder.Services.AddDependencyInjectionConfiguration();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseDatabaseConfiguration();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Enter fullscreen mode Exit fullscreen mode

B. Arquivo de Configuração

A segunda abordagem é criar em um arquivo de configuração. Na mesma raiz do projeto: Configuration/FluentValidationConfig

using  AL.Manager.Validator.Conta;
using FluentValidation.AspNetCore;
using System.Globalization;

namespace CL.WebApi.Configuration;

public static class FluentValidationConfig
{
    public static void AddFluentValidationConfiguration(this IServiceCollection services)
    {
                services.AddValidatorsFromAssemblyContaining<Program>(); // Vai registrar todos os validadores do seu projeto   

    }
}
Enter fullscreen mode Exit fullscreen mode

Agora é necessário chamar o nosso método criado anteriormente no startup do programa.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddFluentValidationConfiguration();

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.Services.AddDataBaseConfiguration(builder.Configuration);

builder.Services.AddDependencyInjectionConfiguration();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseDatabaseConfiguration();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Enter fullscreen mode Exit fullscreen mode

Top comments (0)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.