dzod 0.2.0+1 copy "dzod: ^0.2.0+1" to clipboard
dzod: ^0.2.0+1 copied to clipboard

A powerful Dart schema validation library inspired by Zod, providing type-safe validation, parsing, and inference with excellent developer experience.

Nonstop Logo

NonStop

Digital Product Development Experts for Startups & Enterprises

About | Website

🔐 Dzod

⚡ Enterprise-grade Dart schema validation library

pub package License Flutter

Test Coverage Tests


🎯 What is Dzod? #

Dzod is an enterprise-grade Dart schema validation library heavily inspired by Zod with advanced enterprise features. Built for production applications requiring robust data validation, type safety, and exceptional developer experience.

🏆 Key Achievements #

  • 🚀 Enterprise Features: Advanced error handling, async validation, schema composition, and JSON Schema generation
  • ⚡ 1588+ Comprehensive Tests: 99.3% test coverage with enterprise-grade quality assurance
  • 💡 Developer Experience: Intuitive API design with comprehensive documentation and examples

🚀 Quick Start #

# Add to your pubspec.yaml
dart pub add dzod

Example 1: Basic User Schema Validation #

import 'package:dzod/dzod.dart';

// Define an enterprise-grade user schema
final userSchema = z.object({
  'id': z.string().cuid2(), // CUID2 validation
  'name': z.string().min(2).max(50),
  'email': z.string().email(),
  'age': z.number().min(18).max(120),
  'role': z.enum_(['admin', 'user', 'guest']),
  'preferences': z.object({
    'theme': z.enum_(['light', 'dark']).defaultTo('light'),
    'notifications': z.boolean().defaultTo(true),
  }).partial(),
  'createdAt': z.string().datetime(),
});

// Validate with detailed error reporting
final result = userSchema.validate({
  'id': 'ckjf0x7qr0000qzrmn831i7rn',
  'name': 'John Doe',
  'email': 'john@example.com',
  'age': 25,
  'role': 'admin',
  'preferences': {'theme': 'dark'},
  'createdAt': '2023-01-01T00:00:00Z',
});

if (result.isSuccess) {
  final user = result.data;
  print('✅ Valid user: ${user['name']}');
} else {
  // Enterprise-grade error handling
  final errors = result.errors!;
  print('❌ Validation failed:');
  for (final error in errors.errors) {
    print('  • ${error.fullPath}: ${error.message}');
  }
}

📖 Core Features #

Feature Description Status
🔥 Schema Types 19+ schema types with advanced validation ✅ Complete
⚡ Async Validation Full async/await support with database checks ✅ Complete
🔧 Advanced Features Pipelines, discriminated unions, coercion ✅ Complete
📊 Error System 100+ error codes, custom formatting, context tracking ✅ Complete
🏗️ Schema Composition Introspection, JSON Schema generation, metadata ✅ Complete
🚀 Performance Lazy evaluation, caching, memory optimization ✅ Complete

🔧 Schema Types #

🎯 Basic Types #

Example 2: String Validations #

// String validations (separate examples)
final emailSchema = z.string().min(2).max(50).email();
final urlSchema = z.string().url();
final uuidSchema = z.string().uuid();
final cuidSchema = z.string().cuid();
final cuid2Schema = z.string().cuid2();
final ulidSchema = z.string().ulid();
final jwtSchema = z.string().jwt();
final base64Schema = z.string().base64();
final hexSchema = z.string().hex();
final hexColorSchema = z.string().hexColor();
final emojiSchema = z.string().emoji();
final jsonSchema = z.string().json();
final nanoidSchema = z.string().nanoid();

Example 3: Number Validations #

