Nowadays most of the application fetching data from API and displaying data into apps. In this blog, we will see how to fetch data from API. So let’s get started.
If you are starting a project from scratch, you can create a new flutter project by using IDE or command. If you already have a flutter project skip this step.
Add the http package
To add the http package, open your pubspec.yaml file and add the http package under the dependencies section. You can get the latest version of http package on pub.dev/packages/http.
dependencies:
http: <latest_version>
Add the INTERNET permission (Android)
To use the internet in android, open the AndroidManifest.xml and add the internet permission.
<uses-permission android:name="android.permission.INTERNET" />
Serializing JSON inside model classes
Create the Model Class
In this example tutorial https://jsonplaceholder.typicode.com/posts API, you can use your original API.
To create a model class,
- Go the https://app.quicktype.io/.
- Then give the model class name and paste the JSON response.
- In the right sidebar, select the Dart programming language, use method names fromMap(), and make all properties required.
- Then, copy the model class code.
- create a dart file in your project and paste the model class code.
The model class looks like this,
import 'dart:convert';
List<Post> postFromJson(String str) =>
List<Post>.from(json.decode(str).map((x) => Post.fromMap(x)));
class Post {
Post({
required this.userId,
required this.id,
required this.title,
required this.body,
});
int userId;
int id;
String title;
String body;
factory Post.fromMap(Map<String, dynamic> json) => Post(
userId: json["userId"],
id: json["id"],
title: json["title"],
body: json["body"],
);
}
Make an HTTP Request
To fetch data from internet create a function called fetchPost(). That function return Future<List<Post>>.
Future<List<Post>> fetchPost() async {
final response =
await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts'));
if (response.statusCode == 200) {
final parsed = json.decode(response.body).cast<Map<String, dynamic>>();
return parsed.map<Post>((json) => Post.fromMap(json)).toList();
} else {
throw Exception('Failed to load album');
}
}
The http.get() function requests JSON data from the server. The JSON response data is stored in the response variable. Then we check the response status code is 200 or not. If the response code is 200, then convert the JSON into a Post using the fromMap() factory method otherwise we throwing Exception. Fetching data from the internet takes some time so make fetchPost() an asynchronous function.
Fetch the data
Then call the fetchPost() function in the initState().
Future<List<Post>> fetchPost() async {
final response =
await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts'));
if (response.statusCode == 200) {
final parsed = json.decode(response.body).cast<Map<String, dynamic>>();
return parsed.map<Post>((json) => Post.fromMap(json)).toList();
} else {
throw Exception('Failed to load album');
}
}
The build method is not recommended for API calls. So, calling fetchPost() in the initState(). Because the initState() called only one time.
Display the Data
To display the data from internet, use the FutureBuilder
widget. The FutureBuilder accepts future and builder. In this case future is futurePost and the builder is responsible for rendering screen.
FutureBuilder<List<Post>>(
future: futurePost,
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (_, index) => Container(
child: Container(
margin: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
padding: EdgeInsets.all(20.0),
decoration: BoxDecoration(
color: Color(0xff97FFFF),
borderRadius: BorderRadius.circular(15.0),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"${snapshot.data![index].title}",
style: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 10),
Text("${snapshot.data![index].body}"),
],
),
),
),
);
} else {
return Center(child: CircularProgressIndicator());
}
},
),
Demo

Full Source Code
post_model.dart
import 'dart:convert';
List<Post> postFromJson(String str) =>
List<Post>.from(json.decode(str).map((x) => Post.fromMap(x)));
class Post {
Post({
required this.userId,
required this.id,
required this.title,
required this.body,
});
int userId;
int id;
String title;
String body;
factory Post.fromMap(Map<String, dynamic> json) => Post(
userId: json["userId"],
id: json["id"],
title: json["title"],
body: json["body"],
);
}
main.dart
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:rest_api_example/post_model.dart';
Future<List<Post>> fetchPost() async {
final response =
await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts'));
if (response.statusCode == 200) {
final parsed = json.decode(response.body).cast<Map<String, dynamic>>();
return parsed.map<Post>((json) => Post.fromMap(json)).toList();
} else {
throw Exception('Failed to load album');
}
}
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late Future<List<Post>> futurePost;
@override
void initState() {
super.initState();
futurePost = fetchPost();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fetch Data Example',
theme: ThemeData(
primaryColor: Colors.lightBlueAccent,
),
home: Scaffold(
appBar: AppBar(
title: Text('Fetch Data Example'),
),
body: FutureBuilder<List<Post>>(
future: futurePost,
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (_, index) => Container(
child: Container(
margin: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
padding: EdgeInsets.all(20.0),
decoration: BoxDecoration(
color: Color(0xff97FFFF),
borderRadius: BorderRadius.circular(15.0),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"${snapshot.data![index].title}",
style: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 10),
Text("${snapshot.data![index].body}"),
],
),
),
),
);
} else {
return Center(child: CircularProgressIndicator());
}
},
),
),
);
}
}