Skip to content

A generic validator with business logic separation in mind. (pub.dev package)

License

Notifications You must be signed in to change notification settings

ahmdaeyz/generic_validator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

pub package likes

This package provides APIs to facilitate separating validation and business rules from the application presentation.

Features

  • Express your rules in a declarative way.
  • Feedback doesn't have to be of a certain type (totally generic)
  • Group related rules together and eliminate if else statements.
  • Supports asynchronous evalution of rules.

Usage

Check /example for a full detailed usage.

You can declare a ValidationRule with a ruler which encapsulates your validation and of course the negativeFeedback of your choice which can be of any type then call apply on it.

final myName = 'Ahmed';
final arabicName = 'احمد';
final nameRule = ValidationRule(
            ruler: (value) {
              if (RegExp("[A-Za-z]").hasMatch(value)) {
                return true;
              }
              return false;
            },
            negativeFeedback: "Name has to be in English");
final validResult = nameRule.apply(myName); // Returns Valid
final invalidResult = nameRule.apply(arabicName); // Returns Invalid which has a reasons property of the type of the negative feedback passed earlier.

Grouping rules together can be convenient in that case, you can subclass the Validator and override its rules getter declaring your rules.

class NameValidator extends Validator<String, dynamic> {
  @override
  List<ValidationRule<String, dynamic>> get rules => [
      ValidationRule(
            ruler: (value) {
              if (value.isNotEmpty){
                return true;
              }
              return false;
            },
            negativeFeedback: "Name can't be empty"),
        ValidationRule(
            ruler: (value) {
              if (RegExp("[A-Za-z]").hasMatch(value)) {
                return true;
              }
              return false;
            },
            negativeFeedback: "Name has to be in English"),
      ];
}

Call validate on it to get the result:

  
  final aValidName = "Ahmed";
  final invalidName = "";
  final nameValidator = NameValidator();
  final validResult = nameValidator.validate(aValidName); // Returns Valid
  final invalidResult = nameValidator.validate(invalidName); // Returns Invalid with a reasons property

You can also mixin StringRules which has common rules like notEmpty

class NameValidator extends Validator<String, dynamic> with StringRules {
  @override
  List<ValidationRule<String, dynamic>> get rules => [
        notEmpty<String>(negativeFeedback: "This field can't be empty."),
        max(
            maxLength: 10,
            negativeFeedback: "Name can't be more than 10 characters."),
        ValidationRule(
            ruler: (value) {
              if (RegExp("[A-Za-z]").hasMatch(value)) {
                return true;
              }
              return false;
            },
            negativeFeedback: "Name has to be in English"),
      ];
}

You can create both an AsyncValidationRule and an AsyncValidator which can have both ValidationRule and AsyncValidationRules rules.

A validation result have a couple of convient methods like when, maybeWhen, map, and maybeMap. for usages like:

// Map validation result objects to String or null for use with the TextFormfield validator function.
nameValidator.validate(val).maybeMap(
    invalid: (invalid) => invalid.reasons.first,
    orElse: () => null,
);
// Side effects based on a validation result.
phoneValidator.validate(val).maybeWhen(
      invalid: (reasons) {
        // show a dialog
      },
      orElse: () {
        // pop the current screen
      },
);

About

A generic validator with business logic separation in mind. (pub.dev package)

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published