← All courses

Networking & JSON

🗓 May 31, 2026 ⏱ 2 min read

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 statusCode and error cases.
  • Calling fetchUsers() directly in build without FutureBuilder (it refetches on every rebuild) — cache it in state or a provider.
Summary: Use the http (or dio) package for REST calls, parse JSON into model classes with fromJson, and display async data cleanly with FutureBuilder. Keep networking in a repository for real apps.