Overview
Ack is a schema validation library for Dart and Flutter that helps you validate data with a simple, fluent API. Ack is short for "acknowledgment".
Why Use Ack?
- Simplify Validation: Easily handle complex data validation logic.
- Ensure Data Integrity: Guarantee data consistency from external sources (APIs, user input).
- Single Source of Truth: Define data structures and rules in one place.
- Reduce Boilerplate: Minimize repetitive code for validation and JSON conversion.
What Ack Does
- Ensures data conforms to your defined schemas
- Facilitates seamless conversion between JSON and Dart models
- Generates JSON Schema specifications from your schemas
- Delivers detailed and easy-to-understand validation error messages
Basic Usage
import 'package:ack/ack.dart';
// Define the structure and rules for a user object.
final userSchema = Ack.object({
'name': Ack.string.minLength(2).maxLength(50), // Name must be a string between 2 and 50 chars.
'age': Ack.int.min(0).max(120), // Age must be an integer between 0 and 120.
'email': Ack.string.email().nullable(), // Email must be a valid format, but can be null.
}, required: ['name', 'age']); // Name and age are mandatory fields.
// Data to validate.
final dataToValidate = {
'name': 'John',
'age': 30,
'email': 'john@example.com'
};
// Perform the validation against the schema.
final result = userSchema.validate(dataToValidate);
// Check the validation outcome.
if (result.isOk) {
// Validation passed, safely access the validated data.
final validData = result.getOrThrow();
print('Valid data: $validData');
} else {
// Validation failed, access the detailed error.
final error = result.getError();
print('Validation Error: $error'); // Use error.toString() for full details.
}
Core Features
Ack provides a comprehensive set of features for data validation and transformation:
- Schema Types: Define data structures with strings, numbers, booleans, lists, objects, and more
- Validation Rules: Apply constraints like length, range, pattern matching, and custom validators
- TypeSafe Schemas: Create type-safe schemas with automatic validation
- Error Handling: Get detailed, structured error messages for validation failures
- JSON Serialization: Convert between JSON and typed models
TypeSafe Schemas
Turn any Dart class into a validating schema with annotations:
import 'package:ack/ack.dart';
import 'dart:convert';
// Define a model with validation and automatic inference
@Schema()
class User {
@MinLength(2) // Validation rule
final String name; // Non-nullable, required from constructor
@IsEmail() // Validation rule
final String email; // Non-nullable, required from constructor
@Min(18) // Validation rule
final int age; // Non-nullable, required from constructor
// Constructor parameters automatically determine required/optional status
User({
required this.name, // → Automatically inferred as required
required this.email, // → Automatically inferred as required
required this.age, // → Automatically inferred as required
});
}
// Dynamic payload from API, form, etc.
final Map<String, dynamic> payload = {
'name': 'John',
'email': 'john@example.com',
'age': 30
};
Automatic Inference: Ack automatically determines which fields are required or optional based on your constructor parameters (required this.field
vs this.field
) and field types (String
vs String?
). No need for redundant @Required
or @Nullable
annotations in most cases!
Generated schemas provide three main capabilities:
1. Type-safe property access
// Access typed properties directly from the schema
final userSchema = UserSchema().parse(payload);
if (userSchema.isValid) {
String name = userSchema.name; // Typed as String
String email = userSchema.email; // Typed as String
int age = userSchema.age; // Typed as int
print('$name ($email) is $age years old');
// Create model when needed
final user = User(name: name, email: email, age: age);
}
2. Flexible model creation patterns
// Add factory method to your model
class User {
// ... existing fields ...
factory User.fromSchema(UserSchema schema) {
if (!schema.isValid) {
throw AckException(schema.getErrors()!);
}
return User(name: schema.name, email: schema.email, age: schema.age);
}
}
// Usage
final user = User.fromSchema(UserSchema().parse(payload));
3. JSON Schema generation for documentation
// Generate JSON Schema from the same model definition
final jsonSchema = UserSchema().toJsonSchema();
print(jsonEncode(jsonSchema)); // Use in API docs or client validation