Setup
Add the http package to your pubspec.yaml:
dependencies:
http: ^1.1.0
Then run dart pub get and import it:
import 'package:http/http.dart' as http;
import 'dart:convert';
GET Requests
Future<void> fetchPosts() async {
var url = Uri.parse('https://jsonplaceholder.typicode.com/posts');
var response = await http.get(url);
if (response.statusCode == 200) {
var posts = jsonDecode(response.body) as List;
print('Loaded $${posts.length} posts');
for (var post in posts.take(3)) {
print('- $${post['title']}');
}
} else {
print('Failed: $${response.statusCode}');
}
}
// With headers and query parameters:
Future<void> fetchWithParams() async {
var uri = Uri.https('api.example.com', '/users', {
'page': '1',
'limit': '10',
});
var response = await http.get(uri, headers: {
'Authorization': 'Bearer your-token-here',
'Accept': 'application/json',
});
print(response.body);
}
POST Requests
Future<Map<String, dynamic>> createPost(String title, String body) async {
var url = Uri.parse('https://jsonplaceholder.typicode.com/posts');
var response = await http.post(
url,
headers: {
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode({
'title': title,
'body': body,
'userId': 1,
}),
);
if (response.statusCode == 201) {
return jsonDecode(response.body);
}
throw Exception('Failed to create post: $${response.statusCode}');
}
void main() async {
var post = await createPost('My Dart Post', 'Learning HTTP in Dart');
print('Created: $${post['id']}');
}
Error Handling
import 'package:http/http.dart' as http;
Future<String> safeFetch(String url) async {
try {
var response = await http.get(Uri.parse(url))
.timeout(Duration(seconds: 10)); // timeout!
if (response.statusCode >= 400) {
throw HttpException('HTTP $${response.statusCode}', uri: Uri.parse(url));
}
return response.body;
} on SocketException {
throw Exception('No internet connection');
} on TimeoutException {
throw Exception('Request timed out');
} on HttpException catch (e) {
throw Exception('HTTP error: $e');
}
}
HTTP Client Wrapper
class ApiService {
static const _base = 'https://jsonplaceholder.typicode.com';
final _client = http.Client();
Map<String, String> get _headers => {
'Content-Type': 'application/json',
'Accept': 'application/json',
};
Future<T> _get<T>(String path, T Function(dynamic) parser) async {
final res = await _client.get(Uri.parse('$_base$path'), headers: _headers);
if (res.statusCode != 200) throw Exception('Error $${res.statusCode}');
return parser(jsonDecode(res.body));
}
Future<List<Map>> getPosts() =>
_get('/posts', (body) => (body as List).cast<Map>());
Future<Map> getPost(int id) =>
_get('/posts/$id', (body) => body as Map);
void dispose() => _client.close();
}
void main() async {
var api = ApiService();
try {
var posts = await api.getPosts();
print('Total: $${posts.length}');
var post = await api.getPost(1);
print('Post 1: $${post['title']}');
} finally {
api.dispose();
}
}
🧠 Quiz
1. What HTTP status code indicates a resource was successfully created?
- A) 200
- B) 201 ✅
- C) 204
- D) 301
2. Why should you use http.Client() instead of top-level http.get() in long-running apps?
- A) It is faster
- B) It reuses connections for better performance and allows proper cleanup ✅
- C) It supports HTTPS
- D) It handles JSON automatically
Summary
Use the http package (dart pub add http) for HTTP requests. http.get() for data retrieval, http.post() for creating resources. Always check response.statusCode. Use http.Client() for connection reuse in production. Add timeout with .timeout(Duration(...)) and handle SocketException for network errors.