# Asp.Net Core Minimal APIs with FluentValidation

In this post we will use how the model can be validated in minimal APIs and how FluentValidation can help us in this process.

# What is Asp.Net Core Minimal APIs

Minimal APIs are a new feature in .NET 6 that helps the developers to create APIs with minimal dependencies in ASP.NET Core. Minimal APIs simplify API development through the use of a more compact code syntax.

# Validation

In Web API development it is very important to validate the request before processing it. A lot of validations can be done and one of these validations is the Model.

Model Validation is a technique used to validate the model state before continuing with the request, checking if the data meets all the defined rules.

Minimal APIs do not come with any built-in support for validation, like [Data Annotations](https://learn.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-5.0#validation-attributes), however we are free to create our own validation or use libraries like [MinimalValidation](https://github.com/DamianEdwards/MiniValidation) and [FluentValidation](https://docs.fluentvalidation.net/en/latest/).

## FluentValidation

FluentValidation is a .NET library for building strongly-typed validation rules. It is an open source and uses a fluent interface and lambda expressions for creating validation rules.

FluentValidation has several built-in validators. The error message for each validator can contain special placeholders that will be filled in when the error message is constructed.

Some examples of validators:

```csharp
RuleFor(customer => customer.Surname).NotNull();

RuleFor(customer => customer.Surname).NotEmpty();

//Not equal to a particular value
RuleFor(customer => customer.Surname).NotEqual("Foo");

//Equal to a particular value
RuleFor(customer => customer.Surname).Equal("Foo");

//Equal to another property
RuleFor(customer => customer.Password).Equal(customer => customer.PasswordConfirmation);

//must be between 1 and 250 chars (inclusive)
RuleFor(customer => customer.Surname).Length(1, 250); 

//must be 10 chars or more
RuleFor(customer => customer.Surname).MinimumLength(10); 

//Less than a particular value
RuleFor(customer => customer.CreditLimit).LessThan(100);

//Less than another property
RuleFor(customer => customer.CreditLimit).LessThan(customer => customer.MaxCreditLimit);
```

The complete list of validators can be found in [here](https://docs.fluentvalidation.net/en/latest/built-in-validators.html).

# Let's code

First we will create our ASP.NET Core Web API. For Minimal API's we need to uncheck the option *Use controllers*.

![MinimalAPIs.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1667914917370/v62mUo-Z3.png align="left")

The default code shows an implementation of one endpoint, *weatherforecast*, in the *Program.cs* file but we will create different endpoints using a different model.

### Model

This model will be used to create the context service, validator and the endpoints.

```csharp
public class Todo
{
    public int Id { get; set; }
    public string Name { get; set; }
    public bool IsComplete { get; set; }
    public DateTimeOffset? CompletedTimestamp { get; set; }
}
```

### Context

To persist the data a DbContext implementation will be created and for this the nuget package [Microsoft.EntityFrameworkCore](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore) needs to be installed.

```csharp
public class TodoDb : DbContext
{
    public TodoDb(DbContextOptions<TodoDb> options)
        : base(options) { }

    public DbSet<Todo> Todos => Set<Todo>();
}
```

### Validator

To create the validator is necessary to install the nuget package [FluentValidation.AspNetCore](https://www.nuget.org/packages/FluentValidation.AspNetCore/11.2.2).

With this library is possible to define the rules for each property of the class used in the request of the endpoint, can be the model or a [DTO](https://en.wikipedia.org/wiki/Data_transfer_object), for this post it will be created for the model.

```csharp
public class TodoValidator : AbstractValidator<Todo>
{
    public TodoValidator()
    {
        RuleFor(m => m.Name).NotEmpty().WithMessage("The field 'Name' is required.");
        RuleFor(m => m.IsComplete).NotEmpty();
        RuleFor(m => m.CompletedTimestamp).LessThanOrEqualTo(DateTime.Now);
    }
}
```

The validator has rules for three properties: Name, IsComplete and CompletedTimestamp. Name and IsComplete are required and the Name has a custom message. For the property CompletedTimestamp should be less than or equal to the current date.

### Settings

Before using the validator and the dbContext it is necessary to add them in the services of the services collection of the API.

```csharp
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddScoped<IValidator<Todo>, TodoValidator>();
```

### Endpoints

The validator and the dbContext will be injected to the endpoint and the model can be validated before being persisted.

```csharp
app.MapPost("/todoitems", async (IValidator<Todo> validator, Todo todo, TodoDb db) =>
{
    ValidationResult validationResult = await validator.ValidateAsync(todo);

    if (!validationResult.IsValid)
    {
        return Results.ValidationProblem(validationResult.ToDictionary());
    }

    db.Todos.Add(todo);
    await db.SaveChangesAsync();

    return Results.Created($"/todoitems/{todo.Id}", todo);
});
```

### Results

The property CompletedTimestamp is not required so it will be validated only when it has a value.

![Validation00.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1668002307740/Geqfs9mz1.png align="left")

![validation001.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1668002505113/bVwn5N54i.png align="left")

The properties Name and IsComplete are required, so they need to have value to continue. For the property Name the message was customized.

![Validation01.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1668002748635/U4TR9JyHx.png align="left")

# Wrapping Up

You can find the full code on my [GitHub](https://github.com/jhonatanfernando/api-fluent-validator).
