Learn how to parse JSON data in Flutter, transforming HTTP responses into Dart objects using the dart:convert library. Understand JSON structures, create model classes, and serialize objects back to JSON.
In the world of mobile app development, interacting with web services and APIs is a common task. JSON (JavaScript Object Notation) is the most widely used format for data interchange between clients and servers due to its simplicity and readability. In this section, we will delve into how to parse JSON data in Flutter, transforming HTTP responses into Dart objects that your app can work with.
JSON is a lightweight data interchange format that is easy for humans to read and write, and easy for machines to parse and generate. It is text-based and language-independent, making it a popular choice for APIs. JSON data is structured in a key-value pair format, similar to a dictionary in Python or an object in JavaScript.
Here’s a simple JSON example:
{
"userId": 1,
"id": 1,
"title": "Sample Post",
"body": "This is a sample post body."
}
In the context of Flutter, JSON is commonly used to receive data from web services, which can then be parsed and used within the app.
Flutter provides the dart:convert
library to handle JSON data. This library includes the jsonDecode
function, which is used to parse JSON strings into Dart objects.
To start using the dart:convert
library, you need to import it into your Dart file:
import 'dart:convert';
The jsonDecode
function takes a JSON string and converts it into a corresponding Dart object. For example:
String jsonString = '{"userId": 1, "id": 1, "title": "Sample Post", "body": "This is a sample post body."}';
Map<String, dynamic> jsonMap = jsonDecode(jsonString);
print(jsonMap['title']); // Output: Sample Post
While you can work directly with maps, it’s a best practice to create Dart classes that represent your JSON data. This approach provides type safety and makes your code more readable and maintainable.
Let’s create a Post
class to represent the JSON data structure:
class Post {
final int userId;
final int id;
final String title;
final String body;
Post({required this.userId, required this.id, required this.title, required this.body});
factory Post.fromJson(Map<String, dynamic> json) {
return Post(
userId: json['userId'],
id: json['id'],
title: json['title'],
body: json['body'],
);
}
Map<String, dynamic> toJson() {
return {
'userId': userId,
'id': id,
'title': title,
'body': body,
};
}
}
The fromJson
factory constructor is a common pattern in Dart for creating an instance of a class from a map. This constructor takes a Map<String, dynamic>
as input and returns an instance of the Post
class.
APIs often return lists of JSON objects. To handle this, you can parse JSON arrays into lists of Dart objects.
Suppose you receive a JSON response containing a list of posts:
[
{
"userId": 1,
"id": 1,
"title": "Sample Post 1",
"body": "This is the body of sample post 1."
},
{
"userId": 2,
"id": 2,
"title": "Sample Post 2",
"body": "This is the body of sample post 2."
}
]
You can parse this array into a list of Post
objects as follows:
Future<List<Post>> fetchPosts() async {
final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts'));
if (response.statusCode == 200) {
final List jsonResponse = jsonDecode(response.body);
return jsonResponse.map((post) => Post.fromJson(post)).toList();
} else {
throw Exception('Failed to load posts');
}
}
In addition to parsing JSON into Dart objects, you might need to convert Dart objects back into JSON strings. This is useful when sending data back to a server.
The toJson
method converts a Dart object into a map, which can then be encoded into a JSON string using jsonEncode
.
Post post = Post(userId: 1, id: 1, title: 'Sample Post', body: 'This is a sample post body.');
String jsonString = jsonEncode(post.toJson());
print(jsonString); // Output: {"userId":1,"id":1,"title":"Sample Post","body":"This is a sample post body."}
Let’s put everything together with a practical example. Assume you have a Flutter app that fetches posts from an API and displays them in a list.
Define the Post Model: As shown earlier, create a Post
class with fromJson
and toJson
methods.
Fetch and Parse Data: Use the fetchPosts
function to retrieve and parse the JSON data.
Display Data in UI: Use Flutter widgets to display the list of posts.
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class Post {
final int userId;
final int id;
final String title;
final String body;
Post({required this.userId, required this.id, required this.title, required this.body});
factory Post.fromJson(Map<String, dynamic> json) {
return Post(
userId: json['userId'],
id: json['id'],
title: json['title'],
body: json['body'],
);
}
Map<String, dynamic> toJson() {
return {
'userId': userId,
'id': id,
'title': title,
'body': body,
};
}
}
Future<List<Post>> fetchPosts() async {
final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts'));
if (response.statusCode == 200) {
final List jsonResponse = jsonDecode(response.body);
return jsonResponse.map((post) => Post.fromJson(post)).toList();
} else {
throw Exception('Failed to load posts');
}
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter JSON Parsing',
home: Scaffold(
appBar: AppBar(
title: Text('Posts'),
),
body: FutureBuilder<List<Post>>(
future: fetchPosts(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(snapshot.data![index].title),
subtitle: Text(snapshot.data![index].body),
);
},
);
} else if (snapshot.hasError) {
return Center(child: Text('${snapshot.error}'));
}
return Center(child: CircularProgressIndicator());
},
),
),
);
}
}
To better understand the mapping between JSON keys and Dart object properties, consider the following diagram:
graph TD; JSON["JSON Object"] -->|userId| DartClass["Dart Class: Post"] JSON -->|id| DartClass JSON -->|title| DartClass JSON -->|body| DartClass
json_serializable
to automate the creation of fromJson
and toJson
methods. This reduces boilerplate code and minimizes errors.By following these guidelines and examples, you can effectively parse JSON data in your Flutter applications, enabling seamless integration with web services and APIs.