Skip to content
This repository was archived by the owner on Aug 18, 2021. It is now read-only.

Validate input and data

Gustavo Denis edited this page Oct 31, 2019 · 1 revision
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.

Clone this wiki locally