Fetching and displaying data from an API is a common task in Flutter app development. In this tutorial, you’ll learn how to display API data in a ListView
using the Dart programming language in a Flutter application. This approach helps create dynamic and real-time user interfaces based on external data sources.

We’ll use the http
package to fetch JSON data from a sample REST API and render it neatly in a ListView
. This is a beginner-friendly example that demonstrates working with network requests, decoding JSON, and managing state with FutureBuilder
.
Step 1: Add Dependencies
Add the http
package to your pubspec.yaml
:
dependencies: flutter: sdk: flutter http: ^0.13.6
Run flutter pub get
to install the dependencies.
Step 2: Create Model Class
Create a file post_model.dart
:
// post_model.dart class Post { final int id; final String title; final String body; Post({required this.id, required this.title, required this.body}); factory Post.fromJson(Map<String, dynamic> json) { return Post( id: json['id'], title: json['title'], body: json['body'], ); } }
Step 3: Create API Service
Create a file api_service.dart
:
// api_service.dart import 'dart:convert'; import 'package:http/http.dart' as http; import 'post_model.dart'; class ApiService { static const String url = 'https://jsonplaceholder.typicode.com/posts'; static Future<List<Post>> fetchPosts() async { final response = await http.get(Uri.parse(url)); if (response.statusCode == 200) { List jsonData = json.decode(response.body); return jsonData.map((data) => Post.fromJson(data)).toList(); } else { throw Exception('Failed to load posts'); } } }
Step 4: Build UI with ListView
Edit your main.dart
:
// main.dart import 'package:flutter/material.dart'; import 'api_service.dart'; import 'post_model.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'API ListView Demo', home: PostListScreen(), ); } } class PostListScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Posts from API')), body: FutureBuilder<List<Post>>( future: ApiService.fetchPosts(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return Center(child: CircularProgressIndicator()); } else if (snapshot.hasError) { return Center(child: Text('Error: ${snapshot.error}')); } else if (!snapshot.hasData || snapshot.data!.isEmpty) { return Center(child: Text('No posts available')); } final posts = snapshot.data!; return ListView.builder( itemCount: posts.length, itemBuilder: (context, index) { final post = posts[index]; return ListTile( title: Text(post.title), subtitle: Text(post.body), ); }, ); }, ), ); } }
By using FutureBuilder
, this example simplifies handling asynchronous operations and displaying the results in real time. You can further enhance this with pagination or error retry features.
For more about handling APIs in Flutter, refer to the Flutter networking guide.