Using the HTTP Package in Dart
In the previous lesson, you learned how to work with APIs in Dart. Now, we will go deeper into the http package and understand how to use headers, query parameters, timeouts, and advanced request handling.
These concepts are critical for building real-world Dart applications such as dashboards, mobile apps, backend services, and CLI tools.
Why the HTTP Package Is Important
The http package allows Dart programs to:
- Send GET, POST, PUT, DELETE requests
- Attach headers like authentication tokens
- Send query parameters
- Handle API errors and timeouts
Basic HTTP Client
The simplest way to make a request is using http.get(),
but for large applications, using http.Client is recommended.
import 'package:http/http.dart' as http;
void main() async {
final client = http.Client();
final response = await client.get(
Uri.parse('https://jsonplaceholder.typicode.com/posts'),
);
print(response.statusCode);
print(response.body);
client.close();
}
Adding Headers to Requests
Headers are used for authentication, content type, and custom metadata.
Example: Sending a token with the request.
final response = await http.get(
Uri.parse('https://jsonplaceholder.typicode.com/posts'),
headers: {
'Authorization': 'Bearer my_api_token',
'Content-Type': 'application/json',
},
);
Headers are commonly used for:
- JWT authentication
- API keys
- Content negotiation
Using Query Parameters
Query parameters help filter or paginate API responses.
Example: Fetch posts for a specific user.
final uri = Uri.https(
'jsonplaceholder.typicode.com',
'/posts',
{'userId': '1'},
);
final response = await http.get(uri);
print(response.body);
This generates:
https://jsonplaceholder.typicode.com/posts?userId=1
POST Requests with JSON Data
When sending data to APIs, we usually send JSON.
final response = await http.post(
Uri.parse('https://jsonplaceholder.typicode.com/posts'),
headers: {
'Content-Type': 'application/json',
},
body: jsonEncode({
'title': 'New Dart Post',
'body': 'Learning HTTP in Dart',
'userId': 10,
}),
);
print(response.statusCode);
print(response.body);
PUT and DELETE Requests
PUT updates existing resources.
await http.put(
Uri.parse('https://jsonplaceholder.typicode.com/posts/1'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({
'title': 'Updated Title',
'body': 'Updated content',
}),
);
DELETE removes a resource.
await http.delete(
Uri.parse('https://jsonplaceholder.typicode.com/posts/1'),
);
Handling Timeouts
Network calls can fail or hang. Timeouts prevent your app from freezing.
try {
final response = await http
.get(Uri.parse('https://jsonplaceholder.typicode.com/posts'))
.timeout(Duration(seconds: 5));
print(response.body);
} catch (e) {
print('Request timed out or failed');
}
Handling Status Codes Properly
Always check HTTP status codes.
- 200–299 → Success
- 400–499 → Client errors
- 500+ → Server errors
if (response.statusCode == 200) {
print('Success');
} else {
print('Failed: ${response.statusCode}');
}
Reusable API Service Class
Large applications should separate API logic.
class ApiService {
final String baseUrl =
'https://jsonplaceholder.typicode.com';
Future fetchPosts() async {
final response =
await http.get(Uri.parse('$baseUrl/posts'));
if (response.statusCode == 200) {
return response.body;
} else {
throw Exception('API error');
}
}
}
Real-World Applications
- REST API integration
- Mobile app backends
- Authentication services
- Data-driven dashboards
📝 Practice Exercises
Exercise 1
Fetch comments using query parameters.
Exercise 2
Create a POST request with user input.
Exercise 3
Add timeout handling to an API call.
What’s Next?
In the next lesson, you will build command-line tools using Dart that consume APIs and handle user input.