Parsing JSON in Flutter

Learn about getting and parsing JSON data from the internet when building a cross-platform app using Flutter. By Kevin D Moore.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 2 of 3 of this article. Click here to view the first page.

Understanding JSON

JSON is just a text format that most REST APIs use to return their data. Another common format is XML, but XML is quite a bit more verbose.

Here’s a small example of JSON:

{
  "user": {
      "name": "Kevin Moore",
      "occupation": "Programmer"
   }
}

Notice that the snippet starts with a brace {, which indicates an object. JSON can also start as an array, which uses the square bracket [ symbol to signify the start of the array. JSON needs to be properly formatted, so all beginning { and [ symbols need to have their ending symbols: } and ].

Once you have downloaded a JSON string, you can do a few different things:

  1. Keep it as a string and parse out the key/value pairs.
  2. Convert the string to a Dart Map from which you can get the key/value pairs.
  3. Convert the string to Dart model objects from which you can get the values from the object properties.

All of these options have different pros and cons. Dealing with a string can get complicated if you have a lot of data. Using Map values can make the code quite verbose. Converting to model objects takes more work, but is easier to use.

We’ll prefer the model object approach below.

Parsing JSON

There are a few different ways that you can parse JSON code.

By Hand

You can parse a JSON string by hand by using the dart:convert library.

Here’s an example:

import 'dart:convert';

Map<String, dynamic> user = jsonDecode(jsonString);
var name = user['user]['name'];

This doesn’t look too hard, but if you start working with complex JSON strings, it becomes very tedious to write and maintain.

Using Libraries

If you go to Pub.dev, a repository of Dart packages, and search for JSON Flutter libraries, you’ll find several libraries for dealing with JSON. For this tutorial, you’ll be using two Flutter libraries:

  • HTTP for network calls, as seen above.
  • json_annotation for annotating your JSON model classes.

You’ll also use two development libraries that create helper classes for converting JSON strings into your model objects:

  • build_runner, which runs your json_serializable library.
  • json_serializable, which creates the extra helper classes that convert strings into your models.

These two libraries will go into the dev_dependencies section of your pubspec.yaml.

To add them, start by opening pubspec.yaml in the root of the project. First, you’ll add the Flutter libraries.

In the dependencies section, add the json_annotation dependency underneath http:

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^0.1.2
  http: ^0.12.0+2
  json_annotation: ^2.0.0 

Next, go to the dev_dependencies section and add the build_runner and json_serializable dependencies:

dev_dependencies:
  flutter_test:
    sdk: flutter    
  build_runner: ^1.0.0
  json_serializable: ^2.0.0

Next, press the Packages get prompt that shows up in the top-right side of the Android Studio. If you have any problems, make sure you line up the dependecies to match what you see in the final project, since YAML file formatting is very strict.

The Cat API

Now, open cats_api.dart in the lib/api folder. The first line is a constant called apiKey. Replace Your Key with the key you obtained from the Cat API site, then take a look at the code:

const String apiKey = 'Your Key';
//1
const String catAPIURL = 'https://api.thecatapi.com/v1/breeds?';
// 2
const String catImageAPIURL = 'https://api.thecatapi.com/v1/images/search?';
// 3
const String breedString = 'breed_id=';
// 4
const String apiKeyString = 'x-api-key=$apiKey';

class CatAPI {
  // 5
  Future<dynamic> getCatBreeds() async {
     // 6
    Network network = Network('$catAPIURL$apiKeyString');
    // 7
    var catData = await network.getData();
    return catData;
  }
  // 8
  Future<dynamic> getCatBreed(String breedName) async {
    Network network =
        Network('$catImageAPIURL$breedString$breedName&$apiKeyString');
    var catData = await network.getData();
    return catData;
  }
}

Here’s what you see:

  1. A string value of the API to get the list of breeds.
  2. A string URL for running a cat image search.
  3. A string to capture the actual breed ID.
  4. A string that uses your API key to add to the final URL.
  5. A method getCatBreeds() to return the breed data.
  6. Use of your Network class from above to pass in your breed’s API string and your key.
  7. Awaiting the asynchronous result.
  8. A method getCatBreed(String breedName) to get the cat image for a given breed.

Using the Cat API

Open cat_breeds.dart in the lib/screens folder.

Inside _CatBreedsPageState, add the following:

void getCatData() async {
  var result = await CatAPI().getCatBreeds();
  print(result);
}

This method calls the cat API to get the cat breeds.

You’ll need to import the CatAPI class from cat_info.dart. You can do that manually or, if you like, put the cursor over the call to the CatAPI constructor and press Option + Enter and choose Import.

Next, call the new method you’ve added to get the cat data by adding the following to the bottom of initState():

getCatData();

Now, run your app to check if your connection to the API works. Take a look at the output in the run tab and you should see the JSON string printed out.

Output in the console

Now that your your initial call to the Cat API works, you’ll create the model classes you need in the next step.

Creating Models

Get started by opening cats.dart in the Models folder. You’ll see commented out an example of the JSON data returned by the API.

Add a class that describes a cat breed:

class Breed {
  String id;
  String name;
  String description;
  String temperament;

  Breed({this.id, this.name, this.description, this.temperament});
}

This class defines the fields you’ll pull from the JSON. You need the id to get the image of the cat breed. You’ll display name and description on the card view.

If you look at the data you printed to the console above, you’ll see that it starts with the square bracket [ character, meaning that you’ll get a JSON array of breeds. Add a class to hold that array of data now:

class BreedList {
  List<Breed> breeds;

  BreedList({this.breeds});
}

This class holds a Dart list of cat breeds.

For the image search, you need to describe the cat, the cat breed and the list of cat breeds, like so:

class Cat {
  String name;
  String description;
  String life_span;

  Cat({this.name, this.description, this.life_span});
}

class CatBreed {
  String id;
  String url;
  int width;
  int height;
  List<Cat> breeds;

  CatBreed({this.id, this.url, this.width, this.height, this.breeds});
}

class CatList {
  List<CatBreed> breeds;

  CatList({this.breeds});
}

Add those classes to cats.dart now.

For this tutorial, you won’t use the temperament or life_span fields, but you could use them if you wanted to enhance the app.