Validasi


A flexible, composeable, and type-safe validation library for Dart & Flutter.
Documentation API Documentation
Caution
This is the complete rewrite of the Validasi library into a completely new API (with modifier support).
Installation
To use this package, add validasi as a dependency in your pubspec.yaml file:
dependencies:
validasi: 1.0.0-dev.0
Quick Usage
To use this library, simply import package:validasi/validasi.dart and the rules from package:validasi/rules.dart. Here's a basic example:
import 'package:validasi/validasi.dart';
import 'package:validasi/rules.dart';
void main() {
final schema = Validasi.string([
Nullable(),
Transform((input) => input?.trim()),
StringRules.minLength(3),
StringRules.maxLength(16)
]);
final result = schema.validate(' Hello World! ');
print("isValid: ${result.isValid}, errors: ${result.errors.map((e) => e.message).join(', ')}, value: ${result.data}");
}
Type-Safe Validation with Input Transformation
When accepting different input types, use withPreprocess to ensure type safety at compile time:
final ageSchema = Validasi.number<int>([
NumberRules.moreThan(0),
NumberRules.lessThan(150),
]).withPreprocess(
ValidasiTransformation<String, int>((value) => int.parse(value)),
);
// validate() now accepts String due to preprocessing
final result = ageSchema.validate('25');
print("Valid: ${result.isValid}, Age: ${result.data}"); // Valid: true, Age: 25
Validating Complex Data Structures
Map Validation:
final schema = Validasi.map<dynamic>([
MapRules.hasFields({
'name': Validasi.string([
StringRules.minLength(1),
]),
'age': Validasi.number<int>([
NumberRules.moreThan(0),
]),
}),
]);
final result = schema.validate({'name': 'John', 'age': 30});
print('Valid: ${result.isValid}');
List Validation:
final schema = Validasi.list<String>([
IterableRules.forEach(
Validasi.string([
StringRules.minLength(1),
]),
),
]);
final result = schema.validate(['item1', 'item2', 'item3']);
print('Valid: ${result.isValid}');
Handling Dynamic Inputs with withPreprocess:
// Accept JSON-like data and validate as typed schema
final userSchema = Validasi.map<dynamic>([
MapRules.hasFields({
'name': Validasi.string([StringRules.minLength(1)]),
'age': Validasi.number<int>([NumberRules.moreThan(0)]),
}),
]);
final result = userSchema.validate({
'name': 'Alice',
'age': 28,
});
Features
Type-Safe Validation Engine
Validasi provides type-safe validation schemas for various data types:
Validasi.string()- String validationValidasi.number<T>()- Numeric validation (int, double, num)Validasi.list<T>()- List/Iterable validationValidasi.map<T>()- Map validationValidasi.any<T>()- Generic type validation
Built-in Rules
The library comes with comprehensive built-in rules organized by data type:
String Rules:
StringRules.minLength()- Minimum length validationStringRules.maxLength()- Maximum length validationStringRules.oneOf()- Value must be one of specified options
Number Rules:
NumberRules.finite()- Ensures number is finiteNumberRules.lessThan()- Less than comparisonNumberRules.lessThanEqual()- Less than or equal comparisonNumberRules.moreThan()- Greater than comparisonNumberRules.moreThanEqual()- Greater than or equal comparison
Iterable Rules:
IterableRules.minLength()- Minimum list lengthIterableRules.forEach()- Validate each item in the list
Map Rules:
MapRules.hasFields()- Validate nested map fields with individual schemasMapRules.hasFieldKeys()- Ensure required keys existMapRules.conditionalField()- Conditional field validation based on other fields
Modifier Rules:
Nullable()- Allow null valuesRequired()- Ensure non-null valuesTransform()- Transform values during validationHaving()- Custom validation with context accessInlineRule()- Create custom validation rules inline
Preprocessing & Transformation
Use ValidasiTransformation to preprocess input data before validation:
final schema = Validasi.string([StringRules.minLength(3)])
.withPreprocess(ValidasiTransformation((value) => value.toString()));
final result = schema.validate(123); // Converts to "123" then validates
Safe Validation
All validation returns a ValidasiResult object that contains:
isValid- Boolean indicating validation successdata- The validated (and potentially transformed) dataerrors- List of validation errors with messages and paths
Agent-Native Core Support (Beta)
Agent-native support is currently in beta and only supports Validasi v1.0.0-dev.x.
Validasi now includes machine-friendly schema and result payloads for tool calling workflows.
import 'dart:convert';
import 'package:validasi/validasi.dart';
import 'package:validasi/rules.dart';
final schema = Validasi.map<dynamic>([
MapRules.hasFields({
'name': Validasi.string([StringRules.minLength(2)]),
'age': Validasi.number<int>([NumberRules.moreThanEqual(18)]),
}),
]);
// Describe validation contract for an agent/tool.
final descriptor = schema.introspect().toJson();
print(jsonEncode(descriptor));
// Validate and return deterministic tool payload.
final result = schema.validate({'name': 'A', 'age': 15});
print(jsonEncode(result.toToolResponse()));
Tooling-focused APIs:
ValidasiEngine.introspect()for rule/schema metadataValidationError.toToolMap()for stable error payloadsValidasiResult.toToolResponse()for stable validation envelopes
MCP Adapter (Beta)
For external MCP clients, use the adapter package in packages/validasi_mcp.
This adapter is beta and targets only Validasi v1.0.0-dev.x.
It exposes stdio JSON-RPC support for:
initializetools/listtools/call
With built-in tools:
list_schemasdescribe_schemavalidate_input
See packages/validasi_mcp/README.md for usage and embedding examples.
Nested Validation with Error Paths
Validasi tracks error paths for nested structures, making it easy to identify exactly where validation fails:
final result = schema.validate(complexNestedData);
result.errors.forEach((error) {
print("Error at ${error.path?.join('.')}: ${error.message}");
});
License
The Validasi Library is licensed under MIT License.
Contribution
We welcome contributions! Here's how to set up the development environment:
Setting Up Development Environment
# Clone the repository
git clone https://github.com/albetnov/validasi
cd validasi
# Install root dependencies (includes melos)
dart pub get
# Install workspace dependencies
dart run melos bootstrap
Running Tests
The test structure in test/ directory mirrors the lib/src structure:
# Run all tests
dart run melos run test
# Run tests for root package only
dart run melos run test:validasi
# Run tests for MCP package only
dart run melos run test:mcp
# Run tests with coverage
dart test --coverage=coverage
# Format coverage report
dart pub global activate coverage
dart pub global run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info --report-on=lib