flutter-implement-json-serialization

Créez des classes modèles avec les méthodes `fromJson` et `toJson` en utilisant `dart:convert`. À utiliser pour mapper manuellement les clés JSON aux propriétés de classe pour des structures de données simples.

npx skills add https://github.com/flutter/skills --skill flutter-implement-json-serialization

Sérialisation manuelle de JSON en Flutter

Contenu

Principes fondamentaux

  • Importer dart:convert : Utilisez la bibliothèque intégrée dart:convert de Flutter pour l'encodage JSON manuel (jsonEncode) et le décodage (jsonDecode).
  • Appliquer la sécurité des types : Castez toujours le résultat dynamic de jsonDecode() vers le type attendu, généralement Map<String, dynamic> pour les objets ou List<dynamic> pour les tableaux.
  • Encapsuler la logique de sérialisation : Définissez des classes modèle simples contenant des propriétés correspondant à la structure JSON. Implémentez un constructeur factory fromJson et une méthode toJson dans le modèle.
  • Gérer l'analyse en arrière-plan : Si vous analysez des documents JSON volumineux (temps d'exécution > 16 ms), déportez la logique d'analyse vers un isolate séparé en utilisant la fonction compute() de Flutter pour éviter le saccadement de l'interface.
  • Lever des exceptions en cas d'erreur : Lors du traitement des réponses HTTP, levez une exception si le code de statut n'est pas réussi (par exemple, pas 200 OK ou 201 Created). Ne retournez pas null.

Workflow : Implémenter un modèle sérialisable

Utilisez cette checklist pour implémenter la sérialisation manuelle de JSON pour un modèle de données.

Progression des tâches :

  • [ ] Définir la classe modèle simple avec des propriétés final.
  • [ ] Implémenter le constructeur factory Model.fromJson(Map<String, dynamic> json).
  • [ ] Implémenter la méthode Map<String, dynamic> toJson().
  • [ ] Écrire des tests unitaires pour les deux méthodes de sérialisation.
  • [ ] Exécuter le validateur -> examiner les erreurs de type mismatch -> corriger la logique de casting.
  1. Définir le modèle : Créez une classe avec des propriétés correspondant aux clés JSON.
  2. Implémenter fromJson : Extrayez les valeurs de la Map et castez-les vers les types Dart appropriés. Utilisez le pattern matching ou un casting explicite.
  3. Implémenter toJson : Retournez une Map<String, dynamic> mappant les propriétés de la classe à leurs clés de chaîne JSON.
  4. Valider : Exécutez les tests unitaires pour vous assurer que la sécurité des types, l'autocomplétion et la gestion des exceptions au moment de la compilation fonctionnent correctement.

Workflow : Récupérer et analyser du JSON

Utilisez ce workflow conditionnel lors de la récupération et de l'analyse de JSON à partir d'une requête réseau.

Progression des tâches :

  • [ ] Exécuter la requête HTTP.
  • [ ] Valider le code de statut de la réponse.
  • [ ] Déterminer la stratégie d'analyse (Synchrone vs. Isolate).
  • [ ] Décoder et mapper le JSON vers le modèle.
  1. Exécuter la requête : Utilisez le package http pour effectuer l'appel réseau.
  2. Valider la réponse :
    • Si response.statusCode == 200 (ou 201 pour POST), procédez à l'analyse.
    • Si le code de statut indique une erreur, levez une Exception.
  3. Déterminer la stratégie d'analyse :
    • Si vous analysez une charge utile petite (par exemple, un seul objet), analysez de manière synchrone sur le thread principal.
    • Si vous analysez une charge utile volumineuse (par exemple, un tableau de milliers d'objets), utilisez compute(parseFunction, response.body) pour analyser dans un isolate en arrière-plan.
  4. Décoder et mapper : Passez le JSON décodé au constructeur fromJson de votre modèle.

Exemples

Implémentation de modèle haute fidélité

import 'dart:convert';

class User {
  final int id;
  final String name;
  final String email;

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

  // Factory constructor for deserialization
  factory User.fromJson(Map<String, dynamic> json) {
    return switch (json) {
      {
        'id': int id,
        'name': String name,
        'email': String email,
      } => 
        User(
          id: id,
          name: name,
          email: email,
        ),
      _ => throw const FormatException('Failed to load User.'),
    };
  }

  // Method for serialization
  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'name': name,
      'email': email,
    };
  }
}

Analyse synchrone (charge utile petite)

import 'dart:convert';
import 'package:http/http.dart' as http;

Future<User> fetchUser(http.Client client, int userId) async {
  final response = await client.get(
    Uri.parse('https://api.example.com/users/$userId'),
    headers: {'Accept': 'application/json'},
  );

  if (response.statusCode == 200) {
    // Decode returns dynamic, cast to Map<String, dynamic>
    final Map<String, dynamic> jsonMap = jsonDecode(response.body) as Map<String, dynamic>;
    return User.fromJson(jsonMap);
  } else {
    throw Exception('Failed to load user');
  }
}

Analyse en arrière-plan (charge utile volumineuse)

import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;

// Top-level function required for compute()
List<User> parseUsers(String responseBody) {
  final parsed = (jsonDecode(responseBody) as List<dynamic>).cast<Map<String, dynamic>>();
  return parsed.map<User>((json) => User.fromJson(json)).toList();
}

Future<List<User>> fetchUsers(http.Client client) async {
  final response = await client.get(
    Uri.parse('https://api.example.com/users'),
    headers: {'Accept': 'application/json'},
  );

  if (response.statusCode == 200) {
    // Offload expensive parsing to a background isolate
    return compute(parseUsers, response.body);
  } else {
    throw Exception('Failed to load users');
  }
}

Skills similaires