- Flutter Development Tutorial (Beginner to Intermediate)
- Part 1: Introduction to Flutter and Environment Setup
- Part 2: Dart Basics for Flutter
- Part 3: Understanding Widgets and Building UI
- Part 4: Navigation and Routing
- Part 5: Working with Forms and Input Handling
- Part 6: Lists, Grids, and Dynamic Content
- Part 7: Advanced State Management
13. API Integration in Flutter (HTTP Requests)
Most mobile apps require data from remote servers or APIs. Flutter supports making HTTP requests to fetch data from RESTful services.
13.1 Adding HTTP Dependency
To make HTTP requests, add the http package in pubspec.yaml:
dependencies:
http: ^0.13.0
13.2 Making a GET Request
Using http.get() allows you to fetch data from an API. Wrap it in an async function and use FutureBuilder to display the data.
Example: Simple GET Request
import 'package:http/http.dart' as http;
import 'dart:convert';
Future<List<String>> fetchItems() async {
final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts'));
if (response.statusCode == 200) {
final List<dynamic> data = jsonDecode(response.body);
return data.map((item) => item['title'].toString()).toList();
} else {
throw Exception('Failed to load items');
}
}
class ApiExample extends StatefulWidget {
@override
_ApiExampleState createState() => _ApiExampleState();
}
class _ApiExampleState extends State<ApiExample> {
late Future<List<String>> items;
@override
void initState() {
super.initState();
items = fetchItems();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('API Example')),
body: FutureBuilder<List<String>>(
future: items,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
} else {
return ListView(
children: snapshot.data!.map((item) => ListTile(title: Text(item))).toList(),
);
}
},
),
);
}
}
Handling Errors and Timeout
final response = await http.get(
Uri.parse('https://jsonplaceholder.typicode.com/posts'),
headers: {'Authorization': 'Bearer your_api_key'},
).timeout(Duration(seconds: 5), onTimeout: () {
throw Exception('Request timed out');
});
Best Practices for API Integration:
- Use try-catch blocks to handle potential errors.
- Optimize API calls by using caching mechanisms, pagination, and debouncing (for search features).
- Always handle slow connections using timeout() and retry logic.
14. Error Handling in Flutter
Proper error handling is crucial for building stable apps. Flutter provides tools to catch errors and display user-friendly messages when things go wrong.
14.1 Using try-catch for Errors
Wrap asynchronous code in try-catch blocks to handle exceptions gracefully.
Example: Basic Error Handling
void fetchData() async {
try {
final response = await http.get(Uri.parse('https://example.com/data'));
if (response.statusCode == 200) {
// Parse the data
} else {
throw Exception('Failed to load data');
}
} catch (error) {
print('Error: $error');
}
}
14.2 Global Error Handling with FlutterError
You can handle uncaught exceptions globally using FlutterError.onError:
void main() {
FlutterError.onError = (FlutterErrorDetails details) {
FlutterError.presentError(details);
// Optionally report error to external service
};
runApp(MyApp());
}
14.3 Error Handling in UI with FutureBuilder
When using FutureBuilder, always check for errors and handle them appropriately.
Example: Handling Errors in UI
return FutureBuilder<List<String>>(
future: items,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return ListView(...);
}
},
)
Best Practices for Error Handling:
- Handle both synchronous and asynchronous errors: Use try-catch for handling runtime exceptions in asynchronous code and other strategies like assertions for synchronous code.
- Display user-friendly messages: Always catch errors gracefully and provide informative feedback to the user, such as “Something went wrong. Please try again.”
- Log errors: Use error tracking tools (such as Firebase Crashlytics, Sentry, etc.) to log errors for future debugging.
- Avoid error silencing: Do not suppress exceptions without proper handling—this could mask bugs and lead to hard-to-trace issues.