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

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

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

Parse unstructured data from APIs, Flutter forms, config files, and more — with type safety and static type inference.

Inspired by Zod, ZodArt provides a powerful, expressive API to define validation schemas and parse unknown data into strongly typed Dart values.

Features #

  • Define schemas for primitive and complex types
  • Parse unknown/unstructured data into strongly typed Dart values
  • Easy to integrate with freezed models
  • Composable and reusable schemas — easily reuse schemas across your app
  • Supports nested objects, arrays, optional/nullable fields
  • Built-in validation rules
  • Rich, localizable error messages
  • Works great with REST APIs, GraphQL, JSON files, user input

Usage #

Try ZodArt right now in DartPad (TODO)!

Simple example without freezed #

import 'package:zodart/zodart.dart';

/// Person class used in the example below
///
/// Automatic fromJson method generation is planned for a future release.
/// A class generated with the `freezed` package can also be used here
class Person {
  final String firstName;
  final String lastName;
  final int? age;
  final bool? disabled;

  Person({
    required this.firstName,
    required this.lastName,
    this.age,
    this.disabled,
  });

  factory Person.fromJson(Map<String, dynamic> json) {
    return Person(
      firstName: json['firstName'] as String,
      lastName: json['lastName'] as String,
      age: json['age'] as int?,
      disabled: json['disabled'] as bool?,
    );
  }

  @override
  String toString() {
    return 'Person(firstName: $firstName, lastName: $lastName, age: $age, disabled: $disabled)';
  }
}

/// Schema defined using ZodArt
///
/// Validates that:
/// - `firstName` is from 1 to 20 characters long
/// - `lastName` is from 1 to 30 characters long
/// - `age` is greater or equal to 0 (can be omitted)
/// - `disabled` is present, but can be null
final personSchema = ZObject.withMapper(
  {
    'firstName': ZString().min(1).max(20),
    'lastName': ZString().min(1).max(30),
    'age': ZInt().optional().min(0),
    'disabled': ZBool().nullable(),
  },
  // Mapper required to create the `Person` instance (you can use Freezed `fromJson` here)
  fromJson: Person.fromJson,
);

void main() {
  final res = personSchema.parse({'firstName': 'Zod', 'lastName': 'Art', 'disabled': null});

  print(res.isError); // false
  print(res.isSuccess); // true
  print(res.value); // Person(firstName: Zod, lastName: Art, age: null, disabled: null)
}

Reusing and composing schemas #

Define smaller schemas and compose them into complex ones:

/// The String cannot be empty and is trimmed after the parse
final minSchema = ZString().trim().min(1);

/// Extends the [minSchema] and adds rule that the String must be max 10 characters long
final minMaxSchema = minSchema.max(10);

/// Extends the [minMaxSchema] and adds rule that the String can be `null`
final minMaxNullableSchema = minMaxSchema.nullable();

/// Extends the [minMaxNullableSchema] and conversion from String to Int in the end
final composedNullableIntSchema = minMaxNullableSchema.toInt();

/// Object schema composed from previously defined schemas, returns a Dart Record (String, int)
final objSchema = ZObject<(String, int)>.withMapper(
  {
    'str': minSchema,
    'int': composedNullableIntSchema,
  },
  fromJson: (map) => (map['str'], map['int']),
);

void main() {
  // Returns: true (empty string after trim, violates min(1) rule)
  print(minSchema.parse('     ').isError);

  // Returns: 'ZodArt'
  print(minSchema.parse(' ZodArt  ').value);

  // Returns: 'ZodArt'
  print(minMaxSchema.parse(' ZodArt ').value);

  // Returns: true
  print(minMaxNullableSchema.parse(null).isSuccess);

  // Returns: 105
  print(composedNullableIntSchema.parse(' 105  ').value);

  // Returns: true
  print(composedNullableIntSchema.parse(null).isSuccess);

  // Returns error message: Failed to parse value 'ZodArt', from String to int.
  print(composedNullableIntSchema.parse('ZodArt').issueSummary);

  // Returns: ('ZodArt', 100)
  print(objSchema.parse({'str': 'ZodArt', 'int': ' 100 '}).value);
}

Explore the example/ folder — ready-to-use snippets you can copy into your project.

Additional information #

This package is under active development. 🚀

You can check the planned features and report bugs or feature requests by opening an issue on the GitHub page.

2
likes
0
points
304
downloads

Publisher

verified publishermergepanic.com

Weekly Downloads

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

Repository (GitHub)
View/report issues

Topics

#parsing #validation #form-validation #schema #type-safe

License

unknown (license)

Dependencies

fpdart, freezed, freezed_annotation, json_annotation, meta, very_good_analysis

More

Packages that depend on zodart