Skip to content

Composition of object validators

rsamec edited this page Jul 24, 2014 · 1 revision

Compositio of object validators

You will learn how to create custom validator for your own object with nested structure. You will learn how to composite more custom validators to one main validator.

Let`s image your object has this structure.

interface IData{
    Person1:IPerson
    Person2:IPerson
}
interface IPerson{
    Checked:boolean;
    FirstName:string;
    LastName:string;
    Contact:IContact;
}
interface IContact{
    Email:string;
    Mobile:IPhone;
    FixedLine:IPhone;
}
interface IPhone{
    CountryCode:string
    Number:string
}

To create validator you have to

  • create AbstractValidator IData object
  • create AbstractValidator IPerson object
  • create AbstractValidator IContact object
  • create AbstractValidator IPhone object
  • compose these validators to match the object structure with ValidatorFor property
        var required = new Validation.RequiredValidator();

           var createMainValidator = function(){
               var validator = new Validation.AbstractValidator<IData>();

               var personValidator = createPersonValidator();
               validator.ValidatorFor("Person1",personValidator);
               validator.ValidatorFor("Person2",personValidator);

               return validator;
           }
           var createPersonValidator = function() {

               var maxLength = new Validation.MaxLengthValidator(15);

               var validator = new Validation.AbstractValidator<IPerson>();
               validator.RuleFor("FirstName", required);
               validator.RuleFor("FirstName", maxLength);

               validator.RuleFor("LastName", required);
               validator.RuleFor("LastName", maxLength);

               var contactValidator = createContactValidator();
               validator.ValidatorFor("Contact",contactValidator);

               return validator;
           }

           var createContactValidator = function() {

               var validator = new Validation.AbstractValidator<IContact>();
               validator.RuleFor("Email", required);
               validator.RuleFor("Email", new Validation.MaxLengthValidator(100));
               validator.RuleFor("Email", new Validation.EmailValidator());

               var phoneValidator = createPhoneValidator();
               validator.ValidatorFor("Mobile", phoneValidator);
               validator.ValidatorFor("FixedLine", phoneValidator);

               return validator;
           }

           var createPhoneValidator = function() {

               var validator = new Validation.AbstractValidator<IPhone>();
               validator.RuleFor("CountryCode", required);
               validator.RuleFor("CountryCode", new Validation.MaxLengthValidator(3));

               validator.RuleFor("Number", required);
               validator.RuleFor("Number", new Validation.MaxLengthValidator(9));

               var optionsFce = function() {
                   var deferral = Q.defer();
                   setTimeout(function () {
                       deferral.resolve([
                           { "value": 420, "text": "CZE" },
                           { "value": 22, "text": "USA" },
                           { "value": 33, "text": "GER" },
                           { "value": 444, "text": "FRA" }
                       ]);
                   }, 500);
                   return deferral.promise;
               };

               var param = new Validation.ParamValidator();
               param.ParamId = "countryCodes";
               param.Options = optionsFce();

               validator.RuleFor("CountryCode", param);

               return validator;
           }

           var mainValidator = createMainValidator();

Use validator to get validation results

        this.MainValidator = mainValidator.CreateRule("Person");

        //first call sync validation
        var result = this.MainValidator.Validate(this.Data);

        //verify
        if (result.HasErrors){
            console.log(result.ErrorMessage);
        }

        //second - call async validation
        var promiseResult = this.MainValidator.ValidateAsync(this.Data);

        //verify
        promiseResult.then(function (resultAsync) {
            if (resultAsync.HasErrors){
                console.log(resultAsync.ErrorMessage);
            }
        }

Test - custom object validator with composition - nested structures

describe('nested validation rules', function () {

    beforeEach(function(){

        //setup
        var getData = function () {
            var contact = {
                Email:'[email protected]',
                Mobile:{
                    CountryCode:'CZE',
                    Number:'736483690'
                },
                FixedLine:{
                    CountryCode:'USA',
                    Number:'736483690'
                }
            };
            return{
                Person1: {
                    Checked:true,
                    FirstName: "John",
                    LastName: "Smith",
                    Contact: contact
                },
                Person2: {
                    Checked:true,
                    FirstName: "Adam",
                    LastName: "Novak",
                    Contact: contact
                }
            }
        };

        this.Data = getData();
        this.MainValidator =  mainValidator.CreateRule("Main");

    });

    it('fill correct data - no errors', function (done) {

        //when

        //excercise
        var result = this.MainValidator.Validate(this.Data);
        var promiseResult = this.MainValidator.ValidateAsync(this.Data);

        //verify
        var selfValidator = this.MainValidator;
        promiseResult.then(function (response) {

            selfValidator.ValidationResult.LogErrors();

            //verify
            expect(selfValidator.ValidationResult.HasErrors).to.equal(false);

            done();

        }).done(null,done);
    });


    it('fill incorrect data - some errors', function (done) {

        //when
        //nested property error
        this.Data.Person1.Contact.Email = "";

        //async nested property error
        this.Data.Person1.Contact.Mobile.CountryCode = "BLA";

        //excercise
        var result = this.MainValidator.Validate(this.Data);
        var promiseResult = this.MainValidator.ValidateAsync(this.Data);

        //verify
        var selfValidator = this.MainValidator;
        promiseResult.then(function (response) {

            selfValidator.ValidationResult.LogErrors();

            //verify
            expect(selfValidator.ValidationResult.HasErrors).to.equal(true);

            done();

        }).done(null,done);
    });