JSON

  1. What is JSON?
  2. JSON, which stands for JavaScript Object Notation, is an open-standard format used on the web and in mobile clients. It’s the most widely used format for Representational State Transfer (REST)-based APIs that servers provide. If you talk to a server that has a REST API, it will most likely return data in a JSON format. An example of a JSON response looks something like this:

    {

       "title": "The Shawshank Redemption",

       "rank": "1",

       "id": "tt0111161"

    }

    That is an example movie response that contains three fields.

    While it’s possible to treat the JSON as just a long string and try to parse out the data, it’s much easier to use a package that already knows how to do that. Flutter has a built-in package for decoding JSON, but in this chapter, you’ll use the json_serializable and json_annotation packages to help make the process easier.

    Flutter’s built-in dart:convert package contains methods like json.decode and json.encode, which converts a JSON string to a Map<String, dynamic> and back. While this is a step ahead of manually parsing JSON, you’d still have to write extra code that takes that map and puts the values into a new class.

    The json_serializable package comes in handy because it can generate model classes for you according to the annotations you provide via json_annotation. Before taking a look at automated serialization, you’ll see in the next section what manual serialization entails.


  3. Serializing JSON inside model classes
  4. To convert the JSON above to a model class, you’d first create a Movie model class:

    class Movie {

      final String title;

      final int rank;

      final String id;

      Movie(this.title, this.rank, this.id);

    }




    Then you’d add toJson() and fromJson() factory methods:

    class Movie {

      final String title;

      final int rank;

      final String id;

      Movie(this.title, this.rank, this.id);

      factory Movie.fromJson(Map<String, dynamic> json) {

        return Movie(

            json['title'] as String, json['rank'] as int, json['id'] as String);

      }

      Map<String, dynamic> toJson() {

        return <String, dynamic>{'title': title, 'rank': rank, 'id': id};

      }

    }




    In fromJson(), you grab data from the JSON map variable named json and convert it to arguments you pass to the Movie constructor. In toJson(), you construct a map using the JSON field names.

  5. Serializing JSON inline
  6. By looking at the, dart:convert documentation, you’ll see that you can decode the JSON by calling the jsonDecode() function, with the JSON string as the method argument.

    import 'dart:convert';

     

    void main() {

      String rawJson = '{"name":"Mary","age":30}';

     

      Map<String, dynamic> map = jsonDecode(rawJson);

     

      print(map);

    }

     



    {name: Mary, age: 30}

    Unfortunately, jsonDecode() returns a Map<String, dynamic>, meaning that you do not know the types of the values until runtime. With this approach, you lose most of the statically typed language features: type safety, autocompletion and most importantly, compile-time exceptions. Your code will become instantly more error-prone. For example, whenever you access the name or email fields, you could quickly introduce a typo. A typo that the compiler doesn’t know about since the JSON lives in a map structure.