DevToolBoxGRATUIT
Blog

JSON vers Dart : Guide complet des classes modèles Flutter

10 min de lecturepar DevToolBox

La conversion de JSON en classes Dart est l'une des tâches les plus courantes en développement Flutter. Que vous récupériez des données depuis une API REST ou lisiez une configuration locale, vous avez besoin de classes Dart bien structurées.

Pourquoi les classes modèles

Correspondance des types JSON vers Dart

Type JSONType DartExemple
stringString"hello" → "hello"
number (int)int42 → 42
number (float)double3.14 → 3.14
booleanbooltrue → true
nullNull / dynamicnull → null
arrayList<T>[1,2,3] → [1,2,3]
objectMap / Class{} → User()

Classe modèle manuelle (fromJson / toJson)

L'approche la plus directe est d'écrire les classes à la main :

// JSON input
{
  "id": 1,
  "name": "John Doe",
  "email": "john@example.com",
  "isActive": true,
  "score": 95.5
}

// Dart model class
class User {
  final int id;
  final String name;
  final String email;
  final bool isActive;
  final double score;

  User({
    required this.id,
    required this.name,
    required this.email,
    required this.isActive,
    required this.score,
  });

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'] as int,
      name: json['name'] as String,
      email: json['email'] as String,
      isActive: json['isActive'] as bool,
      score: (json['score'] as num).toDouble(),
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'name': name,
      'email': email,
      'isActive': isActive,
      'score': score,
    };
  }
}

Gestion des objets imbriqués

Créez des classes Dart séparées pour chaque niveau d'imbrication :

// JSON with nested object
{
  "id": 1,
  "name": "John",
  "address": {
    "street": "123 Main St",
    "city": "Springfield",
    "zipCode": "62701"
  }
}

// Dart classes
class Address {
  final String street;
  final String city;
  final String zipCode;

  Address({required this.street, required this.city, required this.zipCode});

  factory Address.fromJson(Map<String, dynamic> json) {
    return Address(
      street: json['street'] as String,
      city: json['city'] as String,
      zipCode: json['zipCode'] as String,
    );
  }

  Map<String, dynamic> toJson() => {
    'street': street, 'city': city, 'zipCode': zipCode,
  };
}

class User {
  final int id;
  final String name;
  final Address address;

  User({required this.id, required this.name, required this.address});

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'] as int,
      name: json['name'] as String,
      address: Address.fromJson(json['address'] as Map<String, dynamic>),
    );
  }

  Map<String, dynamic> toJson() => {
    'id': id, 'name': name, 'address': address.toJson(),
  };
}

Gestion des listes

Les tableaux JSON correspondent au type List de Dart :

// JSON with arrays
{
  "name": "John",
  "hobbies": ["coding", "reading", "gaming"],
  "orders": [
    {"id": 1, "product": "Laptop", "price": 999.99},
    {"id": 2, "product": "Mouse", "price": 29.99}
  ]
}

// Dart
class User {
  final String name;
  final List<String> hobbies;
  final List<Order> orders;

  User({required this.name, required this.hobbies, required this.orders});

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      name: json['name'] as String,
      hobbies: List<String>.from(json['hobbies'] as List),
      orders: (json['orders'] as List)
          .map((e) => Order.fromJson(e as Map<String, dynamic>))
          .toList(),
    );
  }
}

Bonnes pratiques Null Safety

Avec le null safety de Dart, gérez correctement les champs nullable :

  • Utilisez `required` pour les champs obligatoires
  • Utilisez le suffixe `?` pour les types nullable
  • Fournissez des valeurs par défaut avec `??`
  • Utilisez `late` uniquement quand la valeur sera initialisée
class User {
  final int id;
  final String name;
  final String? bio;        // nullable
  final String avatarUrl;   // with default

  User({
    required this.id,
    required this.name,
    this.bio,
    this.avatarUrl = 'https://example.com/default-avatar.png',
  });

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'] as int,
      name: json['name'] as String,
      bio: json['bio'] as String?,
      avatarUrl: json['avatarUrl'] as String? ?? 'https://example.com/default-avatar.png',
    );
  }
}

Utiliser json_serializable

Pour les grands projets, json_serializable automatise le code répétitif :

Étape 1 : Ajouter les dépendances

# pubspec.yaml
dependencies:
  json_annotation: ^4.8.1

dev_dependencies:
  json_serializable: ^6.7.1
  build_runner: ^2.4.6

Étape 2 : Créer le modèle avec annotations

import 'package:json_annotation/json_annotation.dart';

part 'user.g.dart';

@JsonSerializable()
class User {
  final int id;
  final String name;
  final String email;

  @JsonKey(name: 'is_active')
  final bool isActive;

  @JsonKey(defaultValue: 0.0)
  final double score;

  User({
    required this.id,
    required this.name,
    required this.email,
    required this.isActive,
    required this.score,
  });

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
  Map<String, dynamic> toJson() => _$UserToJson(this);
}

Étape 3 : Exécuter Build Runner

dart run build_runner build --delete-conflicting-outputs

Utiliser Freezed pour les modèles immuables

Le package freezed génère des classes immuables avec copyWith et sérialisation JSON :

import 'package:freezed_annotation/freezed_annotation.dart';

part 'user.freezed.dart';
part 'user.g.dart';

@freezed
class User with _$User {
  const factory User({
    required int id,
    required String name,
    required String email,
    @Default(false) bool isActive,
  }) = _User;

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
}

Erreurs courantes et solutions

ErreurSolution
Utiliser `json['key']` sans vérification nullUtiliser `json['key'] as String? ?? ''`
Oublier de convertir les objets imbriquésAppeler `NestedClass.fromJson(json['key'])`
Utiliser `int` pour tous les nombresUtiliser `num` et convertir
Ne pas gérer les clés manquantesUtiliser `json.containsKey('key')`
Retourner le mauvais type dans toJsonS'assurer que les objets imbriqués appellent `.toJson()`

FAQ

Quelle est la meilleure façon de convertir JSON en classes Dart ?

Pour les petits projets, la conversion manuelle suffit. Pour les grands projets, utilisez json_serializable ou freezed.

Comment gérer les clés JSON dynamiques en Dart ?

Utilisez Map<String, dynamic>.

json_serializable ou freezed ?

json_serializable pour la sérialisation simple, freezed pour l'immuabilité et copyWith.

Comment gérer les dates ?

Utilisez DateTime.parse() pour les chaînes ISO 8601.

𝕏 Twitterin LinkedIn
Cet article vous a-t-il aidé ?

Restez informé

Recevez des astuces dev et les nouveaux outils chaque semaine.

Pas de spam. Désabonnez-vous à tout moment.

Essayez ces outils associés

DTJSON to Dart{ }JSON FormatterKTJSON to KotlinTSJSON to TypeScript

Articles connexes

Syntaxe YAML et validation : Erreurs courantes et solutions

Maîtrisez la syntaxe YAML : règles d'indentation, erreurs de parsing, types de données et bonnes pratiques.

JSON vers Kotlin Data Class : Guide kotlinx.serialization, Moshi et Gson

Convertir JSON en data class Kotlin en ligne. Apprenez le parsing JSON avec kotlinx.serialization, Moshi et Gson.