In this section, we will explore how to use REST APIs in Flutter to fetch and manipulate data from a remote server. REST (Representational State Transfer) is a popular architectural style for designing networked applications, and it is widely used for web services.

Key Concepts

  1. HTTP Requests: Understanding the different types of HTTP requests (GET, POST, PUT, DELETE).
  2. HTTP Package: Using the http package in Flutter to make network requests.
  3. Asynchronous Programming: Handling asynchronous operations using async and await.
  4. Error Handling: Managing network errors and exceptions.
  5. JSON Parsing: Converting JSON data to Dart objects and vice versa.

HTTP Requests

HTTP requests are the foundation of REST APIs. Here are the most common types:

  • GET: Retrieve data from the server.
  • POST: Send data to the server to create a new resource.
  • PUT: Update an existing resource on the server.
  • DELETE: Remove a resource from the server.

Using the http Package

To make HTTP requests in Flutter, we use the http package. First, add the http package to your pubspec.yaml file:

dependencies:
  flutter:
    sdk: flutter
  http: ^0.13.3

Then, run flutter pub get to install the package.

Making a GET Request

Let's start with a simple GET request to fetch data from a REST API.

Example: Fetching Data from a REST API

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('REST API Example')),
        body: Center(child: DataFetcher()),
      ),
    );
  }
}

class DataFetcher extends StatefulWidget {
  @override
  _DataFetcherState createState() => _DataFetcherState();
}

class _DataFetcherState extends State<DataFetcher> {
  String data = 'Fetching data...';

  @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

  1. Importing Packages: We import the necessary packages, including http for making network requests and dart:convert for JSON parsing.
  2. Stateful Widget: We create a StatefulWidget to manage the state of the fetched data.
  3. fetchData Method: This method makes a GET request to a sample API and updates the state with the fetched data.
  4. Error Handling: We check the status code of the response to handle errors appropriately.

Making a POST Request

Next, let's see how to send data to a server using a POST request.

Example: Sending Data to a REST API

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('REST API Example')),
        body: Center(child: DataSender()),
      ),
    );
  }
}

class DataSender extends StatefulWidget {
  @override
  _DataSenderState createState() => _DataSenderState();
}

class _DataSenderState extends State<DataSender> {
  String responseMessage = 'Sending data...';

  Future<void> sendData() 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) {
      setState(() {
        responseMessage = 'Data sent successfully';
      });
    } else {
      setState(() {
        responseMessage = 'Failed to send data';
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        Text(responseMessage),
        ElevatedButton(
          onPressed: sendData,
          child: Text('Send Data'),
        ),
      ],
    );
  }
}

Explanation

  1. POST Request: We use the http.post method to send data to the server.
  2. Headers: We set the Content-Type header to application/json.
  3. Body: We encode the data as JSON using jsonEncode.
  4. Response Handling: We check the status code to determine if the data was sent successfully.

Practical Exercise

Task

Create a Flutter app that fetches a list of users from a REST API and displays their names in a ListView.

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('User List')),
        body: Center(child: UserList()),
      ),
    );
  }
}

class UserList extends StatefulWidget {
  @override
  _UserListState createState() => _UserListState();
}

class _UserListState extends State<UserList> {
  List<String> users = [];

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

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

    if (response.statusCode == 200) {
      final List<dynamic> data = json.decode(response.body);
      setState(() {
        users = data.map((user) => user['name'] as String).toList();
      });
    } else {
      setState(() {
        users = ['Failed to load users'];
      });
    }
  }

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

Explanation

  1. Fetching Users: We make a GET request to fetch a list of users.
  2. Parsing JSON: We parse the JSON response and extract the user names.
  3. Displaying Data: We use a ListView.builder to display the user names in a list.

Summary

In this section, we learned how to use REST APIs in Flutter to fetch and send data. We covered:

  • Making GET and POST requests using the http package.
  • Handling asynchronous operations with async and await.
  • Parsing JSON data.
  • Managing network errors.

In the next section, we will explore how to handle network errors more robustly and how to integrate more complex REST API interactions in your Flutter applications.

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