Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/danielcardonarojas/verify

A Dart validation DSL to validate your flutter app models.
https://github.com/danielcardonarojas/verify

dart dartlang flutter input-validation validation

Last synced: 27 days ago
JSON representation

A Dart validation DSL to validate your flutter app models.

Awesome Lists containing this project

README

        




Validations made simple



Build Status


Pub Package


Codecov


MIT License

A fp inspired validation DSL. For Dart and Flutter projects.

## Features

- Completely extensible (create your own combinators, validator primitives, etc)
- Flexible Verify is an extension based API (There is not single class created its all pure functions)
- Customizable (Define you own error types if required) organize validators how ever you want
- Bloc friendly (See [examples](https://github.com/DanielCardonaRojas/verify/tree/master/example) for a concrete implementation)
- Null safe (as a prerelease)

## Usage

### Creating validators

A Validator is just a simple function alias:

```dart
// One of 2 variats depending on wether the validated subject will be transformed into another type or not
typedef ValidatorT = Either, T> Function(S subject);
typedef Validator = Either, S> Function(S subject);
```

So you can create your own validator by just specifying a function for example:

```dart
final Validator emailValidator = (String email) {
return email.contains('@') ? Right(email) : Left('Bad email format')
};
```

**Create simple validators from predicates**

A simpler way is to use some of the built in helpers.

```dart
final contains@ = Verify.that(
(String email) => email.contains('@'),
error: 'Bad email format'
);

```

Use custom errors and filter them by type

### Reuse validators

Use composition to build up more complex validators.

```dart
final Validator emailValidator = Verify.all([ contains@, notEmpty ])
```

### Validate and transform

Validators are also capable of transforming their input, so for instance we can do
parsing and validation in one go.

```dart
final Validator intParsingValidator = (String str) => Right(int.parse(str));

final validator = intParsingValidator.onException((_) => Error('not an integer'));
```

### Field validations

Given a model, for instance a user:

```dart
class User extends Equatable {
final String? phone;
final String? mail;
final int? age;

const User(this.phone, this.mail, this.age);

@override
List get props => [phone ?? '', mail ?? '', age ?? ''];
}
```

Additional checks can be performed on the object and its fields by chaining a series of `check`
and `checkField` methods.

```dart
final userValidator = Verify.empty()
.check((user) => !user.phone!.isEmpty, error: Error('phone empty'))
.checkField((user) => user.mail!, emailValidator);

final someUser = User('','', 25);
final Either, User> validationResult = userValidator.verify(someUser);
```

> Note: The difference between check and checkField is that the later ignore the verification when the value is null,
> this will likely change in next version supporting null safety.

### Run a validator

Running a validator is a simple as passing in a parameter since its just a function.
To be a bit more eloquent a `verify` method is provided, this method is special because besides
forwarding the argument to the calling validator it can also be used to filter the error list and
have it cast to a specific error type. Just supply a specific type parameter.

```dart
final signUpValidation = Verify.subject();
final errors = signUpValidation
.verify(newState); // Either, SignUpState>
```

### Built in validators

Verify doesn't come with many built in validators, because they are so simple to create.

It does come with some regex shorthands.

```dart
final validator = Verify.fromRegex(RegExp(r"(^\d+$)", error: Error('not just digits')) // Validator
```

### Form validation

Often times you will have modeled your error type similar to:

```dart
enum FormField {
email,
password,
passwordConfirmation,
}

class SignUpError extends ValidationError {
final String message;
final FormField field;

SignUpError(this.message, {required this.field});

@override
String get errorDescription => message;
}
```

In these scenarios its convenient to be able to group errors by field.

The solution verify provides for this is:

```dart
final validator = Verify.inOrder([
validateMail,
validatePassword,
validateConfirmation,
]);

final Map errorMap = validator
.verify(someState)
.errorsGroupedBy((error) => error.field);
```

## Sequencing

A slightly different API can be used to achieve the same results as the `inOrder` composition function.

```dart
final numberValidator = Verify.subject()
.then(Verify.that(
(subject) => subject % 2 == 0,
error: Error('not even'),
))
.then(Verify.that(
(subject) => subject >= 10,
error: Error('single digit'),
));

final errors2 = numberValidator.errors(3); // yields 1 error
final errors = numberValidator.errors(4); // yields 1 error
```

This way you have quick access to errors segmented by field.