Parsing JSON in Flutter

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

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 2 of 4 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": "Sardor Islomov",
      "occupation": "Software Engineer"
   }
}

Notice that the snippet starts with a brace {, which indicates an object. JSON can also start as an array, which uses the square bracket [ 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’ve downloaded a JSON string, you can do a few different things:

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

All 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.

You’ll use the model object approach below.

Parsing JSON

You can parse JSON code in a few different ways.

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 use 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: ^1.0.5
  http: ^0.13.6
  json_annotation: ^4.8.1

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

dev_dependencies:
  flutter_test:
    sdk: flutter
  build_runner: ^2.4.4
  json_serializable: ^6.7.0

Next, press the Packages get or the Pub 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 dependencies 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 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<String> getCatBreeds() async {
    // 6
    final network = Network('$catAPIURL$apiKeyString');
    // 7
    final catData = await network.getData();
    return catData;
  }
  // 8
  Future<String> getCatBreed(String breedName) async {
    final network =
    Network('$catImageAPIURL$breedString$breedName&$apiKeyString');
    final 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. The 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. The 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 {
  final catJson = await CatAPI().getCatBreeds();
  print(catJson);
}

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, press Option-Enter and choose Import.

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

@override
void initState() {
  super.initState();
  getCatData();
}

Now, run/restart your app to check if your connection to the API works. Look at the output in the run tab, and you’ll see the JSON string printed out:

Cat API Log Output

Now that 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 lib/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({
    required this.id,
    required this.name,
    required this.description,
    required 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.

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

class BreedList {
  List<Breed> breeds;

  BreedList({required 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. Add the classes below to cats.dart:

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

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

class CatBreed {
  String id;
  String url;
  int width;
  int height;

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

class CatList {
  List<CatBreed> breeds;

  CatList({required this.breeds});
}

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.