// Number validations (separate examples)
final basicNumberSchema = z.number().min(0).max(100).integer().positive();
final stepSchema = z.number().step(0.1);
final precisionSchema = z.number().precision(2);
final safeIntSchema = z.number().safeInt();
final percentageSchema = z.number().percentage();
final probabilitySchema = z.number().probability();
final latitudeSchema = z.number().latitude();
final longitudeSchema = z.number().longitude();
final powerOfTwoSchema = z.number().powerOfTwo();
final primeSchema = z.number().prime();
final perfectSquareSchema = z.number().perfectSquare();

Example 4: Boolean and Null Types #

// Boolean and null types
final boolSchema = z.boolean();
final nullSchema = z.null_();

🏗️ Complex Types #

Example 5: Advanced Object Manipulation #

// Advanced object manipulation (separate examples)
final baseUserSchema = z.object({
  'name': z.string(),
  'email': z.string().email(),
  'age': z.number().min(18),
  'address': z.object({
    'street': z.string(),
    'city': z.string(),
    'country': z.string(),
  }),
});

// Field selection and manipulation
final pickedSchema = baseUserSchema.pick(['name', 'email']);
final omittedSchema = baseUserSchema.omit(['age']);
final extendedSchema = baseUserSchema.extend({'phone': z.string()});

// Optional/required variations
final partialSchema = baseUserSchema.partial();
final deepPartialSchema = baseUserSchema.deepPartial();
final requiredSchema = partialSchema.required(['name', 'email']);

// Different handling modes for unknown properties
final strictSchema = baseUserSchema.strict();
final passthroughSchema = baseUserSchema.passthrough();
final stripSchema = baseUserSchema.strip();
final catchallSchema = baseUserSchema.catchall(z.string());

Example 6: Advanced Arrays #

// Advanced arrays (separate examples)
final baseArraySchema = z.array(z.string());

// Length constraints
final rangeArraySchema = baseArraySchema.min(1).max(10);
final exactLengthSchema = baseArraySchema.length(5);
final nonemptySchema = baseArraySchema.nonempty();

// Element validation
final uniqueSchema = baseArraySchema.unique();
final includesSchema = baseArraySchema.includes('required');
final excludesSchema = baseArraySchema.excludes('forbidden');

// Conditional validation
final someEmailSchema = baseArraySchema.some((element) => element.contains('@'));
final everyMinLengthSchema = baseArraySchema.every((element) => element.length >= 2);

// Transformation and filtering
final mappedSchema = baseArraySchema.mapElements((s) => s.trim());
final filteredSchema = baseArraySchema.filter((s) => s.length > 0);
final sortedSchema = baseArraySchema.sort((a, b) => a.compareTo(b));

Example 7: Type-safe Tuples #

// Type-safe tuples
final tupleSchema = z.tuple([
  z.string(),
  z.number(),
  z.boolean(),
]);

// Rest elements for additional values
final tupleWithRest = tupleSchema.rest(z.string());

// Length constraints
final exactLengthTuple = tupleSchema.exactLength(3);
final minLengthTuple = tupleSchema.minLength(2);
final maxLengthTuple = tupleSchema.maxLength(5);

Example 8: Flexible Enums #

// Flexible enums
final roleSchema = z.enum_(['admin', 'user', 'guest']);

// Remove specific values
final restrictedRoles = roleSchema.exclude(['guest']);

// Add new values
final extendedRoles = roleSchema.extend(['moderator', 'supervisor']);

// Case-insensitive matching
final caseInsensitiveRoles = roleSchema.caseInsensitive();

Example 9: Key-value Records #

// Key-value records
final recordSchema = z.record(z.number());

// Size constraints
final sizedRecord = recordSchema.min(1).max(10);

// Key requirements
final keyConstrainedRecord = recordSchema
    .requiredKeys({'id'})
    .optionalKeys({'meta'});

// Strict validation (no additional keys)
final strictRecord = recordSchema.strict();

🎭 Advanced Schema Types #

Example 10: Discriminated Unions #

