Azure Functions with Fluent Validation

2022, Jul 12

Apis can be easily implemented with the power of Azure Functions, and when you need to validate models, Fluent Validation comes in handy, helping us to validate models elegantly. Fluent Validation is a validation library available as a NuGet package, that can be easily implemented by developers. It uses a fluent API that leverages lambda expressions to validate rules.

Check my previous article if you want more details about the Fluent Validation in .NET 6. Otherwise, stick to this article as I'm going straight to coding.

Creating the project

On Visual Studio 2022 create a new Functions project. Make sure you get the settings right.


If you are like me and like Dependency Injection, check the PlayGoKids repository for this example.

You are going to notice that I have deleted the out-of-the-box Functions1.cs, added Startup.cs and created other classes for Products. The solution looks like this:


The NuGet packages FluentValidation and FluentValidation.AspNetCore are assigned to the project.

On Startup.cs the FluentValidation library is hooked up to Service Collection. This is possible because of the NuGet package FluentValidation.AspNetCore.


[assembly: FunctionsStartup(typeof(Startup))]
namespace FluentValidationFunction
    public class Startup : FunctionsStartup
        public override void Configure(IFunctionsHostBuilder builder)
            builder.Services.AddFluentValidation(conf =>


The models created are ProductViewModel.cs and its validator ProductViewModelValidator.cs, that contains the Fluent Validation.


public class ProductViewModel
    public string Name { get; set; }
    public string Sku { get; set; }
    public int Quantity { get; set; }
    public double Price { get; set; }


public class ProductViewModelValidator : AbstractValidator<ProductViewModel>
    public ProductViewModelValidator()
        RuleFor(model => model.Name).NotNull().NotEmpty().WithMessage("Please specify a name");
        RuleFor(model => model.Sku).NotNull().NotEmpty().Length(3, 10);
        RuleFor(model => model.Quantity).GreaterThanOrEqualTo(0);
        RuleFor(model => model.Price).NotEqual(0).When(model => model.Quantity > 0)
            .WithMessage("Please specify a price");

The rules are simple to understand, for more details please check my previous article.

The Open Api

The solution has a POST endpoint (with OpenApi attributes) that allows users to submit a Product. The Fluent Validation is executed on the request, and in case it fails, it returns a BadRequest.


public class ProductApi
    private readonly ILogger<ProductApi> _logger;
    private readonly IValidator<ProductViewModel> _validator;

    public ProductApi(ILogger<ProductApi> log, IValidator<ProductViewModel> validator)
        _logger = log;
        _validator = validator;

    [OpenApiOperation(operationId: nameof(AddProductAsync), tags: new[] {"name"})]
    [OpenApiSecurity("function_key", SecuritySchemeType.ApiKey, Name = "code", In = OpenApiSecurityLocationType.Query)]
    [OpenApiRequestBody(contentType: "application/json", bodyType: typeof(ProductViewModel), Description = nameof(ProductViewModel), Required = true)]
    [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json ", bodyType: typeof(string), Description = "The OK response")]
    public async Task<IActionResult> AddProductAsync(
        [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]
        HttpRequest req)
        _logger.LogInformation($"{nameof(AddProductAsync)} has been triggered");

        // Deserialize object
        var productJson = await req.ReadAsStringAsync();
        var productViewModel = JsonConvert.DeserializeObject<ProductViewModel>(productJson);

        // Validating
        var productValidationResult = await _validator.ValidateAsync(productViewModel);

        if (!productValidationResult.IsValid)
            return new BadRequestObjectResult(productValidationResult.Errors.Select(e => new
                e.ErrorCode, e.PropertyName, e.ErrorMessage

        // TODO: Perform add product

        return new OkResult();

Running the solution

Run the solution and open Swagger to perform the POST:


That was the port number set for this function.


When submitting a payload that fails the rules, the validation is displayed.

curl -X POST "http://localhost:7270/api/AddProductAsync" -H  "accept: application/json " -H  "Content-Type: application/json" -d "{  \"name\": \"Marmite\",  \"sku\": \"MARMITE\",  \"quantity\": 2,  \"price\": 0}"

Because Price was not provided when Quantity is greater than zero, the error message is displayed:


The model is validated and the error message is displayed, as expected.