Data Fetching Basics in Flutter
Tags: dart, flutter
Published: 2019-11-06 13:52:46

_Read the original article [here](https://rahmanfadhil.com/flutter-data-fetching/)_

Great applications should provide useful information to their users. Therefore, displaying data from other source (server) is necessary for most application. Fortunately, Flutter gives us convenient tools out of the box to do such thing.

In Dart language, we can use a package called `http`. It‚Äôs a package that contains useful functions to send and retrieve data from HTTP server.

To install `http` package, add the following package to your `pubspec.yaml` file on your Flutter project.

```yaml
# ...

dependencies:
  http: <latest_version> # add this
```

In this tutorial, we will fetch some data from [JSONPlaceholder](https://jsonplaceholder.typicode.com). It's an open-source REST API that contains useful fake resources like blog posts, comments, photos, users, etc.

First, we can create a function that returns the response of our HTTP request. This function is asynchronous, so it should return a Future. Then, we need to check wether the response is successful or not by checking the HTTP status code. Finally, we decode our response body to with `jsonDecode` function and return it.

We also want to use the `http` package which we installed earlier.

```dart
import 'package:http/http.dart' as http;

Future<List<dynamic>> fetchPost() async {
  final response = await http.get('https://jsonplaceholder.typicode.com/posts/1');

  if (response.statusCode == 200) {
    List<dynamic> post = jsonDecode(response.body);
    return post;
  } else {
    throw Exception('Failed to load post');
  }
}
```

Now, look back to you Flutter widget where you want to make a request to the server. If your widget is now stateless, change it to stateful. Because, we want to store the response data to display it in our widget.

```dart
import 'package:flutter/material.dart';

class PostDetail extends StatefulWidget {
  @override
  _PostDetailState createState() => _PostDetailState();
}

class _PostDetailState extends State<PostDetail> {
  @override
  Widget build(BuildContext context) {
    // Your widgets
  }
}
```

Create an `initState` method in your widget. This method will be invoked whenever your flutter widget is ready to be displayed on the screen. From there, we will fetch our data and save the response to the widget state.

```dart
// ...

class _PostDetailState extends State<PostDetail> {
  Future<List<dynamic>> _post;

  @override
  void initState() {
    super.initState();

    _post = fetchPost();
  }

  @override
  Widget build(BuildContext context) {
    // Your widgets
  }
}
```

From there, we invoke our `fetchPost` function and store the response to the `post` widget state.

Remember, this data is asynchronous. So we can't just put the `post` state inside our build method directly.

One way to display asynchronous data is by using a widget called **FutureBuilder**. It's a widget provided by Flutter inside the [Flutter Material Library](https://api.flutter.dev/flutter/material/material-library.html). This widget makes us very easy to work with asynchronous data. It let us determine what to display when the data is loaded.

When using FutureBuilder widget, we need to define our Future, obviously, and a function that returns a widget.

```dart
// ...

class _PostDetailState extends State<PostDetail> {
  Future<List<dynamic>> _post;

  @override
  void initState() {
    super.initState();

    _post = fetchPost();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: _post,
      builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
        if (snapshot.hasData) {
          // Data fetched successfully, display your data here
          return Column(
            children: <Widget>[
              Text(snapshot.data['title']),
              Text(snapshot.data['content'])
            ],
          );
        } else if (snapshot.hasError) {
          // If something went wrong
          return Text('Something went wrong...');
        }

        // While fetching, show a loading spinner.
        return CircularProgressIndicator();
      }
    )
  }
}
```

The `builder` function gets two parameters. The BuildContext, and an AsyncSnapshot. The AsyncSnaphot object, which we defined as `snapshot`, has the `hasData` and `hasError` properties, which very useful to check if there is an error. Finally, while the request is still going on, we can display a loading spinner.