// Discriminated unions for efficient parsing
final messageSchema = z.discriminatedUnion('type', [
  z.object({
    'type': z.literal('text'),
    'content': z.string(),
  }),
  z.object({
    'type': z.literal('image'),
    'url': z.string().url(),
    'alt': z.string().optional(),
  }),
  z.object({
    'type': z.literal('video'),
    'url': z.string().url(),
    'duration': z.number().positive(),
  }),
]);

// Add new variants
final extendedMessages = messageSchema.extend([
  z.object({
    'type': z.literal('audio'),
    'url': z.string().url(),
    'duration': z.number(),
  })
]);

// Remove specific variants
final restrictedMessages = messageSchema.exclude(['video']);

// Filter to specific variants only
final filteredMessages = messageSchema.discriminatorIn(['text', 'image']);

Example 11: Multi-stage Validation Pipelines #

// Multi-stage validation pipelines
final userPipeline = z.pipeline([
  z.string().transform((s) => s.trim()),
  z.string().min(2).max(50),
  z.string().refine((s) => !s.contains('admin')),
  z.string().transform((s) => s.toLowerCase()),
]);

// Add additional stages
final emailPipeline = userPipeline.pipe([z.string().email()]);

// Prepend a stage
final trimmedPipeline = userPipeline.prepend([z.string().trim()]);

// Insert stage at specific index
final modifiedPipeline = userPipeline.insertAt(1, [z.string().min(1)]);

// Replace stage at specific index
final replacedPipeline = userPipeline.replaceStageAt(0,
    z.string().transform((s) => s.trim().toLowerCase()));

Example 12: Enhanced Recursive Schemas #

// Enhanced recursive schemas with circular detection
final categorySchema = z.recursive<Map<String, dynamic>>(
      () =>
      z.object({
        'name': z.string(),
        'children': z.array(z.recursive<Map<String, dynamic>>(
                () =>
                z.object({
                  'name': z.string(),
                })
        )).optional(),
      }),
  maxDepth: 100, // Prevent infinite recursion
  enableCircularDetection: true, // Detect circular references
  enableMemoization: true, // Cache validation results
);

// Modify settings with fluent API
final modifiedSchema = categorySchema
    .withMaxDepth(50) // Change max depth
    .withCircularDetection(false) // Disable circular detection
    .withMemoization(false); // Disable memoization

Example 13: Automatic Type Coercion #

// Automatic type coercion
final numberCoercion = z.coerce.number(); // String -> Number
final booleanCoercion = z.coerce.boolean(); // String -> Boolean
final dateCoercion = z.coerce.date(); // String -> DateTime
final listCoercion = z.coerce.list(); // String -> List

// Strict coercion mode
final strictNumberCoercion = z.coerce.number(strict: true);

// Advanced number coercion with additional validation
final advancedNumber = z.coerce.number(strict: false)
    .transform((num) => double.parse(num.toStringAsFixed(2)))
    .refine((num) => num >= 0 && num <= 100, 
        message: 'Must be between 0 and 100');

⚡ Async Validation #

Example 14: Database Validation #

// Database validation example
final userSchema = z.object({
  'email': z.string().email().refineAsync(
    (email) async {
      final exists = await checkEmailExists(email);
      return !exists;
    },
    message: 'Email already exists',
  ),
  'username': z.string().min(3).refineAsync(
    (username) async {
      final available = await checkUsernameAvailable(username);
      return available;
    },
    message: 'Username not available',
  ),
});

Example 15: API Validation with External Service #

// API validation with external service
final apiSchema = z.string().url()
    .transformAsync((url) async {
      final response = await http.get(Uri.parse(url));
      return response.statusCode == 200 ? url : null;
    })
    .refineAsync(
      (result) async => result != null,
      message: 'URL is not accessible',
    );

Example 16: Async Validation Methods #

// Validate with async methods
final result = await userSchema.validateAsync({
  'email': 'user@example.com',
  'username': 'johndoe',
});

// Safe async parsing
final data = await userSchema.safeParseAsync(userData);
if (data != null) {
  print('Valid user: $data');
}

