Validation Schemas
Schemas define what kind of data you expect and which rules should run on it. The main idea is simple: pick a schema type, attach rules, and validate the value.
Schema Types
String Schema
Use Validasi.string() for text values.
import 'package:validasi/validasi.dart';
import 'package:validasi/rules.dart';
import 'package:validasi/engine.dart';
final nameSchema = Validasi.string([
Rules.string.minLength(2),
Rules.string.maxLength(50),
]);
final result = nameSchema.validate('John Doe');
print(result.isValid);Number Schema
Use Validasi.number<T>() for numeric values.
final ageSchema = Validasi.number<int>([
Rules.number.moreThanEqual(0),
Rules.number.lessThan(150),
]);
print(ageSchema.validate(25).isValid);List Schema
Use Validasi.list<T>() for lists and other iterables.
final tagsSchema = Validasi.list<String>([
Rules.iterable.minLength(1),
Rules.iterable.forEach<String>([
Rules.string.minLength(2),
Rules.string.maxLength(20),
]),
]);
print(tagsSchema.validate(['flutter', 'dart']).isValid);Map Schema
Use Validasi.map<T>() for objects and structured data.
final userSchema = Validasi.map<dynamic>([
Rules.map.hasFields({
'name': FieldRules<String>([
Rules.string.minLength(1),
]),
'age': FieldRules<int>([
Rules.number.moreThanEqual(18),
]),
}),
]);
print(userSchema.validate({
'name': 'Alice',
'age': 25,
}).isValid);Any Schema
Use Validasi.any<T>() when you want to validate a value with custom rules.
final termsSchema = Validasi.any<bool>([
Rules.inline<bool>((value) {
return value == true ? null : 'You must accept the terms';
}),
]);
print(termsSchema.validate(true).isValid);Schema Composition
Schemas are easy to extend because the API lets you reuse existing schemas as building blocks. Define small schemas once, then combine them into larger ones with Rules.map, Rules.iterable, or additional inline rules.
final emailRules = <Rule<String>>[
Rules.transform<String>((value) => value?.trim().toLowerCase()),
Rules.string.minLength(5),
Rules.inline<String>((value) {
return value.contains('@') ? null : 'Invalid email format';
}),
];
final passwordRules = <Rule<String>>[
Rules.string.minLength(8),
];
final registrationSchema = Validasi.map<dynamic>([
Rules.map.hasFields({
'email': FieldRules<String>(emailRules),
'password': FieldRules<String>(passwordRules),
'confirmPassword': FieldRules<String>(passwordRules),
}),
Rules.inline<Map<String, dynamic>>((value) {
return value['password'] == value['confirmPassword']
? null
: 'Passwords do not match';
}),
]);This pattern keeps rule lists small and reusable while still letting you build stricter validation at the top level.
Typed Input Handling
By default, each schema accepts its output type. However, when you need to accept a different input type (e.g., strings from JSON), use withPreprocess to convert and enforce the input type at compile time:
// Schema validates int, but accepts String input
final ageSchema = Validasi.number<int>([
Rules.number.moreThanEqual(0),
Rules.number.lessThan(150),
]).withPreprocess(
ValidasiTransformation<String, int>((value) => int.parse(value)),
);
// validate() now requires String at compile time
final result = ageSchema.validate('25');
print(result.data); // 25 (int)Key Points:
- Without
withPreprocess,validate()accepts the schema's output type withPreprocesschanges the accepted input type at compile time- Use this for parsing external data: JSON strings, form inputs, API responses
- For more details, see Transformations Guide
Validation Results
validate() returns a ValidasiResult with the final data and any errors.
final result = userSchema.validate(data);
if (result.isValid) {
print(result.data);
} else {
for (final error in result.errors) {
print('${error.path?.join('.')}: ${error.message}');
}
}isValidtells you whether validation passed.datacontains the validated value, including any transformations.errorscontains the validation failures.error.messageis the human-readable message.error.pathpoints to the field that failed in nested structures.
Best Practices
- Keep schemas small and reusable.
- Use explicit type parameters for better type safety.
- Put transforms before validation rules when both are needed.
- Prefer clear, user-friendly error messages.
