codec library

Type-safe and composable JSON codec abstraction.

Design Goals

  1. Failures throw CodecException: Codec.decode / Codec.encode return values directly and throw this package's independent CodecException hierarchy (DecodeException / EncodeException) on failure. Messages include PathSegment paths and DecodeErrorKind descriptions. Internally, failures stay value-based as DecodeOutcome so they can be accumulated, then convert to exceptions only at public exits. Use Codec.withFormatExceptions on the top-level codec for compatibility with existing on FormatException catch blocks.
  2. Codecs are first-class values: Codec.string, Codec.object(...), and other factories return passable, composable Codec instances. Chainable combinators such as .list(), .nullable(), .refine(), and .bimap() cover common transforms.
  3. Automatic path tracking: nested field, list element, and discriminated-branch errors include paths like $.user.contacts[2].phone.
  4. Advanced shapes are first-class: sealed unions use Codec.discriminated, recursive structures use Codec.lazy, and multi-version field compatibility uses Codec.firstOf.
  5. No third-party runtime dependencies: only the Dart SDK is required.

Package Structure

The implementation is split into responsibility-focused part files. Private _xxx types stay library-local; consumers access behavior through Codec factories and exported public types:

  • src/decode_error.dart — paths, error model, and accumulation strategy
  • src/decode_context.dart — decode context and decode-result algebra
  • src/codec_base.dartCodec base class, public API, and factories
  • src/primitives.dart — primitive const singleton codecs
  • src/combinators.dart — codec combinators
  • src/object_codec.dart — Object/Discriminated + FieldsReader DSL

Quick Start

final class UserModel {
  final String name;
  final String? avatar;
  final int age;
  const UserModel({required this.name, this.avatar, required this.age});

  static final Codec<UserModel> codec = Codec.object<UserModel>(
    (b) => UserModel(
      name: b.required('name', Codec.string),
      avatar: b.optional('avatar', Codec.string),
      age: b.optionalOr('age', Codec.integer, 0),
    ),
    encode: (u) => {
      'name': u.name,
      'avatar': u.avatar,
      'age': u.age,
    }.omitNulls,
  );

  factory UserModel.fromJson(Object? json) =>
      codec.decode(json, typeHint: 'UserModel');

  Object? toJson() => codec.encode(this);
}

Classes

BadFormat
Codable
Marks a class for codec_gen and emits a top-level _$xxxCodec field.
Codec<T>
Base class for codecs.
CodecEnum
Marks an enum for codec_gen and emits a top-level _$xxxCodec field.
CodecField
Field-level configuration.
CodecIgnore
Shorthand marker that makes codec_gen skip this field entirely.
CodecUnion
Marks a sealed/base union for codec_gen to emit Codec.discriminated.
CodecUnionCase
Marks the discriminator value for a union branch.
CodecValue
JSON mapping for one enum value.
CustomKind
DecodeContext
Runtime decode context: current value, path stack, and error mode.
DecodeError
Single field-level decode error.
DecodeErrorKind
Decode error category.
DecodeFail<T>
DecodeOk<T>
DecodeOutcome<T>
Internal decode-result algebra converted to CodecException by Codec.decode.
FailedRefinement
FieldsReader
Field reader passed to object decode builders.
IsNullField
MissingField
PathField
PathIndex
PathSegment
Immutable JSON path segment chain starting at the root ($).
UnexpectedError
Unexpected bare exception caught by the top-level decode guard.
UnknownTag
WrongType

Enums

DateTimeEpochUnit
Unit for numeric epoch values.
DateTimeMode
DateTime codec mode used by @CodecField(...).
ErrorMode
Error accumulation strategy.
FieldRename
Field rename strategy.

Extensions

MapOmitNulls on Map<String, V?>
Returns a new map without entries whose value is null.

Exceptions / Errors

CodecException
Root codec exception type.
DecodeException
Decode failure caused by JSON that does not match the model contract.
EncodeException
Encode failure caused by the Dart object or codec implementation.