0% found this document useful (0 votes)
59 views

Parsing Complex JSON in Flutter. Parse Different Types of Simple and - by Pooja Bhaumik - Flutter Community - Medium

This document provides an overview of parsing complex JSON in Flutter. It discusses 3 JSON structures of increasing complexity - a simple map, a structure with arrays, and a nested structure. For each structure, it demonstrates how to define a model class, add a fromJson factory constructor to map the JSON to class properties, and load and access the JSON data. Key steps include identifying the JSON structure, defining matching model classes, explicitly handling lists, and creating nested classes for nested JSON objects.

Uploaded by

isapuncuna6395
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
59 views

Parsing Complex JSON in Flutter. Parse Different Types of Simple and - by Pooja Bhaumik - Flutter Community - Medium

This document provides an overview of parsing complex JSON in Flutter. It discusses 3 JSON structures of increasing complexity - a simple map, a structure with arrays, and a nested structure. For each structure, it demonstrates how to define a model class, add a fromJson factory constructor to map the JSON to class properties, and load and access the JSON data. Key steps include identifying the JSON structure, defining matching model classes, explicitly handling lists, and creating nested classes for nested JSON objects.

Uploaded by

isapuncuna6395
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 16

Parsing complex JSON in Flutter

Pooja Bhaumik Follow


Jul 8, 2018 · 10 min read

I have to admit, I was missing the gson world of Android after working with JSON in
Flutter/Dart. When I started working with APIs in Flutter, JSON parsing really had me
struggle a lot. And I’m certain, it confuses a lot of you beginners.

We will be using the built in dart:convert library for this blog. This is the most basic
parsing method and it is only recommended if you are starting with Flutter or you’re
building a small project. Nevertheless, knowing the basics of JSON parsing in Flutter is
pretty important. When you’re good at this, or if you need to work with a larger project,
consider code generator libraries like json_serializable, etc. If possible, I will discover
them in the future articles.

Fork this sample project. It has all the code for this blog that you can experiment with.

JSON structure #1 : Simple map


Let’s start with a simple JSON structure from student.json

{
"id":"487349",
"name":"Pooja Bhaumik",
"score" : 1000
}

Rule #1 : Identify the structure. Json strings will either have a Map (key-value
pairs) or a List of Maps.

Rule #2 : Begins with curly braces? It’s a map.


Begins with a Square bracket? That’s a List of maps.

student.json is clearly a map. ( E.g like, id is a key, and 487349 is the value for id )

Let’s make a PODO (Plain Old Dart Object?) file for this json structure. You can find this
code in student_model.dart in the sample project.

class Student{
String studentId;
String studentName;
int studentScores;

Student({
this.studentId,
this.studentName,
this.studentScores
});

}
Perfect!
Was it? Because there was no mapping between the json maps and this PODO file. Even the
entity names don’t match.
I know, I know. We are not done yet. We have to do the work of mapping these class
members to the json object. For that, we need to create a factory method. According to
Dart documentation, we use the factory keyword when implementing a constructor
that doesn’t always create a new instance of its class and that’s what we need right now.

factory Student.fromJson(Map<String, dynamic> parsedJson){


return Student(
studentId: parsedJson['id'],
studentName : parsedJson['name'],
studentScores : parsedJson ['score']
);
}

Here, we are creating a factory method called Student.fromJson whose objective is to


simply deserialize your json.

I’m a little noob, can you tell me about Deserialization?

Sure. Let’s tell you about Serialization and Deserialization first. Serialization simply
means writing the data(which might be in an object) as a string, and Deserialization is
the opposite of that. It takes the raw data and reconstructs the object model. In this
article, we mostly will be dealing with the deserialization part. In this first part, we are
deserializing the json string from student.json

So our factory method could be called as our converter method.

Also must notice the parameter in the fromJson method. It’s a Map<String, dynamic> It
means it maps a String key with a dynamic value. That’s exactly why we need to
identify the structure. If this json structure were a List of maps, then this parameter
would have been different.

But why dynamic?


Let’s look at another json structure first to answer your question.
name is a Map<String, String> , majors is a Map of String and List<String> and
subjects is a Map of String and List<Object>

Since the key is always a string and the value can be of any type, we keep it as dynamic

to be on the safe side.

Check the full code for student_model.dart here.

Accessing the object


Let’s write student_services.dart which will have the code to call Student.fromJson and
retrieve the values from the Student object.

Snippet #1 : imports

import 'dart:async' show Future;


import 'package:flutter/services.dart' show rootBundle;
import 'dart:convert';
import 'package:flutter_json/student_model.dart';

The last import will be the name of your model file.

Snippet #2 : load Json Asset (optional)

Future<String> _loadAStudentAsset() async {


return await rootBundle.loadString('assets/student.json');
}
In this particular project, we have our json files in the assets folder, so we have to load
the json in this way. But if you have your json file on the cloud, you can do a network call
instead. Network calls are out of the scope of this article.

Snippet #3 : load the response

Future loadStudent() async {


String jsonString = await _loadAStudentAsset();
final jsonResponse = json.decode(jsonString);
Student student = new Student.fromJson(jsonResponse);
print(student.studentScores);
}