🔧 Enterprise Error Handling #

🎯 Advanced Error System #

Example 20: Error Code System #

// 100+ standardized error codes
final schema = z.string().email();
final result = schema.validate('invalid-email');

if (result.isFailure) {
  final errors = result.errors!;

  // Access error details
  for (final error in errors.errors) {
    print('Code: ${error.code}'); // ValidationErrorCode enum
    print('Message: ${error.message}'); // Human-readable message
    print('Path: ${error.fullPath}'); // Field path
    print('Expected: ${error.expected}'); // Expected value/type
    print('Received: ${error.received}'); // Actual value
    print('Context: ${error.context}'); // Additional context
  }

  // Error filtering (available methods)
  final emailErrors = errors.filterByPath(['email']);
  final typeErrors = errors.filterByCode(ValidationErrorCode.invalidEmail);

  // Basic error analysis
  print('Total errors: ${errors.errors.length}');
  print('Has errors: ${errors.hasErrors}');
  print('First error: ${errors.errors.first.message}');

  // Error codes analysis
  final errorCodes = errors.errors.map((e) => e.code).toSet();
  print('Unique error codes: $errorCodes');
}

🎨 Custom Error Formatting #

Example 21: Multiple Error Output Formats #

// Multiple error output formats
final errors = result.errors!;

// JSON format for APIs
final jsonErrors = errors.toJson();

print(jsonErrors);
// {"errors": [{"code": "invalid_email", "message": "Invalid email format", "path": ["email"]}]}

// Human-readable format (using available methods)
final readable = errors.formattedErrors;

print(readable);
// "ValidationError at email: Invalid email format (received: invalid-email, expected: valid email)"

// Individual error formatting
for (final error in errors.errors) {
  print('${error.fullPath}: ${error.message}');
}
// Output: "email: Invalid email format"

// Custom error collection analysis
final errorsByPath = <String, List<ValidationError>>{};
for (final error in errors.errors) {
  final path = error.fullPath;
  errorsByPath.putIfAbsent(path, () => []).add(error);
}
print('Errors by field: $errorsByPath');

🌐 Global Error Configuration #

Example 22: Global Error Configuration #

// Configure global error messages
ErrorMessages.setMessages({
  'invalid_email': 'Please enter a valid email address',
  'min_length': 'Must be at least {min} characters',
  'max_length': 'Must not exceed {max} characters',
});

// Custom error formatter
// Note: ErrorFormatter.setGlobalFormatter is not directly available in the current API
// Instead, use the error formatting methods on ValidationErrorCollection:
// errors.formattedErrors - for human-readable format
// errors.toJson() - for JSON format

// Error context tracking
final context = ErrorContext.builder()
    .operation('user_registration')
    .source('api')
    .metadata({'userId': '123', 'timestamp': DateTime.now()})
    .build();

// Use the context with ErrorContext.withContext
final result = ErrorContext.withContext(context, () {
  return schema.validate('invalid');
});

🏗️ Schema Composition & Introspection #

📊 Schema Analysis #

Example 23: Schema Introspection #

// Schema introspection
final userSchema = z.object({
  'name': z.string().min(2).max(50),
  'email': z.string().email(),
  'age': z.number().min(18),
}).describe('User profile schema');

// Get schema information (using available methods)
print('Schema shape: ${userSchema.shape.keys}'); // Keys: [name, email, age]
print('Required fields: ${userSchema.requiredKeys}'); // {name, email, age}
print('Optional fields: ${userSchema.optionalKeys}'); // {}
print('Total fields: ${userSchema.shape.length}'); // 3

// Schema structure analysis
for (final entry in userSchema.shape.entries) {
  final field = entry.key;
  final schema = entry.value;
  final isRequired = userSchema.requiredKeys.contains(field);
  print('Field $field: ${schema.runtimeType} (required: $isRequired)');
}

