In this section, we will learn how to fetch data from the internet in a Flutter application. This is a crucial skill for building modern, data-driven applications. We will cover the following topics:

  1. Introduction to HTTP Requests
  2. Using the http Package
  3. Making GET Requests
  4. Making POST Requests
  5. Handling Responses
  6. Practical Example
  7. Exercises

  1. Introduction to HTTP Requests

HTTP (HyperText Transfer Protocol) is the foundation of any data exchange on the Web. It is a protocol used for fetching resources such as HTML documents. It is the basis of any data exchange on the Web and a protocol used by the World Wide Web.

  1. Using the http Package

Flutter provides the http package to make HTTP requests. To use this package, you need to add it to your pubspec.yaml file.

dependencies:
  http: ^0.13.3

After adding the dependency, run flutter pub get to install the package.

  1. Making GET Requests

A GET request is used to request data from a specified resource. Here is how you can make a GET request using the http package.

Example

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Fetch Data Example')),
        body: Center(child: FetchData()),
      ),
    );
  }
}

class FetchData extends StatefulWidget {
  @override
  _FetchDataState createState() => _FetchDataState();
}

class _FetchDataState extends State<FetchData> {
  String data = "Loading...";

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

  Future<void> fetchData() async {
    final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts/1'));

    if (response.statusCode == 200) {
      setState(() {
        data = json.decode(response.body)['title'];
      });
    } else {
      setState(() {
        data = "Failed to load data";
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Text(data);
  }
}

Explanation

  • Importing Packages: We import the http package and dart:convert for JSON decoding.
  • Making the Request: We use http.get to make a GET request to the specified URL.
  • Handling the Response: If the response status code is 200 (OK), we decode the JSON and update the state. Otherwise, we display an error message.

  1. Making POST Requests

A POST request is used to send data to a server to create/update a resource. Here is how you can make a POST request.

Example

Future<void> postData() async {
  final response = await http.post(
    Uri.parse('https://jsonplaceholder.typicode.com/posts'),
    headers: <String, String>{
      'Content-Type': 'application/json; charset=UTF-8',
    },
    body: jsonEncode(<String, String>{
      'title': 'foo',
      'body': 'bar',
      'userId': '1',
    }),
  );

  if (response.statusCode == 201) {
    print('Data posted successfully');
  } else {
    print('Failed to post data');
  }
}

Explanation

  • Making the Request: We use http.post to make a POST request to the specified URL.
  • Headers: We set the Content-Type header to application/json.
  • Body: We encode the data to JSON format.
  • Handling the Response: If the response status code is 201 (Created), we print a success message. Otherwise, we print an error message.

  1. Handling Responses

Handling responses is crucial for ensuring that your app behaves correctly based on the server's response. Always check the status code and handle errors appropriately.

Common Status Codes

Status Code Description
200 OK
201 Created
400 Bad Request
401 Unauthorized
404 Not Found
500 Internal Server Error

  1. Practical Example

Let's create a practical example where we fetch a list of posts from an API and display them in a list.

Example

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Fetch Data Example')),
        body: Center(child: FetchData()),
      ),
    );
  }
}

class FetchData extends StatefulWidget {
  @override
  _FetchDataState createState() => _FetchDataState();
}

class _FetchDataState extends State<FetchData> {
  List<dynamic> data = [];

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

  Future<void> fetchData() async {
    final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts'));

    if (response.statusCode == 200) {
      setState(() {
        data = json.decode(response.body);
      });
    } else {
      setState(() {
        data = [];
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: data.length,
      itemBuilder: (context, index) {
        return ListTile(
          title: Text(data[index]['title']),
          subtitle: Text(data[index]['body']),
        );
      },
    );
  }
}

Explanation

  • Fetching Data: We fetch a list of posts from the API.
  • Displaying Data: We use a ListView.builder to display the data in a list.

  1. Exercises

Exercise 1: Fetch and Display User Data

  1. Fetch user data from https://jsonplaceholder.typicode.com/users.
  2. Display the user names in a list.

Solution

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Fetch User Data')),
        body: Center(child: FetchUserData()),
      ),
    );
  }
}

class FetchUserData extends StatefulWidget {
  @override
  _FetchUserDataState createState() => _FetchUserDataState();
}

class _FetchUserDataState extends State<FetchUserData> {
  List<dynamic> users = [];

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

  Future<void> fetchUserData() async {
    final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/users'));

    if (response.statusCode == 200) {
      setState(() {
        users = json.decode(response.body);
      });
    } else {
      setState(() {
        users = [];
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: users.length,
      itemBuilder: (context, index) {
        return ListTile(
          title: Text(users[index]['name']),
        );
      },
    );
  }
}

Exercise 2: Post Data to an API

  1. Create a form to input a title and body.
  2. Post the data to https://jsonplaceholder.typicode.com/posts.

Solution

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Post Data Example')),
        body: Center(child: PostDataForm()),
      ),
    );
  }
}

class PostDataForm extends StatefulWidget {
  @override
  _PostDataFormState createState() => _PostDataFormState();
}

class _PostDataFormState extends State<PostDataForm> {
  final _formKey = GlobalKey<FormState>();
  String title = '';
  String body = '';

  Future<void> postData() async {
    final response = await http.post(
      Uri.parse('https://jsonplaceholder.typicode.com/posts'),
      headers: <String, String>{
        'Content-Type': 'application/json; charset=UTF-8',
      },
      body: jsonEncode(<String, String>{
        'title': title,
        'body': body,
        'userId': '1',
      }),
    );

    if (response.statusCode == 201) {
      print('Data posted successfully');
    } else {
      print('Failed to post data');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        children: <Widget>[
          TextFormField(
            decoration: InputDecoration(labelText: 'Title'),
            onSaved: (value) {
              title = value!;
            },
          ),
          TextFormField(
            decoration: InputDecoration(labelText: 'Body'),
            onSaved: (value) {
              body = value!;
            },
          ),
          ElevatedButton(
            onPressed: () {
              if (_formKey.currentState!.validate()) {
                _formKey.currentState!.save();
                postData();
              }
            },
            child: Text('Submit'),
          ),
        ],
      ),
    );
  }
}

Conclusion

In this section, we learned how to fetch data from the internet using the http package in Flutter. We covered making GET and POST requests, handling responses, and implemented practical examples. We also provided exercises to reinforce the learned concepts. In the next section, we will learn how to parse JSON data.

Flutter Development Course

Module 1: Introduction to Flutter

Module 2: Dart Programming Basics

Module 3: Flutter Widgets

Module 4: State Management

Module 5: Navigation and Routing

Module 6: Networking and APIs

Module 7: Persistence and Storage

Module 8: Advanced Flutter Concepts

Module 9: Testing and Debugging

Module 10: Deployment and Maintenance

Module 11: Flutter for Web and Desktop

© Copyright 2024. All rights reserved