Есть ли у вас опыт работы с пакетом json_serializable в Dart/Flutter?

«Есть ли у вас опыт работы с пакетом json_serializable в Dart/Flutter?» — вопрос из категории Сети, который задают на 29% собеседований Flutter Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Да, я активно использую json_serializable вместе с json_annotation для сериализации и десериализации JSON в своих Flutter-проектах. Это стандартный подход для работы с API-ответами, который заменяет ручное написание fromJson/toJson на кодогенерацию, что делает код чище и менее подверженным ошибкам.

Типичный workflow в моих проектах:

  1. Определяю модель данных с аннотациями.
  2. Запускаю генератор кода (build_runner).
  3. Использую сгенерированные методы.

Пример модели пользователя:

import 'package:json_annotation/json_annotation.dart';

part 'user.g.dart'; // Файл, который сгенерирует build_runner

@JsonSerializable(explicitToJson: true) // explicitToJson для вложенных объектов
class User {
  final String name;
  final String email;
  @JsonKey(name: 'created_at') // Маппинг поля JSON с другим именем
  final DateTime createdAt;
  @JsonKey(defaultValue: 0) // Значение по умолчанию, если поля нет в JSON
  final int loginCount;
  List<Address> addresses; // Вложенная модель

  User({
    required this.name,
    required this.email,
    required this.createdAt,
    this.loginCount = 0,
    required this.addresses,
  });

  // Сгенерированные методы
  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
  Map<String, dynamic> toJson() => _$UserToJson(this);
}

// Для вложенной модели также нужна аннотация
@JsonSerializable()
class Address { ... }

Запуск кодогенерации: В терминале выполняю команду:

flutter pub run build_runner build --delete-conflicting-outputs

Флаг --delete-conflicting-outputs автоматически разрешает конфликты, что экономит время.

Интеграция с другими пакетами:

  • freezed: Часто использую вместе с json_serializable для создания неизменяемых (immutable) моделей с методами copyWith. Это мощная комбинация для DTO (Data Transfer Objects).
  • dio/retrofit: Сгенерированные модели напрямую используются для парсинга ответов от API.

Плюсы, которые я оценил:

  • Безопасность типов: Ошибки в именах полей или типах ловятся на этапе генерации.
  • Поддержка сложных сценариев: Кастомные конвертеры для DateTime, enum'ов, игнорирование полей (@JsonKey(ignore: true)).
  • Снижение boilerplate: Не нужно вручную писать и поддерживать методы сериализации для больших моделей.

Минус: Необходимость следить за сгенерированными файлами (они добавляются в .gitignore) и периодически перезапускать генератор при изменении моделей.