// Schema comparison (manual equivalence check)
final otherSchema = z.object({
  'name': z.string().min(2).max(50),
  'email': z.string().email(),
  'age': z.number().min(18),
});
final sameKeys = userSchema.shape.keys.toSet()
    .difference(otherSchema.shape.keys.toSet()).isEmpty;
print('Schemas have same structure: $sameKeys');

🔧 Schema Transformation #

Example 24: Schema Transformation and Composition #

// Note: Branded types and readonly schemas are not directly available in the current API
// Instead, use type-safe wrappers or custom validation logic:

// Type-safe ID validation
final userIdSchema = z.string().cuid2().refine(
  (id) => id.startsWith('user_'),
  message: 'User ID must start with "user_"',
);

final productIdSchema = z.string().cuid2().refine(
  (id) => id.startsWith('product_'),
  message: 'Product ID must start with "product_"',
);

// Schema composition
final basicUserSchema = z.object({
  'name': z.string(),
  'email': z.string().email(),
});

final extendedUserSchema = basicUserSchema.extend({
  'age': z.number().min(18),
  'role': z.enum_(['admin', 'user']),
});

// Conditional schemas using discriminated union
final conditionalSchema = z.discriminatedUnion('role', [
  z.object({
    'role': z.literal('admin'),
    'name': z.string(),
    'permissions': z.array(z.string()),
  }),
  z.object({
    'role': z.literal('user'),
    'name': z.string(),
    'department': z.string(),
  }),
]);

📄 JSON Schema Generation #

Example 25: JSON Schema Generation #

// Generate JSON Schema for OpenAPI documentation
final userSchema = z.object({
  'id': z.string().cuid2(),
  'name': z.string().min(2).max(50),
  'email': z.string().email(),
  'age': z.number().min(18).optional(),
  'roles': z.array(z.enum_(['admin', 'user', 'guest'])),
}).describe('User account information');

// JSON Schema generation
final jsonSchema = userSchema.toJsonSchema();

print(jsonEncode(jsonSchema));
// Output:
// {
//   "type": "object",
//   "description": "User account information",
//   "properties": {
//     "id": {"type": "string", "pattern": "[a-z0-9]{25}"},
//     "name": {"type": "string", "minLength": 2, "maxLength": 50},
//     "email": {"type": "string", "format": "email"},
//     "age": {"type": "number", "minimum": 18},
//     "roles": {"type": "array", "items": {"enum": ["admin", "user", "guest"]}}
//   },
//   "required": ["id", "name", "email", "roles"]
// }

🚀 Performance & Optimization #

Caching & Memoization #

Example 26: Performance Optimization #

// Basic schema for repeated validations
final userSchema = z.object({
  'name': z.string().min(2).max(50),
  'email': z.string().email(),
});

// Lazy evaluation (available)
final expensiveSchema = z.lazy(() =>
    z.object({
      'data': z.array(z.string()).transform((data) => data.map((s) => s.trim()).toList()),
    })
);

// Recursive schema with built-in optimization
final treeSchema = z.recursive<Map<String, dynamic>>(
      () =>
      z.object({
        'value': z.string(),
        'children': z.array(z.recursive<Map<String, dynamic>>(
                () =>
                z.object({
                  'value': z.string(),
                })
        )).optional(),
      }),
  maxDepth: 1000, // Prevent infinite recursion
  enableCircularDetection: true, // Detect circular references
  enableMemoization: true, // Cache validation results
);

📊 Performance Monitoring #

Example 27: Performance Monitoring #

// Performance optimization example
final schema = z.object({
  'users': z.array(z.object({
    'name': z.string(),
    'email': z.string().email(),
  })).min(1).max(1000),
});

// Measure validation performance manually
final stopwatch = Stopwatch()..start();
final result = schema.validate(data);
stopwatch.stop();

print('Validation time: ${stopwatch.elapsedMilliseconds}ms');

