Networking & JSON
Making HTTP requests
The simplest way to call an API is the official http package. Add it with flutter pub add http, then make async requests.
import 'package:http/http.dart' as http;
import 'dart:convert';
Future<List<dynamic>> fetchRaw() async {
final res = await http.get(Uri.parse('https://api.example.com/users'));
if (res.statusCode == 200) {
return jsonDecode(res.body); // turn JSON text into Dart maps/lists
}
throw Exception('Failed: ${res.statusCode}');
}
Parsing JSON into model classes
Instead of working with untyped maps, convert JSON into your own classes with a fromJson factory — safer and far easier to use.
class User {
final int id;
final String name;
User({required this.id, required this.name});
factory User.fromJson(Map<String, dynamic> json) => User(
id: json['id'],
name: json['name'],
);
}
Future<List<User>> fetchUsers() async {
final res = await http.get(Uri.parse('https://api.example.com/users'));
final List data = jsonDecode(res.body);
return data.map((j) => User.fromJson(j)).toList();
}
Showing data with FutureBuilder
FutureBuilder handles the three states of async data — loading, error, success — in one widget.
FutureBuilder<List<User>>(
future: fetchUsers(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
}
final users = snapshot.data!;
return ListView.builder(
itemCount: users.length,
itemBuilder: (_, i) => ListTile(title: Text(users[i].name)),
);
},
)
POST requests
await http.post(
Uri.parse('https://api.example.com/users'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({'name': 'Anand'}),
);
Better networking: dio & repositories
For real apps, the dio package adds interceptors, timeouts and easier error handling. Wrap your API calls in a repository class so your widgets/state code stays clean and the network details live in one place.
Common mistakes
- Working with raw JSON maps instead of typed model classes.
- Ignoring
statusCodeand error cases. - Calling
fetchUsers()directly inbuildwithout FutureBuilder (it refetches on every rebuild) — cache it in state or a provider.
Summary: Use thehttp(ordio) package for REST calls, parse JSON into model classes withfromJson, and display async data cleanly withFutureBuilder. Keep networking in a repository for real apps.