Calling APIs with the http Package
Making network requests, decoding JSON, and modeling API responses as Dart classes.
読了時間 2 分
Most real apps need to talk to a server. Flutter doesn't include a networking client in the framework itself — the standard choice is the http package, maintained by the Dart team.
Adding the dependency
dependencies:
http: ^1.2.0Run flutter pub get after adding it, then import it where needed:
import 'package:http/http.dart' as http;Making a GET request
Future<void> fetchUser() async {
final response = await http.get(
Uri.parse('https://api.example.com/users/1'),
);
if (response.statusCode == 200) {
print(response.body);
} else {
throw Exception('Failed to load user: ${response.statusCode}');
}
}http.get returns a Future<Response>, which is why this function is async and uses await — nothing here is Flutter-specific, it's the same async/await pattern from Dart itself. Always check statusCode before trusting response.body — a non-200 response (a 404, a 500) still returns a body, just not the one your code expects.
Decoding JSON into a Dart class
response.body is a raw JSON string. Decode it with dart:convert, and map the result onto a proper class rather than passing raw Map<String, dynamic> objects around your app:
import 'dart:convert';
class User {
final int id;
final String name;
final String email;
User({required this.id, required this.name, required this.email});
factory User.fromJson(Map<String, dynamic> json) {
return User(
id: json['id'] as int,
name: json['name'] as String,
email: json['email'] as String,
);
}
}
Future<User> fetchUser() async {
final response = await http.get(Uri.parse('https://api.example.com/users/1'));
if (response.statusCode != 200) {
throw Exception('Failed to load user');
}
final json = jsonDecode(response.body) as Map<String, dynamic>;
return User.fromJson(json);
}A factory constructor like User.fromJson is the standard Dart pattern for this: it takes a raw decoded map and produces a fully-typed instance, so the rest of your app works with user.name and gets compile-time errors for typos, instead of working with json['nmae'] and getting a silent null at runtime.
Sending data with POST
Future<void> createUser(String name, String email) async {
final response = await http.post(
Uri.parse('https://api.example.com/users'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({'name': name, 'email': email}),
);
if (response.statusCode != 201) {
throw Exception('Failed to create user');
}
}Setting the Content-Type header and encoding the body with jsonEncode are both necessary — without the header, many servers won't parse the body as JSON regardless of its actual content.
Handling failure paths
Networks fail — a request can throw before it even gets a response (no connectivity, DNS failure, timeout):
try {
final user = await fetchUser();
print('Loaded ${user.name}');
} catch (e) {
print('Something went wrong: $e');
}The next lesson covers FutureBuilder, which is how you connect a Future like fetchUser() to the widget tree so loading and error states show up in the UI itself, instead of only in print statements.