o7planning

Parsing JSON with dart:convert

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

1. dart:convert

In many Dart/Flutter applications, you quite often have to work with JSON-formatted data. In this article we will learn how to use the dart:convert library to manually parse JSON data. This is a built-in library in Dart and is suitable for small projects.
For applications with more complex JSON models, using dart:convert can quickly become tedious, repetitive, and lead to many small errors. In that case, you should use dart_json_mapper or json_serializable library.
Although there are many Dart JSON libraries provided by the community now, it is not as diverse as Java. You can ask the question "Is there any library equivalent to Java's GSON/Jackson/Moshi?". The answer is yes, it's dart_json_mapper.
As a simple library, dart:convert doesn't need any additional configuration and is the first JSON processing library you need to think about, for small projects.
Some functions are provided by the dart:convert library:
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)?})
The jsonDecode() function is used to parse a JSON text and return a Dart object. This function returns dynamic type. This return type can be:
  • Map<String,dynamic>
  • List<dynamic>
  • A Dart object if the reviver parameter is not null (see an example below).
Parameters:
  • source: A text in JSON format.
  • reviver: An optional function called for each property found during parsing this JSON text. The [key=null] parameter corresponds to the global JSON object. Leaf-level properties will be executed first, root-level properties will be executed last.
Example: The jsonDecode() function returns a 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
Next example with more complex JSON:
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
Example: The jsonDecode() function returns a List<dynamic>:
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
Example: Use the jsonDecode() function with the reviver parameter to convert a JSON text into a Dart object.
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)?})
The jsonEncode() function is used to convert a Dart object into a JSON text.
Parameters:
  • object: A Dart object.
  • toEncodable: An optional function used to convert non-encodable Dart objects into encodable objects. If this parameter is not provided, the toJson() function will be used as an alternative.
Example: A Dart object with all encodable properties:
// An Encodable object:
var employee = {
  'name': 'John Smith',
  'email': 'john@example.com',
  'contact': {
    'address': 'Address 1',
    'phone': '12345'}
};
Example: A Dart object with several encodable properties, and one non-encodable property:
var employee = {
  'name': 'John Smith', // Encodable
  'email': 'john@example.com', // Encodable
  'contact': Contact('Address 1', '12345') // Unencodable!!!
};
Example: Using the jsonEncode() function to convert a Dart object to JSON text:
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"}}
Example: Converting a Map object to JSON text:
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"}
Example: Using jsonEncode() function with toEncodable parameter:
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"}}
Example: Using jsonEncode() function with toEncodable parameter:
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
}