dup
A powerful, flexible validation library for Dart and Flutter, inspired by JavaScript's yup.
Features
- Schema-based validation for forms and data models
- Chainable, composable validation rules
- Customizable error messages and labels
- Exception-based error handling
- Easy localization (multi-language support)
- Supports Korean postpositions and number formatting
- Easy integration with Flutter
Usage
dup enables you to define validation rules for your data using a schema-based approach, making your validation logic clean, reusable, and maintainable.
1. Define a validation schema
import 'package:dup/dup.dart';
final BaseValidatorSchema schema = BaseValidatorSchema({
'email': ValidateString()
.email()
.required()
.setLabel('Email'),
'password': ValidateString()
.password()
.required()
.setLabel('Password'),
'age': ValidateNumber()
.min(18)
.max(99)
.setLabel('Age'),
});
emailmust be a valid email address and is required.passwordmust meet your password rule and is required.agemust be between 18 and 99.
2. Prepare request data
final request = {
'email': 'test@example.com',
'password': '1234',
'age': 20,
};
3. Validate
Call useUiForm.validate() to validate your data against the schema.
If validation fails, a FormValidationException will be thrown with a map of error messages.
try {
await useUiForm.validate(schema, request);
// Validation passed!
} catch (e) {
print(e.toString()); // Example: 'Email is not a valid email address.'
}
Example: Validating a request object
You can encapsulate validation logic inside your data classes for better structure and reusability.
class RequestObject {
String? title;
String? contents;
RequestObject({this.title, this.contents});
/// Validates the request fields using dup's schema-based validation.
Future validate() async {
final BaseValidatorSchema schema = BaseValidatorSchema({
'title': ValidateString()
.min(2)
.setLabel('Title')
.required(),
'contents': ValidateString()
.min(2)
.setLabel('Contents')
.required(),
});
await useUiForm.validate(schema, {
'title': title,
'contents': contents,
});
}
}
Custom Validation
dup allows you to easily add your own validation logic, either inline or as reusable extensions.
Inline Custom Validator
final validator = ValidateString()
.setLabel('Nickname')
.required()
.addValidator((value) {
if (value != null && value.contains('admin')) {
return 'Nickname cannot contain the word "admin".';
}
return null;
});
Custom Extension Validator
You can define your own extension methods for custom validation rules:
extension CustomStringValidator on ValidateString {
/// Disallow special characters in the string.
ValidateString noSpecialChars({String? message}) {
return addValidator((value) {
if (value != null && RegExp(r'[!@#\$%^&*(),.?":{}|<>]').hasMatch(value)) {
return message ?? '$label cannot contain special characters.';
}
return null;
});
}
}
// Usage
final validator = ValidateString()
.setLabel('Nickname')
.noSpecialChars(message: 'Nickname cannot contain special characters!');
Customizing Error Messages
dup lets you easily override the default error messages for any validation rule.
You can do this in two ways:
1. Per-Validator Custom Message
You can provide a custom message for a specific validation rule using the messageFactory
parameter:
final validator = ValidateString()
.setLabel('Username')
.min(
4, messageFactory: (label, args) => '$label must be at least ${args['min']} characters long.');
- The
messageFactoryis a function that receives the field label and arguments (likemin,max, etc.). - This custom message will be used only for this validation rule.
2. Global Custom Messages
You can globally override error messages for your entire app by registering a custom message factory:
ValidatorLocale.setLocale(
ValidatorLocale(
mixed: {
'required': (args) => '${args['name']} is required.',
// ...other global messages
},
string: {
'min': (args) => '${args['name']} must be at least ${args['min']} characters long.',
/ / ...other string messages
},
// ...number, array, etc.
),
);
- This will apply your custom messages to all validators of the corresponding type and rule.
- You can still override these global messages per-validator using the
messageFactoryparameter if needed.
3. Localization File Customization
If you use localization (e.g., with easy_localization), you can also edit your language JSON files
to change the default messages for each key.
Summary:
- Use
messageFactoryin your validator for per-field custom messages. - Use
ValidatorLocale.setLocale()for app-wide global custom messages. - Edit your localization files for language-specific message customization.
API Overview
BaseValidator: Abstract base class for validatorsValidateString: String validation (min, max, email, password, etc.)ValidateNumber: Number validation (min, max, isInteger, etc.)ValidateList: List validationBaseValidatorSchema: Schema for form validationUiFormService: Service for validating schemas and handling errorsFormValidationException: Exception thrown on validation failure
Links
License
MIT