Validation is an important part of APIs. When using a clean architecture, or another modern application design pattern, most often we leverage CQRS’ commands for actions like POST, PUT, etc. These commands have side effects. While those without side effects like GET requests are implemented in queries. Commands most often need some sort of asynchronous validation, for example, detecting if an entity exists in the database before creating another related entity, etc. It is a best practice to separate validation from the implementation logic. This article will show you how to separate validation logic from the application logic in your commands. With MediatR, this is easy we will do so, there by, respecting the SRP (Single Responsibility Principle).

The Problem

When making a POST request for example, you can use dotnet’s data annotations to validate the properties of the model received by the request before it even reaches your controller’s action logic. For this type of validation, Fluent Validation could also be used (NOTE: With some configuration, Fluent Validation could be used for async validation, but in this article, we’re focusing on validation at the command level). This is great, but what if, after the model is declared valid, your command is called, and you still need some additional asynchronous validation logic before running the application logic inside your command? The easiest thing to do is to mix the validation logic inside your command’s application logic. Here is an example below. Where I call a validation logic inside my “SaveForecast.Command” handler, to check if there is not already an existing similar forecast before saving a new forecast. Here is a link to the source code.

The Problem with the code above is that it mixes validation logic with application logic. For small functionalities, it might be ok, but it will turn out to be very messy when the code grows. What we want is to separate the validation logic, and let the application logic be alone in the command thereby, respecting SRP. This can be done easily and in a flexible manner with MediatR’s pipeline behaviors.

If you find this article useful, please follow me on Twitter,  Github, Linkedin, or like my Facebook page to stay updated.
Follow me on social media and stay updated

Separating the Validation Logic

Our next step is to separate the validation logic and make it flexible in such a way that it will be easy to separate validation for each commands in our system.

NOTE: Here is an interesting article I wrote about migrating old authentication to Asp.net core identity with openid connect

1- Create a validator interface. We will create several validators that will contain the validation logic for each command.

2- We then create a specific validator that will contain the validation logic for our SaveForecast command handler.

3- Using the decorator pattern, MediatR permits us to run code logic before the execution of commands. We will be able to run the validation logic before command execution, with the “IPipelineBehavior”. The decorator pattern is a very famous pattern you must have used in the past even unknowingly. It is the patterned leveraged by ASP.net core middleware. We create a generic validation pipeline behavior for our commands.

4- We register the validation behavior so that it is called to perform validation logic for each commands automagically.

NOTE: if you want every request to be validated, use the following:

NOTE: if you want every request to be validated, use the following:

5- We register our validator in the IOC container so that it is called by the pipeline behavior appropriately.

6- Now we have a clean Command, with clean validation done seamlessly without the need for the validation logic to exist in our command’s handler.

Conclusion

The validation above relies on exceptions thrown to break the execution flow, instead of returning validation errors only. This is my way of doing things, you could customize it if you want. I’d love to know your opinion about this approach in the comments section. I hope this post helps.

References

https://codeopinion.com/validating-commands/

https://code-maze.com/cqrs-mediatr-fluentvalidation/

Follow me on social media and stay updated

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.