Skip to content

Built-in Modifier Rules

This page covers the modifier rules that apply across schemas. Type-specific rules are documented separately.

Global Rules

Nullable

Allows null values to pass validation.

dart
final optionalNameSchema = Validasi.string([
  Rules.nullable<String>(),
  Rules.string.minLength(3),
]);

print(optionalNameSchema.validate(null).isValid);
print(optionalNameSchema.validate('John').isValid);

Required

Explicitly requires a non-null value.

dart
final requiredNameSchema = Validasi.string([
  Rules.required<String>(),
  Rules.string.minLength(3),
]);

print(requiredNameSchema.validate(null).isValid);

Transform

Changes the value before later rules run.

dart
final trimmedSchema = Validasi.string([
  Rules.transform<String>((value) => value?.trim()),
  Rules.string.minLength(3),
]);

final result = trimmedSchema.validate('  hello  ');
print(result.data);
print(result.isValid);

TransformAsync

Async version of Transform. Useful for async operations like fetching data:

dart
final schema = Validasi.string([
  Rules.transformAsync<String>((value) async {
    final normalized = await normalizeEmail(value);
    return normalized;
  }),
  Rules.string.email(),
]);

final result = await schema.validateAsync('USER@Example.com');

Having

Ensures the value is one of a set of allowed values.

dart
final schema = Validasi.string([
  Rules.having<String>(['draft', 'published', 'archived']),
]);

InlineRule

Runs custom validation inline without using context.

dart
final passwordSchema = Validasi.string([
  Rules.string.minLength(8),
  Rules.inline<String>((value) {
    if (!value.contains(RegExp(r'[A-Z]'))) {
      return 'Must contain at least one uppercase letter';
    }
    return null;
  }),
]);

InlineAsync

Async version of InlineRule. Perfect for async checks like email availability:

dart
final registerSchema = Validasi.string([
  Rules.required(),
  Rules.string.email(),
  Rules.inlineAsync((email) async {
    if (email == null) return true;
    final taken = await userRepository.isEmailTaken(email);
    return !taken;
  }, message: 'Email is already taken'),
]);

final result = await registerSchema.validateAsync('user@example.com');

Special Rules

These rules are still modifier rules, but they are used for more advanced control over validation behavior.

Combining Rules

You can stack modifier rules to clean, normalize, and validate in one schema.

dart
final schema = Validasi.string([
  Rules.nullable<String>(),
  Rules.transform<String>((value) => value?.trim()),
  Rules.transform<String>((value) => value?.toLowerCase()),
  Rules.inline<String>((value) {
    if (value != null && value.length < 3) {
      return 'Too short';
    }
    return null;
  }),
  Rules.string.maxLength(50),
]);

Choosing the Right Rule

  • Use Rules.nullable<String>() when null is allowed.
  • Use Rules.required<String>() when you want to make non-null intent explicit.
  • Use Rules.transform<String>() for normalization or data cleanup.
  • Use Rules.transformAsync<String>() for async normalization.
  • Use Rules.having<String>() when the rule needs validation context.
  • Use Rules.inline<String>() for simple custom validation.
  • Use Rules.inlineAsync<String>() for async custom validation (e.g., database checks).

Best Practices

  • Put Rules.nullable<String>() or Rules.required<String>() first so the schema intent is obvious.
  • Keep Rules.transform<String>() rules before validation rules.
  • Use the simplest rule that fits the job.
  • Keep error messages short and clear.

Released under the MIT License.