In this loadStudent() method,


Line 1 : loading the raw json String from the assets.
Line 2 : Decoding this raw json String we got.
Line 3 : And now we are deserializing the decoded json response by calling the
Student.fromJson method so that we can now use Student object to access our entities.
Line 4 : Like we did here, where we printed studentScores from Student class.

Check your Flutter console to see all your print values. (In Android Studio, its under Run
tab)

And voila! You just did your first JSON parsing (or not).
Note: Remember the 3 snippets here, we will be using it for the next set of json parsing (only
changing the filenames and method names), and I won’t be repeating the code again here.
But you can find everything in the sample project anyway.

JSON structure #2 : Simple structure with arrays


Now we conquer a json structure that is similar to the one above, but instead of just
single values, it might also have an array of values.

{
"city": "Mumbai",
"streets": [
"address1",
"address2"
]
}

So in this address.json, we have city entity that has a simple String value, but streets

is an array of String .

As far as i know, Dart doesn’t have an array data type, but instead has a List<datatype>
so here streets will be a List<String> .

Now we have to check Rule#1 and Rule#2 . This is definitely a map since this starts
with a curly brace. streets is still a List though, but we will worry about that later.

So the address_model.dart initially will look like this

class Address {
final String city;
final List<String> streets;

Address({
this.city,
this.streets
});
}

Now since this is a map, our Address.fromJson method will still have a Map<String,

dynamic> parameter.

factory Address.fromJson(Map<String, dynamic> parsedJson) {

return new Address(


city: parsedJson['city'],
streets: parsedJson['streets'],
);
}

Now construct the address_services.dart by adding the 3 snippets we mentioned


above. Must remember to put the proper file names and method names. Sample project
already has address_services.dart constructed for you.
Now when you run this, you will get a nice little error. :/

type 'List<dynamic>' is not a subtype of type 'List<String>'

I tell you, these errors have come in almost every step of my development with Dart. And
you will have them too. So let me explain what this means. We are requesting a
List<String> but we are getting a List<dynamic> because our application cannot
identify the type yet.

So we have to explicitly convert this to a List<String>

var streetsFromJson = parsedJson['streets'];


List<String> streetsList = new List<String>.from(streetsFromJson);

Here, first we are mapping our variable streetsFromJson to the streets entity.
streetsFromJson is still a List<dynamic> . Now we explicitly create a new List<String>

streetsList that contains all elements from streetsFromJson .

Check the updated method here. Notice the return statement now.
Now you can run this with address_services.dart and this will work perfectly.

Json structure #3 : Simple Nested structures


Now what if we have a nested structure like this from shape.json

{
"shape_name":"rectangle",
"property":{
"width":5.0,
"breadth":10.0
}
}

Here, property contains an object instead of a basic primitive data-type.


So how will the PODO look like?
Okay, let’s break down a little.
In our shape_model.dart , let’s make a class for Property first.

class Property{
double width;
double breadth;

Property({
this.width,
this.breadth
});
}

Now let’s construct the class for Shape . I am keeping both classes in the same Dart file.

class Shape{
String shapeName;
Property property;

Shape({
this.shapeName,
this.property
});
}

Notice how the second data member property is basically an object of our previous class
Property .

Rule #3: For nested structures, make the classes and constructors first, and then
add the factory methods from bottom level.

By bottom level, we mean, first we conquer Property class, and then we go one level above to
the Shape class. This is just my suggestion, not a Flutter rule.

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


return Property(
width: json['width'],
breadth: json['breadth']
);
}

This was a simple map.

But for our factory method at Shape class, we cant just do this.

factory Shape.fromJson(Map<String, dynamic> parsedJson){


return Shape(
shapeName: parsedJson['shape_name'],
property : parsedJson['property']
);
}

property : parsedJson['property'] First, this will throw the type mismatch error —

type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of


type 'Property'

And second, hey we just made this nice little class for Property, I don’t see it’s usage
anywhere.

Right. We must map our Property class here.

factory Shape.fromJson(Map<String, dynamic> parsedJson){


return Shape(
shapeName: parsedJson['shape_name'],
property: Property.fromJson(parsedJson['property'])
);
}

So basically, we are calling the Property.fromJson method from our Property class and
whatever we get in return, we map it to the property entity. Simple! Check out the code
here.

Run this with your shape_services.dart and you are good to go.
JSON structure #4 : Nested structures with Lists
Let’s check our product.json

{
"id":1,
"name":"ProductName",
"images":[
{
"id":11,
"imageName":"xCh-rhy"
},
{
"id":31,
"imageName":"fjs-eun"
}
]
}

Okay, now we are getting deeper. I see a list of objects somewhere inside. Woah.

