Fluent Validation in an ASP.NET Core Web API

Fluent Validation allows you to separate validation rules from your model and helps you structure the rules so that they are nice and readable. The rules are also super easy to test.

Some existing code

Let’s say we have started to build a web api to add new customers:


Our NewCustomer model is:


We also have an action filter which will handle validation on the models and return a 400 if they are invalid:


Startup.ConfigureServices looks like this to wire everything up:

So, let’s say we want to make CustomerName a required field in the POST method on the newCustomer model. We could use a standard data annotation:

However, we’re not going to do this. Instead, we’re going to use Fluent Validation to keep our validation logic separate from the model and go on to add more complex rules …

Getting started with Fluent Validation

First we need to bring this library in via nuget. The packge that needs adding is FluentValidation.AspNetCore.
We can then wire this up in Startup.ConfigureServices by adding AddFluentValidation() to AddMVC():


Now let’s add a validation to ensure CustomerName is populated on the newCustomer model using the power of Fluent Validation:


As you can see, this rule is nice and readable. This class is also picked up automatically with the work we have already done in Startup.ConfigureServices.

To check this is working, let’s try to POST a customer without a surname to our API – we should get a 400 with a nice error message in the response body:

Adding some more simple rules

There’s quite a few built in rules in Fluent Validation, including a rule to validate an email address. So, let’s use this:


We can also add multiple rules on a field. Let’s add minimum and maximum length rules on CustomerName:


Again, this is nice and readable.

Conditional rules

So far the rules have been nice and simple. Let’s deal with more complex rules, starting with conditional rules. For example, a rule to ensure the first name is populated if the customer type is a person:


As well as implementing this rule, we’ve also made CustomerType a required field.
What about controlling the error message? At the moment we just get:
‘First Name’ should not be empty.
Let’s change the message to:
‘First Name’ must be filled in for customers of type ‘Person’.
All we need to do is chain a WithMessage() on the rule:

Custom rules

Lastly, we’ll look at a custom rule to ensure the company type is “Person” or “Company”. The rule will be called ValidCustomerType and invoked like below:


We define the rule like so:


We also need to define this validator in a static class (along with any other custom rules):

Unit tests

I introduced this post by saying how simple these rules are to test. The following tests are a few we could write against CreateCustomerValidator using Fluent Validation helpers ShouldHaveValidationErrorFor and ShouldNotHaveValidationErrorFor:

Conclusion

As you can see Fluent Validation is a great library for creating validation rules outside your model. I’d encourage you to check out the project on Github.

Connect with me:RSSGitHubTwitterLinkedIn

Share this:Share on RedditTweet about this on TwitterShare on LinkedInShare on Google+

Leave a Reply

Your email address will not be published. Required fields are marked *