// Use recursive schemas with memoization for performance
final optimizedSchema = z.recursive<Map<String, dynamic>>(
  () => z.object({
    'value': z.string(),
    'children': z.array(z.lazy(() => optimizedSchema)).optional(),
  }),
  enableMemoization: true,
);

📚 Migration Guide #

🔄 From json_annotation #

Example 28: Migration from json_annotation #

// Before: json_annotation
@JsonSerializable()
class User {
  final String name;
  final String email;
  final int? age;

  User({required this.name, required this.email, this.age});

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);

  Map<String, dynamic> toJson() => _$UserToJson(this);
}

// After: Dzod
final userSchema = z.object({
  'name': z.string().min(1),
  'email': z.string().email(),
  'age': z.number().min(0).optional(),
});

// Type-safe parsing with validation
final result = userSchema.validate(jsonData);
if (result.isSuccess) {
  final user = result.data!;
  print('User: ${user['name']} (${user['email']})');
}

🔄 From built_value #

Example 29: Migration from built_value #

// Before: built_value
abstract class User implements Built<User, UserBuilder> {
  String get name;

  String get email;

  int? get age;

  User._();

  factory User([void Function(UserBuilder) updates]) = _$User;
}

// After: Dzod
final userSchema = z.object({
  'name': z.string().min(1),
  'email': z.string().email(),
  'age': z.number().min(0).optional(),
});

// No code generation needed
final user = userSchema.parse(data);

🎯 Best Practices #

🔒 Security & Validation #

Example 30: Security Best Practices #

// Input sanitization
final sanitizedSchema = z.string()
    .trim() // Remove whitespace
    .max(1000) // Prevent DoS
    .refine(
      (value) => !value.contains('<script>'),
  message: 'XSS attempt detected',
);

// Rate limiting validation
final rateLimitedSchema = z.object({
  'email': z.string().email(),
  'message': z.string().max(5000),
}).refine(
      (data) => checkRateLimit(data['email'] as String),
  message: 'Rate limit exceeded',
);

// API key validation
final apiKeySchema = z.string()
    .length(32) // Exact length
    .hex() // Hexadecimal format
    .refineAsync(
      (key) => validateApiKey(key),
  message: 'Invalid API key',
);

🎨 Error Handling Best Practices #

Example 31: Comprehensive Error Handling #

// Comprehensive error handling
Future<void> handleUserInput(Map<String, dynamic> input) async {
  try {
    final result = await userSchema.validateAsync(input);

    if (result.isSuccess) {
      await processUser(result.data!);
    } else {
      final errors = result.errors!;

      // Log errors for debugging
      logger.warning('Validation failed', errors.formattedErrors);

      // Return user-friendly errors
      final userErrors = errors.formattedErrors;
      throw ValidationException(userErrors);
    }
  } catch (e) {
    // Handle unexpected errors
    logger.error('Unexpected validation error', e);
    throw ServerException('Validation failed');
  }
}

🌟 Advanced Examples #

🔐 Authentication Schema #

Example 32: Advanced Authentication Schema #


final authSchema = z.discriminatedUnion('method', [
  // Email/password authentication
  z.object({
    'method': z.literal('email'),
    'email': z.string().email(),
    'password': z.string().min(8).max(128),
  }),

  // OAuth authentication
  z.object({
    'method': z.literal('oauth'),
    'provider': z.enum_(['google', 'github', 'facebook']),
    'token': z.string().jwt(),
  }),

  // API key authentication
  z.object({
    'method': z.literal('apikey'),
    'key': z.string().length(32).hex(),
    'secret': z.string().length(64).hex(),
  }),
]);

// Validate different auth methods
final emailAuth = authSchema.parse({
  'method': 'email',
  'email': 'user@example.com',
  'password': 'securepassword123',
});

final oauthAuth = authSchema.parse({
  'method': 'oauth',
  'provider': 'google',
  'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
});

📊 Data Processing Pipeline #

Example 33: Multi-stage Data Processing #

