Common Recipes
This page provides quick solutions to common validation scenarios. Each recipe shows a complete, working example you can copy and adapt.
Email and Password Validation
Validate user credentials with proper constraints:
import 'package:ack/ack.dart';
// Email with proper format
final emailSchema = Ack.string()
.email()
.notEmpty();
// Password with security requirements
final passwordSchema = Ack.string()
.minLength(8)
.matches(r'.*[A-Z].*', message: 'Password must contain an uppercase letter')
.matches(r'.*[a-z].*', message: 'Password must contain a lowercase letter')
.matches(r'.*[0-9].*', message: 'Password must contain a number');
// Login form schema
final loginSchema = Ack.object({
'email': emailSchema,
'password': passwordSchema,
});
// Usage
final result = loginSchema.safeParse({
'email': 'user@example.com',
'password': 'SecurePass123',
});
if (result.isOk) {
print('Credentials valid');
} else {
print('Error: ${result.getError()}');
}
Nested Object Validation
Validate nested data structures like addresses:
final addressSchema = Ack.object({
'street': Ack.string().notEmpty(),
'city': Ack.string().notEmpty(),
'zipCode': Ack.string().matches(r'\d{5}(-\d{4})?'),
'country': Ack.string().notEmpty(),
});
final userWithAddressSchema = Ack.object({
'name': Ack.string(),
'email': Ack.string().email(),
'shippingAddress': addressSchema,
'billingAddress': addressSchema.optional().nullable(),
});
// Usage
final result = userWithAddressSchema.safeParse({
'name': 'John Doe',
'email': 'john@example.com',
'shippingAddress': {
'street': '123 Main St',
'city': 'Springfield',
'zipCode': '12345',
'country': 'USA',
},
});
List Validation
Validate lists with constraints on items and length:
// Shopping cart with at least 1 item
final cartSchema = Ack.object({
'userId': Ack.string(),
'items': Ack.list(Ack.object({
'productId': Ack.string(),
'quantity': Ack.integer().positive(),
'price': Ack.double().positive(),
})).minLength(1).maxLength(50),
});
// Tags with max 5 items
final postSchema = Ack.object({
'title': Ack.string().minLength(5).maxLength(100),
'content': Ack.string().minLength(10),
'tags': Ack.list(Ack.string()).maxLength(5),
});
Enum Validation
Validate string values against allowed options:
// Status with specific allowed values
final orderSchema = Ack.object({
'orderId': Ack.string(),
'status': Ack.string().enumString([
'pending',
'processing',
'shipped',
'delivered',
'cancelled',
]),
'priority': Ack.string().enumString(['low', 'medium', 'high']),
});
// Usage
final result = orderSchema.safeParse({
'orderId': 'ORD-123',
'status': 'shipped',
'priority': 'high',
});
Custom Validation
Create reusable custom validators for domain-specific rules:
import 'package:ack/ack.dart';
// Custom phone number constraint
class PhoneNumberConstraint extends Constraint<String> with Validator<String> {
PhoneNumberConstraint()
: super(
constraintKey: 'phone_number',
description: 'Must be valid phone number (e.g., +1-234-567-8900)',
);
final _regex = RegExp(r'^\+\d{1,3}-\d{3}-\d{3}-\d{4}$');
@override
bool isValid(String value) => _regex.hasMatch(value);
@override
String buildMessage(String value) =>
'Must be valid phone number (e.g., +1-234-567-8900)';
}
final registrationSchema = Ack.object({
'username': Ack.string().minLength(3),
'email': Ack.string().email(),
'phone': Ack.string().constrain(PhoneNumberConstraint()),
'password': Ack.string().minLength(8),
'confirmPassword': Ack.string().minLength(8),
}).refine(
(data) => data['password'] == data['confirmPassword'],
message: 'Passwords do not match',
);
API Response Validation
Validate external API responses to ensure data integrity:
// GitHub user API response
final githubUserSchema = Ack.object({
'login': Ack.string(),
'id': Ack.integer(),
'avatar_url': Ack.string().url(),
'name': Ack.string().nullable(),
'email': Ack.string().email().nullable(),
'bio': Ack.string().nullable(),
'public_repos': Ack.integer(),
'followers': Ack.integer(),
'following': Ack.integer(),
'created_at': Ack.string(), // ISO datetime
});
// Usage in API call
Future<void> fetchUser(String username) async {
final response = await http.get(
Uri.parse('https://api.github.com/users/$username'),
);
final json = jsonDecode(response.body);
final result = githubUserSchema.safeParse(json);
if (result.isOk) {
final user = result.getOrThrow();
print('User: ${user['login']}');
} else {
print('Invalid API response: ${result.getError()}');
}
}
See Also
- Custom Validation Guide - Deep dive into custom validators
- Flutter Form Validation - Integrate with Flutter forms
- Schema Types - All available schema types
- Validation Rules - Complete constraint reference