devstory

Parsing JSON avec dart:convert

  1. dart:convert
  2. jsonDecode(..)
  3. jsonEncode(..)

1. dart:convert

Dans de nombreuses applications Dart/Flutter, vous devez travailler assez souvent avec des données au format JSON. Dans cet article, on va apprendre à utiliser la bibliothèque dart:convert pour analyser manuellement les données JSON. Il s'agit d'une bibliothèque intégrée à Dart et convient aux petits projets.
Pour les applications avec des modèles JSON plus complexes, l'utilisation de dart:convert peut rapidement devenir fastidieuse, répétitive et entraîner de nombreuses petites erreurs. Dans ce cas, vous devez utiliser la bibliothèque dart_json_mapper ou json_serializable.
Bien qu'il existe maintenant de nombreuses bibliothèques Dart JSON fournies par la communauté, elles ne sont pas aussi diverses que Java. Vous pouvez poser la question "Existe-t-il une bibliothèque équivalente à GSON/Jackson/Moshi de Java ?". La réponse est oui, c'est dart_json_mapper.
En tant que bibliothèque simple, dart:convert ne nécessite aucune configuration supplémentaire et c'est la première bibliothèque de traitement JSON à laquelle vous devez penser, pour les petits projets.
Certaines fonctions sont fournies par la bibliothèque dart:convert :
dynamic jsonDecode(String source,  {Object? reviver(Object? key, Object? value)?})
String jsonEncode(Object? object, {Object? toEncodable(Object? nonEncodable)?})

2. jsonDecode(..)

dynamic jsonDecode(String source,  {Object? reviver(Object? key, Object? value)?})
La fonction jsonDecode() est utilisée pour analyser un texte JSON et retourner un objet Dart. Cette fonction renvoie un type dynamic. Ce type de retour peut être :
  • Map<String,dynamic>
  • List<dynamic>
  • Un objet Dart si le paramètre reviver n'est pas null (voir un exemple ci-dessous).
Les paramètres :
  • source: Un texte en format JSON.
  • reviver: Une fonction facultative convoquée pour chaque propriété trouvée lors de l'analyse de ce texte JSON. Le paramètre [key=null] correspond à l'objet JSON global. Les propriétés de niveau feuille seront exécutées en premier, les propriétés de niveau racine seront exécutées en dernier.
Par exemple : La fonction jsonDecode() renvoie une Map<String,dynamic>:
json_jsonDecode_ex1.dart
import 'dart:convert';

void main() {
  var jsonString = '''{
        "name": "John Smith",
        "email": "john@example.com",
        "salary": 5000,
        "addresses": ["Address 1", "Address 2"]
      }''';  
  Map<String, dynamic> map = jsonDecode(jsonString);

  for (var key in map.keys) {
    print('$key --> ${map[key]}');
  }
  print(' --- ');
 
  List<dynamic> addresses =  map['addresses'];
  for(String address in addresses) {
     print('Address: $address');
  }
}
Output:
name --> John Smith
email --> john@example.com
salary --> 5000
addresses --> [Address 1, Address 2]
 ---
Address: Address 1
Address: Address 2
Un autre exemple avec JSON plus complexe :
json_jsonDecode_ex2.dart
import 'dart:convert';

void main() {
  var jsonString = '''{
        "name": "John Smith",
        "email": "john@example.com",
        "children": [ {
            "name": "Jack Smith",
            "email": "jack@example.com"
        }, {
            "name": "Harry Smith",
            "email": "harry@example.com"
        }]
      }''';
  Map<String, dynamic> map = jsonDecode(jsonString);

  for (var key in map.keys) {
    print('$key --> ${map[key]}');
  }
  print(' --- ');

  List<dynamic> children = map['children'];
  for (dynamic child in children) {
    var childMap = child as Map<String, dynamic>;
    for (var k in childMap.keys) {
      print('  $k --> ${childMap[k]}');
    }
  }
}
Output:
name --> John Smith
email --> john@example.com
children --> [{name: Jack Smith, email: jack@example.com}, {name: Harry Smith, email: harry@example.com}]
 ---
  name --> Jack Smith
  email --> jack@example.com
  name --> Harry Smith
  email --> harry@example.com
Exemple : La fonction jsonDecode() renvoie une List<dynamique> :
json_jsonDecode_ex2.dart
import 'dart:convert';
void main() {
  var jsonString = '''[ {
            "name": "Jack Smith",
            "email": "jack@example.com"
        }, {
            "name": "Harry Smith",
            "email": "harry@example.com"
        }]''';
  List<dynamic> list = jsonDecode(jsonString);

  for (var element in list) {
    var map = element as Map<String, dynamic>;
    for (var k in map.keys) {
      print('$k --> ${map[k]}');
    }
  }
}
Output:
name --> Jack Smith
email --> jack@example.com
name --> Harry Smith
email --> harry@example.com
Exemple : Utiliser la fonction jsonDecode() avec le paramètre reviver pour convertir un texte JSON en objet Dart.
json_jsonDecode_reviver_ex1.dart
import 'dart:convert';

