Demo Angular 6 CLI app using the framework library
| Rules | Description |
|---|---|
| If | Used for program flow. The then part is only evaluated if the if part is true. |
| ForEach | Used to iterate and apply validations to an array. |
| ForStringProperty | Used to stack multiple validations against a single String property. |
| ForDateProperty | Used to stack multiple validations against a single Date property. |
| ForNumberProperty | Used to stack multiple validations against a single Number property. |
| For (deprecated) | Used to stack multiple validations against a single property. |
| ForType | Used to chain validation rules for a type against a single property. |
| Required | Used to test if a property is true to a conditon. |
| NotNull | Used to test if a property is not null. |
| IsNull | Used to test if a property is null. |
| ToResult | Returns the validation result. |
| String Rules | Description |
|---|---|
| NotEmpty | Used to test if a string is not empty. |
| IsEmpty | Used to test if a string is empty. |
| Length | Used to test if a string length is between specified lengths. |
| Matches | Used to test if a string matches a regular expression. |
| NotMatches | Used to test if a string does not match a regular expression. |
| Used to test if a string is a valid email address. | |
| IsCreditCard | Used to test if a string is a valid credit card number. |
| IsLowercase | Used to test if a string is lower case. |
| IsUppercase | Used to test if a string is upper case. |
| IsMixedcase | Used to test if a string is mixed case. |
| IsNumeric | Used to test if a string is numeric. |
| IsAlpha | Used to test if a string is alpha. |
| IsAlphaNumeric | Used to test if a string is alpha numeric. |
| IsGuid | Used to test if a string is guid/uuid. |
| IsBase64 | Used to test if a string is base64. |
| IsUrl | Used to test if a string is an url. |
| IsCountryCode | Used to test if a string is a 2 letter country code. |
| Contains | Used to test if a sub string is contained in the string. |
| Date Rules | Description |
|---|---|
| IsDateOn | Used to test if a date is on the specified date. |
| IsDateAfter | Used to test if a date is after the specified date. |
| IsDateOnOrAfter | Used to test if a date is on or after the specified date. |
| IsDateBefore | Used to test if a date is before the specified date. |
| IsDateOnOrBefore | Used to test if a date is on or before the specified date. |
| IsDateBetween | Used to test if a date is between two specified dates. |
| IsDateLeapYear | Used to test if a date is in a leap year. |
| Number Rules | Description |
|---|---|
| IsNumberEqual | Used to test if a number is equal to a specified number. |
| IsNumberNotEqual | Used to test if a number is not equal to a specified number. |
| IsNumberLessThan | Used to test if a number is less than a specified number. |
| IsNumberLessThanOrEqual | Used to test if a number is less than or equal to a specified number. |
| IsNumberGreaterThan | Used to test if a number is greater than a specified number. |
| IsNumberGreaterThanOrEqual | Used to test if a number is greater than or equal to a specified number. |
| CreditCard | Used to test if a number is a valid credit card number. |
- These rules are used to lay the validation rules for any model.
- These rules can be chained in a fluent manner.
- These rules are available via IValidator<T> interface the framework provides.
Sample usage:
Models
class Employee {
Name: string;
Password: string;
PreviousPasswords: string[];
CreditCards: CreditCard[];
Super: Super;
Email: string;
}
class CreditCard {
Number: string;
Name: string;
ExpiryDate: Date;
}
class Super {
Name: string;
Code: string;
}Validation rules
/* Install npm package ts.validator.fluent and then import like below */
import { IValidator, Validator, ValidationResult } from 'ts.validator.fluent/dist'; let validateSuperRules = (validator: IValidator<Super>) : ValidationResult => {
return validator
.NotNull(m => m.Name, "Should not be null", "Super.Name.Null")
.NotNull(m => m.Code, "Should not be null", "Super.Code.Null")
.If(m => m.Name != null && m.Code != null, validator => validator
.NotEmpty(m => m.Name, "Should not be empty", "Super.Name.Empty")
.Matches(m => m.Code, "^[a-zA-Z]{2}\\d{4}$", "Should not be invalid", "Super.Code.Invalid")
.ToResult())
.ToResult();
}; let validateCreditCardRules = (validator: IValidator<CreditCard>) : ValidationResult => {
return validator
.NotNull(m => m.Name, "Should not be null", "CreditCard.Name.Null")
.NotNull(m => m.Number, "Should not be null", "CreditCard.Number.Null")
.NotNull(m => m.ExpiryDate, "Should not be null", "CreditCard.ExpiryDate.Null")
.If(m => m.Name != null && m.ExpiryDate != null, validator => validator
.NotEmpty(m => m.Name, "Should not be empty", "CreditCard.Name.Empty")
.IsCreditCard(m => m.Number, "Should not be invalid", "CreditCard.Number.Invalid")
.IsDateOnOrAfter(m => m.ExpiryDate, new Date(), "Should be on or after today's date", "CreditCard.ExpiryDate.Invalid")
.ToResult())
.ToResult();
}; let validateEmployeeRules = (validator: IValidator<Employee>) : ValidationResult => {
return validator
.NotEmpty(m => m.Name, "Should not be empty", "Employee.Name.Empty")
.NotNull(m => m.CreditCards, "Should not be null", "CreditCard.Null")
.NotNull(m => m.Super, "Should not be null", "Super.Null")
.NotEmpty(m => m.Email, "Should not be empty", "Employee.Email.Empty")
.If(m => m.Super != null, validator => validator.ForType(m => m.Super, validateSuperRules).ToResult())
.If(m => m.Email != '', validator =>
validator.Email(m => m.Email, "Should not be invalid", "Employee.Email.Invalid")
.ToResult())
.Required(m => m.CreditCards, (m, creditCards) => creditCards.length > 0, "Must have atleast 1 credit card", "Employee.CreditCards.Required")
.If(m => m.CreditCards != null && m.CreditCards.length > 0,
validator => validator
.ForEach(m => m.CreditCards, validateCreditCardRules)
.ToResult())
.If(m => m.Password != '', validator => validator
.ForStringProperty(m => m.Password, passwordValidator => passwordValidator
.Matches("(?=.*?[0-9])(?=.*?[a-z])(?=.*?[A-Z])", "Password strength is not valid", "Employee.Password.Strength")
.Required((m, pwd) => pwd.length > 3, "Password length should be greater than 3", "Employee.Password.Length")
.Required((m, pwd) => !m.PreviousPasswords.some(prevPwd => prevPwd == pwd), "Password is already used", "Employee.Password.AlreadyUsed")
.ToResult())
.ToResult())
.ToResult();
};Populate models
let model = new Employee();
model.Name = "John Doe";
model.Password = "sD4A3";
model.PreviousPasswords = new Array<string>()
model.PreviousPasswords.push("sD4A");
model.PreviousPasswords.push("sD4A1");
model.PreviousPasswords.push("sD4A2");
var expiryDate = new Date();
model.CreditCards = new Array<CreditCard>();
var masterCard = new CreditCard();
masterCard.Number = "5105105105105100";
masterCard.Name = "John Doe"
masterCard.ExpiryDate = expiryDate;
var amexCard = new CreditCard();
amexCard.Number = "371449635398431";
amexCard.Name = "John Doe"
amexCard.ExpiryDate = expiryDate;
model.CreditCards.push(masterCard);
model.CreditCards.push(amexCard);
model.Super = new Super();
model.Super.Name = "XYZ Super Fund";
model.Super.Code = "XY1234";
model.Email = "[email protected]";Synchronous validation
let validationResult = new Validator(model).Validate(validateEmployeeRules); Asynchronous validation
let validationResult = await new Validator(model).ValidateAsync(validateEmployeeRules);Validation result
//Check if the model is valid.
let isValid = validationResult.IsValid;
//Get all errors.
let allErrors = validationResult.Errors;
//Get error for a particular identifier
let employeeNameError = validationResult.Identifier("Employee.Name.Empty");
//Get all errors which start with some identifier string.
//Below code will return Employee.Password.Strength and Employee.Password.Length and
//Employee.Password.AlreadyUsed errors
let superCodeErrors = validationResult.IdentifierStartsWith("Employee.Password");- The models are Employee, Credit Card, Super.
- The Employee model has CreditCard and Super as the child models.
- The rules for Super, CreditCard and Employee validation are laid in the validateSuperRules, validateCreditCardRules and validateEmployeeRules functions, using the IValidator<T> interface the framework provides.
- The Super and CreditCard rules are chained and used in the Employee validation.
- The rules are the same for both Sync and Async.
- For Sync and Async validation, the Validate and ValidateAsync methods on the framework class Validator are used.
- The Employee object is passed to this class and goes through the validation rules laid.
- Each validation rule comprises of a property on which the validation will apply, a message for any error and an identifier string for the error.
- The identifier string is used to group messages together for a field.
- The framework provides an API called IdentifierStartsWith which fetches all the validation errors for a particular identifier starts with the text.
- Eg. "Employee.Password" will fetch all errors whose identifier starts with Employee.Password.
Let us say there is a class Accountant that inherits from Employee.
Models
class Accountant extends Employee {
Code: string;
}Validation rules
let validateAccountantRules = (validator: IValidator<Accountant>) : ValidationResult => {
return validator
.NotEmpty(m => m.Code, "Should not be empty")
.ToResult();
};Populate models
let accountant = new Accountant();
accountant.Code = "ACC001";
//Employee data
accountant.Name = "John Doe";
accountant.Password = "sD4A3";
accountant.PreviousPasswords = new Array<string>()
accountant.PreviousPasswords.push("sD4A");
accountant.PreviousPasswords.push("sD4A1");
accountant.PreviousPasswords.push("sD4A2");
var expiryDate = new Date();
accountant.CreditCards = new Array<CreditCard>();
var masterCard = new CreditCard();
masterCard.Number = "5105105105105100";
masterCard.Name = "John Doe"
masterCard.ExpiryDate = expiryDate;
var amexCard = new CreditCard();
amexCard.Number = "371449635398431";
amexCard.Name = "John Doe";
amexCard.ExpiryDate = expiryDate;
accountant.CreditCards.push(masterCard);
accountant.CreditCards.push(amexCard);
accountant.Super = new Super();
accountant.Super.Name = "XYZ Super Fund";
accountant.Super.Code = "XY1234";
accountant.Email = "[email protected]";Synchronous validation
let validationResult = new Validator(accountant).ValidateBase(validateEmployeeRules)
.Validate(validateAccountantRules); Asynchronous validation
let validationResult = await new Validator(accountant).ValidateBaseAsync(validateEmployeeRules)
.ValidateAsync(validateAccountantRules); - The Accountant model inherits from Employee.
- The validation rules for Accountant model (validateAccountantRules) only validate the properties of the Accountant class.
- The base class Employee is validated using ValidateBase and ValidateBaseAsync methods and the Employee validation rules.