Skip to main content

Validation is performed using Fluent Validation or Validot. See benchmarks for performance differences.

Fluent Validation

Add a static function to your request object that takes a parameter of type AbstractValidator<RequestType> any other parameters will be injected from the dependency container.

For performance reasons the validator is a singleton.

public record WeatherForecastRequest([FromRoute]string City, [FromQuery]int Days = 5)
{
public static void AddValidationRules(AbstractValidator<WeatherForecastRequest> validator)
{
validator.RuleFor(r => r.Days).InclusiveBetween(1, 5);
}
}

Voyager will automatically add NotNull rules for properties that are not nullable in the request object.

Scoped services

If you need to use scoped services during your validation you can inject the IHttpContextAccessor and resolve services from that.

public record WeatherForecastRequest([FromRoute]string City, [FromQuery]int Days = 5)
{
public static void AddValidations(AbstractValidator<WeatherForecastRequest> validator, IHttpContextAccessor contextAccessor)
{
validator.RuleFor(r => r.Days).Must(req => {
var myService = context.HttpContext.RequestServices.GetRequiredService<IMyService>();
// perform validation
});
}
}

Validot

To use Validot add a static CreateValidator method on your request object that returns an IValidator

public static Validot.IValidator<ValidotRequest> CreateValidator()
{
Specification<ValidotRequest> spec = _ => _
.Member(m => m.FirstName, m => m.NotEmpty().WithMessage("name needed"))
.Member(m => m.LastName, m => m.NotEmpty().WithMessage("last needed"))
.Member(m => m.Age, m => m.GreaterThan(10).WithMessage("too young"))
.Member(m => m.PhoneNumbers, m => m.NotEmptyCollection().WithMessage("phone needed"))
.Member(m => m.UserId, m => m.GreaterThan(5).WithMessage("id must be greater than 5"));
return Validator.Factory.Create(spec);
}

Errors

By default Voyager will return a 400 BadRequest if a validation rule fails. It uses the Results.ValidationProblem method and includes all of the validation errors.

If you want to handle the errors yourself or perform some other custom error handling, just add a ValidationResult (or IValidationResult for Validot) parameter to your endpoint method.

[VoyagerEndpoint("weatherForecast/{city}")]
public class WeatherForecastEndpoint
{
public WeatherForecastResponse Get(WeatherForecastRequest request, ValidationResult validationResults)
{
if(validationResults.IsValid)
{
}
}
}