void main() {
  var jsonString = '''{
        "name": "John Smith",
        "email": "john@example.com",
        "contact": {
           "address": "Address 1",
           "phone": "12345"
        }  
      }''';

  Employee emp = jsonDecode(jsonString, reviver: (k, v) {
    if (v is Map) {
      if (k == 'contact') {
        var contactRaw = v as Map<String, dynamic>;
        return Contact.fromRaw(contactRaw);
      } else {
        // k == null
        var empRaw = v as Map<String, dynamic>;
        return Employee.fromRaw(empRaw);
      }
    }
    return v;
  });

  print('Emp Name: ${emp.name}');
  print('Emp Email: ${emp.email}');
  print('Address: ${emp.contact.address}');
}

class Contact {
  String address;
  String phone;
  Contact(this.address, this.phone); // Constructor
  Contact.fromRaw(Map<String, dynamic> map) // Constructor
      : address = map['address'],
        phone = map['phone'];
}

class Employee {
  String name;
  String email;
  Contact contact;
  Employee(this.name, this.email, this.contact); // Constructor
  Employee.fromRaw(Map<String, dynamic> map) // Constructor
      : name = map['name'],
        email = map['email'],
        contact = map['contact'];
}
Output:
Emp Name: John Smith
Emp Email: john@example.com
Address: Address 1

3. jsonEncode(..)

String jsonEncode(Object? object, {Object? toEncodable(Object? nonEncodable)?})
La fonction jsonEncode() est utilisée pour convertir un objet Dart en un texte JSON.
Les paramètres :
  • object: Un objet Dart.
  • toEncodable: Une fonction facultative utilisée pour convertir des objets Dart non encodables en objets encodables. Si ce paramètre n'est pas fourni, la fonction toJson() sera utilisée comme alternative.
Exemple : Un objet Dart avec toutes les propriétés encodables (Encodable) :
// An Encodable object:
var employee = {
  'name': 'John Smith',
  'email': 'john@example.com',
  'contact': {
    'address': 'Address 1',
    'phone': '12345'}
};
Exemple : Un objet Dart avec plusieurs propriétés encodables et une propriété non encodable :
var employee = {
  'name': 'John Smith', // Encodable
  'email': 'john@example.com', // Encodable
  'contact': Contact('Address 1', '12345') // Unencodable!!!
};
Exemple : L'utilisation de la fonction jsonEncode() pour convertir un objet Dart en texte JSON :
json_jsonEncode_ex1.dart
import 'dart:convert';

void main() {
  // An Object (Looks like a JSON):
  var employee = {
    'name': 'John Smith',
    'email': 'john@example.com',
    'contact': {
      'address': 'Address 1',
      'phone': '12345'}
  };
  var jsonString = jsonEncode(employee);
  print(jsonString);
}
Output:
{"name":"John Smith","email":"john@example.com","contact":{"address":"Address 1","phone":"12345"}}
Exemple : La conversion d'un objet Map en texte JSON :
json_jsonEncode_ex2.dart
import 'dart:convert';

void main() {
  var map = Map<String,dynamic>();
    
  map['name'] = 'John Smith';
  map['email'] = 'john@example.com';

  var jsonString = jsonEncode(map);
  print(jsonString);
}
Output:
{"name":"John Smith","email":"john@example.com"}
Exemple : L'utilisation de la fonction jsonEncode() avec le paramètre toEncodable :
json_jsonEncode_toEncodable_ex1.dart
import 'dart:convert';
void main() {
  var contact = Contact('Address 1', '12345');
  var employee = {
    'name': 'John Smith', // Encodable
    'email': 'john@example.com', // Encodable
    'contact': contact // Un-encodable!!!
  };
  var jsonString = jsonEncode(employee, toEncodable: (nonEncodable) {
    if (nonEncodable is Contact) {
      return {
        'address': nonEncodable.address,
        'phone': nonEncodable.phone
      };
    }
    return null;
  });
  print(jsonString);
}

class Contact {
  String address;
  String phone;
  Contact(this.address, this.phone); // Constructor
}
Output:
{"name":"John Smith","email":"john@example.com","contact":{"address":"Address 1","phone":"12345"}}
Exemple : L'utilisation de la fonction jsonEncode() avec le paramètre toEncodable :
json_jsonEncode_toEncodable_ex2.dart
import 'dart:convert';

void main() {
  var contact = Contact('Address 1', '12345');
  var employee = Employee('John Smith', 'john@example.com', contact);

  var jsonString = jsonEncode(employee, toEncodable: (nonEncodable) {
    if (nonEncodable is Contact) {
      return {
        'address': nonEncodable.address,
        'phone': nonEncodable.phone
      };
    } else if(nonEncodable is Employee) {
       return {
           'name': nonEncodable.name,
           'email': nonEncodable.email,
           'contact': nonEncodable.contact
       };
    }
  });
  print(jsonString);
}

class Contact {
  String address;
  String phone;
  Contact(this.address, this.phone); // Constructor
}

class Employee {
  String name;
  String email;
  Contact contact;
  Employee(this.name, this.email, this.contact); // Constructor
}