Fetch data from the internet
Fetching data from the internet is necessary for most apps. Luckily, Dart and Flutter provide tools for this type of work!
Directions
- Make a network request using the
http
package - Convert the response into a custom Dart object
- Fetch and Display the data with Flutter
1. Make a network request
The http
package provides the
simplest way to fetch data from the internet.
In this example, we’ll fetch a sample post from the
JSONPlaceholder REST API using the
http.get
method.
Future<http.Response> fetchPost() {
return http.get('https://jsonplaceholder.typicode.com/posts/1');
}
The http.get
method returns a Future
that contains a Response
.
Future
is a core Dart class for working with async operations. It is used to represent a potential value or error that will be available at some time in the future.- The
http.Response
class contains the data received from a successful http call.
2. Convert the response into a custom Dart object
While it’s easy to make a network request, working with a raw
Future<http.Response>
isn’t very convenient. To make our lives easier, we can
convert the http.Response
into our own Dart object.
Create a Post
class
First, we’ll need to create a Post
class that contains the data from our
network request. It will also include a factory constructor that allows us to
create a Post
from json.
Converting JSON by hand is only one option. For more information, please see the full article on JSON and serialization.
class Post {
final int userId;
final int id;
final String title;
final String body;
Post({this.userId, this.id, this.title, this.body});
factory Post.fromJson(Map<String, dynamic> json) {
return new Post(
userId: json['userId'],
id: json['id'],
title: json['title'],
body: json['body'],
);
}
}
Convert the http.Response
to a Post
Now, we’ll update the fetchPost
function to return a Future<Post>
. To do so,
we’ll need to:
- Convert the response body into a json
Map
with thedart:convert
package - Convert the json
Map
into aPost
using thefromJson
factory.
Future<Post> fetchPost() async {
final response = await http.get('https://jsonplaceholder.typicode.com/posts/1');
final json = JSON.decode(response.body);
return new Post.fromJson(json);
}
Hooray! Now we’ve got a function that we can call to fetch a Post from the internet!
3. Fetch and Display the data
In order to fetch the data and display it on screen, we can use the
FutureBuilder
widget! The FutureBuilder
Widget comes with Flutter and makes it easy to work
with async data sources.
We must provide two parameters:
- The
Future
we want to work with. In our case, we’ll call ourfetchPost()
function. - A
builder
function that tells Flutter what to render, depending on the state of theFuture
: loading, success, or error.
new FutureBuilder<Post>(
future: fetchPost(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return new Text(snapshot.data.title);
} else if (snapshot.hasError) {
return new Text("${snapshot.error}");
}
// By default, show a loading spinner
return new CircularProgressIndicator();
},
);
Complete Example
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
Future<Post> fetchPost() async {
final response =
await http.get('https://jsonplaceholder.typicode.com/posts/1');
final json = JSON.decode(response.body);
return new Post.fromJson(json);
}
class Post {
final int userId;
final int id;
final String title;
final String body;
Post({this.userId, this.id, this.title, this.body});
factory Post.fromJson(Map<String, dynamic> json) {
return new Post(
userId: json['userId'],
id: json['id'],
title: json['title'],
body: json['body'],
);
}
}
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Fetch Data Example',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new Scaffold(
appBar: new AppBar(
title: new Text('Fetch Data Example'),
),
body: new Center(
child: new FutureBuilder<Post>(
future: fetchPost(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return new Text(snapshot.data.title);
} else if (snapshot.hasError) {
return new Text("${snapshot.error}");
}
// By default, show a loading spinner
return new CircularProgressIndicator();
},
),
),
),
);
}
}