JSON and Serialization

33.1 Manual JSON

import 'dart:convert';

class User {
  final int id;
  final String name;
  final String? email;
  final List<String> roles;

  const User({required this.id, required this.name, this.email, this.roles = const []});

  factory User.fromJson(Map<String, dynamic> json) => User(
        id: json['id'] as int,
        name: json['name'] as String,
        email: json['email'] as String?,
        roles: (json['roles'] as List<dynamic>? ?? []).cast<String>(),
      );

  Map<String, dynamic> toJson() => {
        'id': id,
        'name': name,
        if (email != null) 'email': email,
        'roles': roles,
      };
}

void main() {
  const raw = '{"id": 1, "name": "Ana", "roles": ["admin"]}';
  final user = User.fromJson(jsonDecode(raw) as Map<String, dynamic>);
  print(jsonEncode(user));                                     // calls toJson()
  print(const JsonEncoder.withIndent('  ').convert(user.toJson()));
  final users = (jsonDecode('[{"id":1,"name":"A"}]') as List)
      .map((e) => User.fromJson(e as Map<String, dynamic>))
      .toList();
}

33.2 Pattern-Based JSON Validation (Dart 3)

For large or deeply nested models, use code generation (Module 35). For huge payloads, parse in an isolate.

User? parseUser(Object? json) => switch (json) {
      {'id': int id, 'name': String name, 'email': String? email} =>
        User(id: id, name: name, email: email),
      _ => null,
    };