Yes, so this structure has a List of objects, but itself is still a map. (Refer Rule #1, and
Rule #2) . Now referring to Rule #3, let’s construct our product_model.dart .

So we create two new classes Product and Image .

Note: Product will have a data member that is a List of Image

class Product {
final int id;
final String name;
final List<Image> images;

Product({this.id, this.name, this.images});


}

class Image {
final int imageId;
final String imageName;

Image({this.imageId, this.imageName});
}

The factory method for Image will be quite simple and basic.
factory Image.fromJson(Map<String, dynamic> parsedJson){
return Image(
imageId:parsedJson['id'],
imageName:parsedJson['imageName']
);
}

Now for the factory method for Product

factory Product.fromJson(Map<String, dynamic> parsedJson){

return Product(
id: parsedJson['id'],
name: parsedJson['name'],
images: parsedJson['images']
);
}

This will obviously throw a runtime error

type 'List<dynamic>' is not a subtype of type 'List<Image>'

And if we do this,

images: Image.fromJson(parsedJson['images'])

This is also definitely wrong, and it will throw you an error right away because you
cannot assign an Image object to a List<Image>

So we have to create a List<Image> and then assign it to images

var list = parsedJson['images'] as List;


print(list.runtimeType); //returns List<dynamic>

List<Image> imagesList = list.map((i) => Image.fromJson(i)).toList();


list here is a List<dynamic>. Now we iterate over the list and map each object in list

to Image by calling Image.fromJson and then we put each map object into a new list with
toList() and store it in List<Image> imagesList . Find the full code here.

JSON structure #5 : List of maps


Now let’s head over to photo.json

[
{
"albumId": 1,
"id": 1,
"title": "accusamus beatae ad facilis cum similique qui sunt",
"url": "http://placehold.it/600/92c952",
"thumbnailUrl": "http://placehold.it/150/92c952"
},
{
"albumId": 1,
"id": 2,
"title": "reprehenderit est deserunt velit ipsam",
"url": "http://placehold.it/600/771796",
"thumbnailUrl": "http://placehold.it/150/771796"
},
{
"albumId": 1,
"id": 3,
"title": "officia porro iure quia iusto qui ipsa ut modi",
"url": "http://placehold.it/600/24f355",
"thumbnailUrl": "http://placehold.it/150/24f355"
}
]

Uh, oh. Rule #1 and Rule #2 tells me this can’t be a map because the json string starts
with a square bracket. So this is a List of objects? Yes. The object being here is Photo (or
whatever you’d like to call it).

class Photo{
final String id;
final String title;
final String url;

Photo({
this.id,
this.url,
this.title
}) ;

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


return new Photo(
id: json['id'].toString(),
title: json['title'],
url: json['json'],
);
}
}

But its a list of Photo , so does this mean you have to build a class that contains a
List<Photo> ?

Yes, I would suggest that.

class PhotosList {
final List<Photo> photos;

PhotosList({
this.photos,
});
}

Also notice, this json string is a List of maps. So, in our factory method, we won’t have a
Map<String, dynamic> parameter, because it’s a List. And that is exactly why it’s
important to identify the structure first. So our new parameter would be a
List<dynamic> .

factory PhotosList.fromJson(List<dynamic> parsedJson) {

List<Photo> photos = new List<Photo>();

return new PhotosList(


photos: photos,
);
}
This would throw an error

Invalid value: Valid value range is empty: 0

Hey, because we never could use the Photo.fromJson method.


What if we add this line of code after our list initialization?

photos = parsedJson.map((i)=>Photo.fromJson(i)).toList();

Same concept as earlier, we just don’t have to map this to any key from the json string,
because it’s a List, not a map. Code here.

JSON structure #6 : Complex nested structures


Here is page.json.

I will request you to solve this. It is already included in the sample project. You just have
to build the model and services file for this. But I won’t conclude before giving you hints
and tips (if case, you need any).

Rule#1 and Rule#2 as usual applies. Identify the structure first. Here it is a map. So all
the json structures from 1–5 will help.

Rule #3 asks you to make the classes and constructors first, and then add the factory
methods from bottom level. Just another tip. Also add the classes from the deep/bottom
level. For e.g, for this json structure, make the class for Image first, then Data and
Author and then the main class Page . And add the factory methods also in the same

sequence.

For class Image and Data refer to Json structure #4.


For class Author refer to Json structure #3

Beginner’s tip: While experimenting with any new assets, remember to declare it in the
pubspec.yaml file.
And that’s it for this Fluttery article. This article may not be the best JSON parsing article
out there, (because I’m still learning a lot) but I hope it got you started.

Read the Spanish translation by CarlosMillan

Parseando JSON complejo en Flutter


Fuente original: https://medium.com/flutter-community/parsing-
complex-json-in-flutter-747c46655f51
medium.com

Check the next part here

Working with APIs in Flutter


A beginner’s guide to conquering the world of APIs in Flutter for a
better ‘Future’.
medium.com

I got something wrong? Mention it in the


comments. I would love to improve.

If you learnt even a thing or two, clap your hands 👏


as many times as you can to show your support!
This motivates me to write more.
Feeling super generous? Buy me a cupcake.

Hello World, I am Pooja Bhaumik. A creative


developer and a logical designer. You can find me on
Linkedin or stalk me on GitHub or maybe follow
me on Twitter? If that’s too social for you, just drop
a mail to pbhaumik26@gmail.com if you wish to
talk tech with me.

Have a nice fluttery day!

Flutter Dart Android iOS Json

About Help Legal

Get the Medium app

You might also like