zodart 1.2.0 copy "zodart: ^1.2.0" to clipboard
zodart: ^1.2.0 copied to clipboard

Type-safe schema validation with static type inference and a parse-first design.

License: MIT Pub Points Code coverage GitHub open bugs GitHub next milestone details GitHub last commit

ZodArt

🎯 Parse-first schema validation with static type inference #

Parse unstructured data from APIs, Flutter forms, config files, and more β€” with type safety and static type inference. ZodArt provides a powerful, expressive API to define validation schemas and parse unknown data into strongly typed Dart values.

See ZodArt documentation for more info.

Simple example #

import 'package:zodart/zodart.dart';

/// The string’s length must be between 1 and 20
final minMaxSchema = ZString().trim().min(1).max(20);

/// Extends [minMaxSchema] to allow null values
final nullableSchema = minMaxSchema.nullable();

// 24-hour time format with a custom error message
final timeSchema = ZString().regex(
  r'^([01]\d|2[0-3]):[0-5]\d$',
  message: '⚠️ Invalid time format!',
);

// Helper function that sums a list of integers
int sum(List<int> ints) => ints.reduce((a, b) => a + b);

// A list of integers with at least one item
final intsSchema = ZArray(ZInt()).min(1);

void main() {
  final res = minMaxSchema.parse('  ZodArt ');

  // To check the parsed result, use `.isSuccess`
  if (res.isSuccess) {
    print('Success: ${res.value}');
  }
  // Or use the match method for a more functional style.
  res.match(
    (issues) => print('❌ Validation failed: ${issues.localizedSummary}'),
    (val) => print('🟒 Validation successful: $val'),
  );

  // Validate a nullable value
  print(nullableSchema.parse(null).value);

  // Regex validation with custom error message
  print(timeSchema.parse('23:9').issueSummary);

  // Transform the list of integers into a string
  final sumSchema = intsSchema.toStr((vals) => 'Sum: ${sum(vals)}');
  print(sumSchema.parse([1, 2, 3, 4]).value);
}

Complex example #

Even though ZodArt works perfectly without code generation, using it is highly recommended β€” it brings rock-solid type safety 🧬, greatly improves developer experience and significantly reduces boilerplate πŸš€. See full example with code generation or an example without code generation.

To start using the code generation set it up first and simplify schema creation with ZodArt Snippets for VS Code.

ZodArt Snippets extension

import 'package:zodart/zodart.dart';

part '<FILE_NAME>.zodart.dart';
part '<FILE_NAME>.zodart.type.dart';

// Item schema (automatically generates the Item class)
@ZodArt.generateNewClass(outputClassName: 'Item')
abstract class ItemSchema {
  /// Schema definition
  static final schema = (
    id: ZInt().min(1).max(9999),
    name: ZString().trim().min(1).max(20),
    makerName: ZString().process((val) => '$valπŸš€'), // append πŸš€ to the name
    notes: ZArray(ZString().min(1)).nullable(), // nullable list of notes
    price: ZDouble().min(0),
    archived: ZBool().optional(), // optional archived flag
  );

  // Access to generated helper methods like props list etc.
  static const z = _ItemSchemaUtils();
  static final ZObject<Item> zObject = z.zObject;
}

void main() {
  // Parse a map
  final res = ItemSchema.zObject.parse({
    'id': 7,
    'name': 'Cookie',
    'makerName': 'ZodArt',
    'price': 7.5,
    'notes': null,
  });

  res.match(
    (issues) => print('❌ Validation failed: ${issues.localizedSummary}'),
    (item) => print('🟒 Validation successful: $item'),
  );

  // To obtain only issues summary for `item.price` use `getSummaryFor`
  final priceIssueSummary = res.getSummaryFor(ItemSchemaProps.price.name);
  print('Item.price issue: $priceIssueSummary');
}