Working with JSON

Working with JSON #

Manual serialization #

Decoding #

In Dart we can deserialize JSON using jsonDecode function from the dart:convert library.

The function has a return type of dynamic, which means that Dart can’t tell what type it is before running the the application.

It is important to know how types a treated when working with JSON. Here are some examples you can play around with:

import 'dart:convert';

final json = '''{
    "id": 35,
    "categories": ["Programming","Geeky"],
    "joke": "There are only 10 kinds of people in this world: those who know binary and those who don't.",
    "flags": {
        "explicit": false
    }
}''';

void main() {
  final data1 = jsonDecode(json);
  print(data1.toString());
  print("\nRuntime type: ${data1.runtimeType}");
  print("Can I use it as a Map? ${data1 is Map}");

  print("Can I use it as a Map<String, dynamic>? ${data1 is Map<String, dynamic>}");
  print("Can I use it as a Map<String, Object>? ${data1 is Map<String, Object>}");
  print("\n");

  final categories = data1['categories'];
  print('The field "categories": $categories');
  print('Runtime type: ${categories.runtimeType}');
  print('Is it a List<dynamic>? ${categories is List<dynamic>}');
  print('Is it a List<String>? ${categories is List<String>}');
  print('Is first element a String? ${categories[0] is String}');
}

Encoding #

For serialization to JSON we can use jsonEncode.

It works fine for the following types:

  • num, int, double
  • bool
  • String
  • List
  • Map
import 'dart:convert';

void main() {
    final data = {
        "id": 35,
        "categories": ["Programming","Geeky"],
        "joke": "There are only 10 kinds of people in this world: those who know binary and those who don't.",
        "flags": {
            "explicit": false
        }
    };
    final json = jsonEncode(data);
    print(json);
}

Notice how similar Dart literals are to JSON.

You can make the JSON more readable to humans with JsonEncoder.withIndent('\t').convert.

import 'dart:convert';

void main() {
    final data = { "id": 35, "categories": ["Programming","Geeky"], "joke": "There are only 10 kinds of people in this world: those who know binary and those who don't.", "flags": { "explicit": false } };
    final json = JsonEncoder.withIndent('\t').convert(data);
    print(json);
}

Data transfer objects #

What if we want to work with classes? We don’t get classes back when deserializing. And we can not serialize classes directly.

Attempting to do so, gives us a nasty error.

import 'dart:convert';

class JokeDto {
  int? id;
  List<String>? categories;
  String? setup;
  String? delivery;

  JokeDto({this.id, this.categories, this.setup, this.delivery});
}

void main() {
  final joke = JokeDto(
    id: 1,
    categories: ["Programming"],
    setup: ".NET developers are picky when it comes to food.",
    delivery: "They only like chicken NuGet.",
  );
  jsonEncode(joke);
}

Instead we need some methods to convert between Map<String, dynamic> and our DTO.

It is common to put those conversion methods in the DTO class.

import 'dart:convert';

const json = '''{
    "id": 49,
    "categories": [
        "Programming"
    ],
    "setup": ".NET developers are picky when it comes to food.",
    "delivery": "They only like chicken NuGet."
}''';

class JokeDto {
  int? id;
  List<String>? categories;
  String? setup;
  String? delivery;

  JokeDto({this.id, this.categories, this.setup, this.delivery});

  JokeDto.fromJson(Map<String, dynamic> json) {
    id = json['id'];
    categories = json['categories']?.cast<String>();
    setup = json['setup'];
    delivery = json['delivery'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['id'] = this.id;
    data['categories'] = this.categories;
    data['setup'] = this.setup;
    data['delivery'] = this.delivery;
    return data;
  }
}

void main() {
  final dto = JokeDto.fromJson(jsonDecode(json));
  print(dto);

  print(jsonEncode(dto.toJson()));
}

Wondering why the methods are called fromJson and toJson when they work with Map type? It is just a convention that people in the Dart community use.

The convention implies that fromJson is compatible with jsonDecode and toJson with jsonEncode.

Automatic serialization (using code generation libraries) #

This is a subject for later. Here are some emojies instead.

πŸ§’ 🍷 πŸš— πŸ›£οΈ πŸš” 🎫

πŸ§‘ 🚲 🌳 🌻 😎 🏫

πŸ‘·πŸΏβ€β™‚οΈ πŸ‘ˆ πŸ”₯ πŸ€– πŸ—οΈ

(I haven’t written this part yet)