-
Notifications
You must be signed in to change notification settings - Fork 13
Validate input and data
| Main > Using Liquid for building your application > Validate input and data |
|---|
Liquid helps developers to validate persisted data and input parameters packing FluentValidation functionality inside data classes derived from LightModel and LightViewModel (as well as its subclasses LightMessage, LightCommand and LightQuery).
Additionally, a programmatically way of validation is also provided so as to cover all possible scenarios.
| Take a look at related key concepts of Liquid |
|---|
| Business Logic Separation |
| Business Error Handling |
#Validate input (directly or with ViewModels) Input parameters received from a microservice must be validated upfront so any invalid data is not passed forward to insider (business) classes.
It is responsibility of API classes to enforce external communication correctness. See how it can be done in the sample code bellow:
GoalController.cs
-------------------------------------------------------------------------------
[HttpPost("/{departmentId}")]
public IActionResult Update(string departmentId, [FromBody] GoalViewModel goal)
{
//The way to validate input directly in the controller is like bellow
if (string.IsNullOrEmpty(departmentId))
AddInputValidationErrorCode("DEPARTMENT_ID_MUST_NOT_BE_EMPTY");
//This validates the instance of ViewModel class and its eventual nested ViewModel members
ValidateInput(goal);
//Liquid automatically returns Bad Request code in case of input errors
//before factoring any LightService, LightCommand or LightQuery subclass
var response = Factory<GoalService>().Update(departmentId, goal);
return Result(response);
}
GoalWorker.cs
-------------------------------------------------------------------------------
[MessageBus("PLANNING")]
public class GoalWorker : LightWorker
{
[Queue("updated_goals",1)]
public void Update(GoalMessage msg)
{
//Validates the instance of Message class and its eventual nested ViewModel members
ValidateInput(msg);
//Liquid automatically rejects the message in case of input errors
//before factoring any LightService, LightCommand or LightQuery subclass
var response = Factory<GoalService>().Update(msg.departmentId, msg.MapTo<GoalViewModel>());
//Terminates the message according to domain response
Terminate(response.Result);
}
}
GoalViewModel.cs // GoalMessage.cs would be equivalent
-------------------------------------------------------------------------------
public class GoalViewModel : LightViewModel<GoalViewModel>
{
public string goalId;
public double value;
public DateTime date;
public override void Validate()
{
//Validating ViewModels in a declarative, Fluent-like syntax
RuleFor(g => g.goalId).NotEmpty().WithErrorCode("GOAL_ID_CANNOT_BE_EMPTY");
RuleFor(g => g.date).LessThan(DateTime.Today.AddMonths(1)).WithErrorCode("GOAL_DATE_MUST_BE_ONE_MONTH_MININUM_IN_THE_FUTURE");
//Imperative validation can also be done by standard language primitives
if (value <= 0)
AddInputValidationErrorCode("GOAL_VALUE_MUST_BE_POSITIVE");
}
}
| See how this is done in Liquid Hotel360 sample application. |
|---|
#Validate data schema (with Models) The same approach is used for validating model schema before any write operations by the repository. If an invalid condition is found then an exception is raised considering it a fatal internal inconsistency of the microservice.
public class GoalModel : LightModel<GoalViewModel>
{
public string goalId;
public string departmentlId;
public double value;
public DateTime date;
//There could be nested LightModel attribuites that would be automatically validated as well
public ThresholdModel threshold;
public override void Validate()
{
//Validating ViewModels in a declarative, Fluent-like syntax
RuleFor(g => g.goalId).NotEmpty().WithErrorCode("GOAL_ID_CANNOT_BE_EMPTY");
RuleFor(g => g.date).LessThan(DateTime.Today.AddMonths(1)).WithErrorCode("GOAL_DATE_MUST_BE_ONE_MONTH_MININUM_IN_THE_FUTURE");
//Imperative validation can also be done by standard language primitives
if (value <= 0)
AddInputValidationErrorCode("GOAL_VALUE_MUST_BE_POSITIVE");
if (String.IsNullOrWhiteSpace(departmentlId))
AddInputValidationErrorCode("DEPARTMENT_ID_CANNOT_BE_EMPTY");
}
}
public class ThresholdModel : LightModel<ThresholdModel >
{
...
public override void Validate()
{
...
}
}
| See how this is done in Liquid Hotel360 sample application. |
|---|