When developing network-connected apps, it is most likely that it will need to use some good old JSON at some point. It is hard to imagine a mobile app that doesn't need to communicate with a web server or store structured data.
The guide looks at how to use JSON with Flutter. It explains how to select the right JSON solution for each scenario and why.
If you are here, for learning how to do JSON Serialization in Flutter, you are at the right place. I will be walking you through all the concepts related to JSON.
Excited to learn??
Let's Get started...
We can perform JSON serialization manually or Automated Serialization using Code Generation in Flutter.
Hey but, what is JSON??
If you are a beginner, you will be wondering what the heck is JSON first of all?
JSON stands for JavaScript Object Notation. This doesn't mean you have to learn JavaScript or something, JSON is just a text-based format for representing data. It is fully independent of JavaScript.
You may ask if it is used for representing data then, Why is JavaScript in the Full-form?
Because it is using JavaScript object Syntax.
JSON is used for transmitting data in web applications.
For Example, You want some data from the server or you want to send some data on the server, here Json comes into play to help us.
You may ask, how does JSON look like?
{
"College_Name": "No Name",
"place": "SomeWhere on planet Earth",
"formed": 2052,
"active" : true,
"students":[
{
"name": "name": {
"title": "Mr",
"first": "Gulshan",
"last": "Yadav"
},
"roll_no": 32,
"species" : "human"
},
{
"name": {
"title": "Mr",
"first": "Rahul",
"last": "Yadav"
},
"roll_no": 69,
"species": "Martian"
}
]
}
Now let's see how to manually parse this JSON string.
Let's say we have a program which shows the information about the students.
For starters, it shows some information about the college or school.
So my first step will be loading this JSON output from the source.
This could be anything, you can source your JSON file from the assets in the code or you may use any external API for that.
In this article, we will be learning how to do network calls to get the JSON data and how to parse it properly.
Step 1:
import ‘dart:convert’;
We need dart:convert so that we can use the JsonDecode
function which will help us to map all our JSON into a variable.
Step 2:
Now create a variable of type const
to store the address from where our program will fetch the JSON string.
const myJsonSourceUrl = “https://mysourceofJson.com”;
// Don’t use it, I wrote it for explaining to you.
Step 3:
Create a class of any name of your choice.
For Example:
class NetworkService{
}
Step 4:
Declare a async
function of type Future
of any Name of your choice.
class NetworkService{
Future fetchMyApi() async {
http.Response response = await http.get(Uri.parse(myJsonSourceUrl));
}
}
You may get an error message in your debug console, saying "hey man, idk what is this HTTP. Rectify the mistake."
So to fix it,
head over to your pubsec.yaml
file and add http: ^0.13.3
under the dependencies section.
And then run flutter pub get
in your terminal.
But wait this will not fix your error.
import http inside your program like this,
import 'package:http/http.dart' as http;
now you may see that your error got fixed.
Kudos!
If still your error not got fixed then re-run the command
flutter pub get
in your terminal and also check thepubsec.lock
file to check if your dependencies or loaded or not.My
pubsec.lock
file,If still, you are facing any issue, then head over to our Telegram channel and throw some questions, I'll be happy to help you.
Hey but what does that Future
data type used for, and what it is?
It is an object that represents delayed computation.
A
Future
is used to represent a potential value or error, that will be available at some time in the future.There's more but, right now this much information is enough to get our job done :)
What are those await
and async
?
"Async Simply means occurring at the same time. And Await means to wait. i.e. to wait for a certain operation to over."
Here our program is fetching the JSON string from the source, And then storing it inside a variable of type http.Response
.
Step 5: Check if the response is successful or not?
How do we do that?
It's simple but first of all, we need to know what is a successful response?
A successful response is a response with a status code of 200.
And a failed response is a response with a status code of anything other than 200.
So now we have to just check if the status code is 200 or not.
we can use our simple if-else loop or try-catch method.
For the sake of simplicity, we will be sticking with the if-else loop.
But how to check the status code?
Since we declared our variable of type http.Response, we can access the status code by using
response.statusCode
.
here's how our if-else loop will look like,
if (response.statusCode == 200) {
Map CollegeData = jsonDecode(response.body);
// debugPrint(CollegeData.toString());
List<dynamic> College = CollegeData["students"];
return College.map((json) => students.fromJson(json)).toList();
} else {
throw Exception("Something gone wrong, ${response.statusCode}");
}
Let's break it down,
As we know the first line of our code checks if the status code is 200 or not.
if it is 200 then it will execute the next line of code.
i.e. Map myData = jsonDecode(response.body);
This maps the json string into a variable of type Map
.
What is a Map
?
A
Map
is a collection of key-value pairs.It is similar to a
dictionary
in python.
It is also similar to ahashmap
in java.
It is also similar to ahashtable
in c++.
Now we have to access the values of the Map
.
And we can do that by using the []
operator.
Here we are storing the value of the students
key into a variable of type List<dynamic>
.
Then we are mapping the values of the List<dynamic>
into a List<Student>
.
student_network_service.dart
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:network_request/model/student.dart';
const String randomPersonURL = "https://linktoapi.com"; // Just an example.
class StudentNetworkService {
Future<List<Students>> fetchStudents(int amount) async {
http.Response response = await http.get("$randomPersonURL?results=$amount");
if (response.statusCode == 200) {
Map peopleData = jsonDecode(response.body);
List<dynamic> peoples = peopleData["results"];
return peoples.map((json) => Students.fromJson(json)).toList();
} else {
throw Exception("Something gone wrong, ${response.statusCode}");
}
}
}
But wait where's the code for the Student
class?
At this point, you might have a clear understanding of how manual JSON parsing works.
If not then, hang on.
I will be explaining it in detail.
Step 6:
Now we have to create a class of type Student
. But where?
Create a folder named model
and put it inside the lib folder.
Create a file inside the model folder and name it as student.dart
.
Note: Use lower came case for naming the file. To avoid any errors.
Also, don't use any special characters in the file name.
Create a class named student
. (As we have used student in our above code, we will use it here too.)
What we want our code to do is to parse the JSON string, to get the student's information to show up in a list on the homepage.
So our code will look like this,
model/student.dart
class Students {
String name;
String rollNo;
String species;
Students({this.name, this.rollNo, this.species});
Students.fromJson(Map<String, dynamic> json)
: name =
"${json["name"]["title"]} ${json["name"]["first"]} ${json["name"]["last"]}",
rollNo = json["roll_no"],
species = json["species"];
}
Have a look at the code.
First of all, we are creating a constructor.
Then we are creating a method named fromJson
.
And inside the method, we are parsing the JSON string and storing the values in the variables.
So that's it, we performed the manual JSON parsing.
Here's how we will use this class in our code,
homepage.dart
import 'package:flutter/material.dart';
import 'package:network_request/model/student.dart';
import 'package:network_request/services/student_network_service.dart';
class HomeScreen extends StatelessWidget {
final StudentNetworkService studentService = StudentNetworkService();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: SafeArea(
child: FutureBuilder(
future: studentService.fetchStudents(100),
// 100 is the number of students to fetch, But you can change the fetchStudents function to
// use the json file in your assets too.
builder:
(BuildContext context, AsyncSnapshot<List<Students>> snapshot) {
if (snapshot.hasData) {
return Row(
children: <Widget>[
Expanded(
child: Container(
child: Card(
color: Colors.black.withOpacity(0.5),
child: ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
var currentStudent = snapshot.data[index];
return ListTile(
title: Text(currentStudent.name),
leading: CircleAvatar(
// Left for you to do experiments.
// backgroundImage:
// NetworkImage(currentStudent.),
),
subtitle:
Text("Roll no: ${currentStudent.rollNo}"),
);
}),
),
),
),
],
);
}
if (snapshot.hasError) {
return Center(
child: Icon(
Icons.error,
color: Colors.red,
size: 82.0,
));
}
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator(),
SizedBox(
height: 20.0,
),
Text("Loading at the moment, please hold on")
],
));
},
),
),
),
);
}
}
Now let's see how we can do that using the json_serializable
package to implement the same but by a single line of code.
Not a single line of code, but lesser than usual.
Our whole tedious task will be handled by the flutter engine.
Check this post.
Today we learned how to parse the JSON string and store the values in the variables in flutter.
Our next post will guide you on how to generate the dart code so that it can be used to parse the JSON string with a working example.
Reducing the possible errors and bugs.
Until then, Happy Coding :)