// Multi-stage data processing
final dataProcessingPipeline = z.pipeline([
  // Stage 1: Parse JSON
  z.string().transform((json) => jsonDecode(json)),

  // Stage 2: Validate structure
  z.object({
    'users': z.array(z.object({
      'name': z.string(),
      'email': z.string(),
      'age': z.number(),
    })),
    'metadata': z.object({
      'version': z.string(),
      'timestamp': z.string().datetime(),
    }),
  }),

  // Stage 3: Transform data
  z.object({
    'users': z.array(z.object({
      'name': z.string(),
      'email': z.string().email(),
      'age': z.number().min(0).max(150),
    })),
  }).transform((data) =>
  {
    'processedUsers': data['users'],
    'count': (data['users'] as List).length,
    'processedAt': DateTime.now().toIso8601String(),
  }),

  // Stage 4: Final validation
  z.object({
    'processedUsers': z.array(z.object({
      'name': z.string().min(1),
      'email': z.string().email(),
      'age': z.number().min(0),
    })),
    'count': z.number().min(0),
    'processedAt': z.string().datetime(),
  }),
]);

// Process data through pipeline
final result = dataProcessingPipeline.validate(rawJsonData);

🛠️ Development Tools #

🔧 Schema Testing Utilities #

Example 34: Testing Schema Validation #

// Test schema with sample data
void testUserSchema() {
  final schema = z.object({
    'name': z.string().min(2).max(50),
    'email': z.string().email(),
    'age': z.number().min(18),
  });

  // Test valid data
  final validData = {
    'name': 'John Doe',
    'email': 'john@example.com',
    'age': 25,
  };
  assert(schema.validate(validData).isSuccess);

  // Test invalid data
  final invalidData = {
    'name': 'J', // Too short
    'email': 'invalid-email',
    'age': 17, // Too young
  };
  final result = schema.validate(invalidData);
  assert(result.isFailure);
  assert(result.errors!.errors.length == 3);
}

📄 Schema Documentation Generator #

Example 35: Generate Schema Documentation #

// Generate documentation for your schemas
final userSchema = z.object({
  'id': z.string().cuid2().describe('Unique user identifier'),
  'name': z.string().min(2).max(50).describe('User full name'),
  'email': z.string().email().describe('User email address'),
  'age': z.number().min(18).describe('User age in years'),
  'roles': z.array(z.enum_(['admin', 'user', 'guest']))
      .describe('User roles and permissions'),
}).describe('User account schema');

// Generate JSON Schema documentation
final jsonSchema = userSchema.toJsonSchema();

print(jsonEncode(jsonSchema));

// Generate human-readable documentation by introspecting the schema
print('User Schema Documentation:');
print('Description: ${userSchema.description}');
print('Required fields: ${userSchema.requiredKeys}');
print('Optional fields: ${userSchema.optionalKeys}');
for (final entry in userSchema.shape.entries) {
  print('  - ${entry.key}: ${entry.value.runtimeType}');
}

💡 Ready to validate with confidence? Get started with Dzod today!

🙏 Acknowledgments #

  • Heavily inspired by Zod - TypeScript-first schema validation with static type inference
  • Built with ❤️ for the Dart/Flutter community
  • Special thanks to all contributors and early adopters

🔗 Connect with NonStop #

Stay connected and get the latest updates!

LinkedIn X.com Instagram YouTube Email


⭐ Star us on GitHub if this helped you!

📜 License #

This project is licensed under the MIT License - see the LICENSE file for details.

🎉 Founded by Ajay Kumar 🎉**

0
likes
160
points
6
downloads

Publisher

verified publisherdart.nonstopio.com

Weekly Downloads

A powerful Dart schema validation library inspired by Zod, providing type-safe validation, parsing, and inference with excellent developer experience.

Repository (GitHub)
View/report issues

Documentation

Documentation
API reference

License

MIT (license)

Dependencies

flutter

More

Packages that depend on dzod