Validates arguments using one or more validator functions before passing them to the wrapped function.
Validation link
Validation decorators check inputs before executing the wrapped function.
validate link
What it is link
Validates arguments using one or more validator functions before passing them to the wrapped function.
When to use it link
- Input sanitization
- Business-rule enforcement
- Form/API validation
Async / sync support link
Func<R> | Func1<T, R> | Func2<T1, T2, R> | FuncSync<R> |
|---|
| ❌ | ✅ | ✅ | ❌ |
API reference link
1
2
3
4
5
6
| // api-reference
Func1<T, R> validate({
required List<String? Function(T arg)> validators,
ValidationMode mode = ValidationMode.failFast,
void Function(List<String> errors)? onValidationError,
})
|
For Func2:
1
2
3
4
5
6
| // api-reference
Func2<T1, T2, R> validate({
required List<String? Function(T1 arg1, T2 arg2)> validators,
ValidationMode mode = ValidationMode.failFast,
void Function(List<String> errors)? onValidationError,
})
|
ValidationMode:
failFast — stop at the first error.aggregate — collect all errors before throwing.
Throws ValidationException on failure.
Examples link
Minimal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| final parse = Func1<String, int>((s) async => int.parse(s)).validate(
validators: [
(s) => s.isNotEmpty ? null : 'Empty',
(s) => int.tryParse(s) != null ? null : 'Not a number',
],
mode: ValidationMode.aggregate,
);
void main() async {
try {
await parse('x');
} on ValidationException catch (e) {
print(e.errors); // [Not a number]
}
}
|
Real world
1
2
3
4
5
6
7
8
9
10
11
12
| final createUser = Func2<String, String, User>((email, password) async {
return await authApi.createUser(email, password) as User;
}).validate(
validators: [
(email, password) => email.contains('@') ? null : 'Invalid email',
(email, password) => password.length >= 8 ? null : 'Password too short',
],
mode: ValidationMode.aggregate,
onValidationError: (errors) => logger.info('Validation failed: $errors'),
);
await createUser('user@example.com', 'password123');
|
Best practices link
- Use
aggregate for user-facing forms to report all issues at once. - Keep validators pure and fast.
Common pitfalls link
- At least one validator is required; empty list triggers an assertion.
validate is only available on Func1 and Func2.
What it is link
Enforces pre-conditions and post-conditions around execution.
When to use it link
- Defensive programming
- Invariant checking
- Contract validation
Async / sync support link
Func<R> | Func1<T, R> | Func2<T1, T2, R> | FuncSync<R> |
|---|
| ✅ | ✅ | ✅ | ❌ |
API reference link
1
2
3
4
5
6
7
| // api-reference
Func<R> guard({
List<bool Function()> preCondition = const [],
List<bool Function(R result)> postCondition = const [],
String preConditionMessage = 'Pre-condition failed',
String postConditionMessage = 'Post-condition failed',
})
|
For Func1:
1
2
3
4
5
6
| // api-reference
Func1<T, R> guard({
List<bool Function(T arg)> preCondition = const [],
List<bool Function(R result)> postCondition = const [],
...
})
|
For Func2:
1
2
3
4
5
6
| // api-reference
Func2<T1, T2, R> guard({
List<bool Function(T1 arg1, T2 arg2)> preCondition = const [],
List<bool Function(R result)> postCondition = const [],
...
})
|
Throws GuardException on failure.
Examples link
Minimal
1
2
3
4
5
6
7
8
9
10
11
12
| final divide = Func2<int, int, double>((a, b) async => a / b).guard(
preCondition: (a, b) => b != 0,
postCondition: (result) => result.isFinite,
);
void main() async {
try {
await divide(1, 0);
} on GuardException catch (e) {
print(e.message); // Pre-condition failed
}
}
|
Real world
1
2
3
4
5
6
7
8
| final withdraw = Func2<String, double, void>((accountId, amount) async {
await bankApi.withdraw(accountId, amount);
}).guard(
preCondition: (accountId, amount) => accountId.isNotEmpty && amount > 0,
postCondition: (_) => true,
);
await withdraw('account-123', 100.0);
|
Best practices link
- Use guards for invariants that should never be violated in production.
- Provide clear custom messages for debugging.
Common pitfalls link
- At least one condition is required.
- Post-conditions run after the function succeeds; they do not run if the function throws.