ASP.NET Core - FluentValidation em minimal APIs
Hoje vamos recordar como usar a FluentValidation com minimal APIs na ASP.NET Core 7. |
Atualmente não existe suporte para validar o modelo nas minimal APIs (como temos na ASP.NET Core). Portanto, precisamos escrever um código personalizado para validar os modelos em nossa aplicação.
Uma alternativa é usar os recursos da FluentValidation e é isso que veremos a seguir.
Criando a minimal API
Vamos criar um projeto Web API no VS 2022 chamado ApiValidation selecionando as opções a seguir:
Para utilizar a funcionalidade do FluentValidation, precisamos instalar a biblioteca FluentValidation do gerenciador de pacotes NuGet.
Podemos fazer isso na opção Tools ->..->Manage Nuget Packages for Solution e na guia Browse selecionar o pacote FluentValidation.AspNetCore :
Vamos cria no projeto a pasta Entities e criar nesta pasta a classe Produto que representa nosso modelo de domínio :
public
class
Produto { public int Id { get; set; } public string? Codigo { get; set; } public int Quantidade { get; set; } public decimal Preco {get; set; } } |
Como nosso objetivo é focar na validação vamos criar um serviço fake apenas para usarmos no endpoint da API . Para isso crie a pasta Services e nesta pasta crie a interface IProdutoService e a classe ProdutoService:
1- IProdutoService
public
interface
IProdutoService { void IncluirProduto(Produto produto); } |
2- ProdutoService
public
class
ProdutoService
:IProdutoService { public void IncluirProduto(Produto produto) { //lógica para incluir o produto no banco de dados } } |
Vamos criar uma pasta chamada Validations onde iremos definir as regras de validação usando a FluentValidation. Nesta pasta crie a classe ProdutoValidator conforme o código abaixo:
using
ApiValidation.Entities; using FluentValidation; namespace ApiValidation.Validations;public class ProdutoValidator : AbstractValidator<Produto>{ public ProdutoValidator() { RuleFor(x => x.Id).NotNull(); RuleFor(x => x.Codigo).Length(5); RuleFor(x => x.Quantidade).NotNull().InclusiveBetween(1,99); RuleFor(x => x.Preco).NotNull().InclusiveBetween(10.00m,50.00m); } } |
A classe ProdutoValidator herda da classe AbstractValidator, que é a classe base da biblioteca FluentValidation para criação de validadores. O tipo genérico <Produto> indica que este validador é específico para objetos do tipo Produto.
No construtor da classe ProdutoValidator, são definidas as regras de validação para cada propriedade do objeto Produto:
Essas regras de validação serão aplicadas quando um objeto Produto for validado através do método Validate da biblioteca FluentValidation.
Agora vamos registrar o validator e o serviço na classe Program:
... builder.Services.AddScoped<IValidator<Produto>, ProdutoValidator>();
builder.Services.AddScoped<IProdutoService, ProdutoService>(); |
Com tudo pronto podemos criar um endpoint na classe Program:
app.MapPost("/produto", async (IValidator<Produto> validator, IProdutoService service, Produto produto) =>
{
var validationResult = await validator.ValidateAsync(produto);
if (!validationResult.IsValid)
{
return Results.ValidationProblem(validationResult.ToDictionary());
}
service.IncluirProduto(produto);
return Results.Created($"/{produto.Id}", produto);
});
app.Run();
|
Este código define um endpoint HTTP POST que recebe um objeto Produto e o valida usando a biblioteca FluentValidation antes de incluí-lo no serviço de produtos.
Na linha
app.MapPost("/produto", async (IValidator<Produto> validator, IProdutoService service, Produto produto) =>{}
é definido um endpoint HTTP POST na rota "/produto". Este endpoint recebe três parâmetros:
Dentro do método anônimo, primeiro é realizada a validação do objeto Produto usando o método ValidateAsync do validador injetado. O resultado da validação é armazenado na variável validationResult.
Em seguida, é verificado se a validação falhou usando a propriedade IsValid do validationResult. Caso a validação tenha falhado, é retornado um objeto de problema de validação HTTP usando o método Results.ValidationProblem, que é uma extensão da classe HttpResponse. Esse objeto é construído a partir do dicionário de erros retornado pelo método ToDictionary do validationResult.
Se a validação for bem sucedida, o método IncluirProduto do serviço de produtos é chamado para incluir o objeto Produto no banco de dados. Finalmente, uma resposta HTTP 201 (Created) é retornada com o objeto Produto incluído no corpo da resposta, e o cabeçalho Location contendo o ID do produto recém-criado.
Executando o projeto e inserindo alguns dados para testar a validação obtemos o seguinte resultado:
Ao clicar em Execute obtemos o seguinte:
Este é um exemplo básico que mostra o uso da FluentValidation nas minimal APIs.
Você também pode aplicar validadores personalizados usando a interface IValidatableObject. Essa interface contém um método chamado Validate, que você mesmo precisaria implementar. Para fazer isso, você criaria uma classe de modelo que implementasse essa interface e o método Validate.
Pegue o projeto aqui : ApiValidation.zip...
"Louvai ao SENHOR. Louvai ao SENHOR desde os céus, louvai-o nas alturas.
Louvai-o, todos os seus anjos; louvai-o, todos os seus exércitos.
Louvai-o,
sol e lua; louvai-o, todas as estrelas luzentes."
Salmos 148:1-3
Referências:
NET - Unit of Work - Padrão Unidade de ...