Intermediate

Working with APIs in Flutter: Fetching and Displaying Data

Most modern apps rely on APIs (Application Programming Interfaces) to fetch live data — whether it’s showing weather updates, stock prices, news feeds, or social media posts. In Flutter, integrating APIs is straightforward thanks to its powerful networking libraries.

In this post, we’ll walk through the basics of fetching and displaying data from APIs in a Flutter app.


Why Use APIs in Flutter Apps?

APIs allow your app to:

  • Access real-time data from servers.
  • Connect with third-party services like Google, Stripe, or OpenAI.
  • Keep your app lightweight by storing heavy data on servers.
  • Provide dynamic and interactive experiences for users.

Step 1: Add the http Package

The simplest way to make API calls in Flutter is by using the http package.

Add it to your pubspec.yaml:

dependencies:
  http: ^0.13.6

Then import it into your Dart file:

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

Step 2: Fetch Data from an API

Here’s a simple example of fetching data from a public JSON API:

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

  if (response.statusCode == 200) {
    return jsonDecode(response.body);
  } else {
    throw Exception('Failed to load data');
  }
}

This function makes a GET request to an API and decodes the JSON response into a Dart object.


Step 3: Display Data in a Widget

You can use FutureBuilder to display data once it’s fetched:

class ApiExample extends StatelessWidget {
  final Future<List<dynamic>> posts = fetchPosts();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('API Example')),
      body: FutureBuilder<List<dynamic>>(
        future: posts,
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return Center(child: CircularProgressIndicator());
          } else if (snapshot.hasError) {
            return Center(child: Text('Error: ${snapshot.error}'));
          } else {
            return ListView.builder(
              itemCount: snapshot.data!.length,
              itemBuilder: (context, index) {
                return ListTile(
                  title: Text(snapshot.data![index]['title']),
                  subtitle: Text(snapshot.data![index]['body']),
                );
              },
            );
          }
        },
      ),
    );
  }
}

This creates a list of posts fetched from the API and displays them in a scrollable view.


Step 4: Handle Errors & Loading States

Always handle:

  • Loading state → Show a spinner.
  • Error state → Show a friendly error message.
  • Empty state → Show a “No Data Available” message.

Step 5: Use Advanced Tools (Optional)

For larger projects, consider:

  • Dio → A powerful alternative to http with interceptors and advanced config.
  • Retrofit → A code generator that simplifies API integration.
  • Provider / Riverpod / Bloc → For managing state across the app.

Best Practices

  • Keep API logic separate from UI (e.g., in a service class).
  • Avoid hardcoding URLs — use environment configs.
  • Implement caching for frequently used data.
  • Secure your API keys with .env files or Firebase Remote Config.

Conclusion

Working with APIs in Flutter is both powerful and flexible. By combining the http package (or alternatives) with FutureBuilder and clean state management, you can build apps that fetch and display data in real-time across mobile, web, and desktop.

With just a few lines of code, you’ve connected your Flutter app to the world of live data!

Leave a Reply

Your email address will not be published. Required fields are marked *