Flutter REST API
Connecting your Flutter app to web services
🌐 What is REST API?
REST API allows your Flutter app to communicate with web servers using HTTP requests. You can fetch data, send information, and interact with backend services to create dynamic, data-driven mobile applications.
// Simple GET request example
import 'package:http/http.dart' as http;
import 'dart:convert';
Future<void> fetchData() async {
final response = await http.get(
Uri.parse('https://api.example.com/data')
);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
print(data);
}
}
Key REST API Concepts
GET Request
Retrieve data from a server. Use GET to fetch information like user profiles, posts, or product lists from your backend API.
final response = await http.get(
Uri.parse('https://api.example.com/users')
);
POST Request
Send data to create new resources. Use POST to submit forms, create new users, or add items to your database through the API.
final response = await http.post(
Uri.parse('https://api.example.com/users'),
body: jsonEncode({'name': 'John'})
);
PUT/PATCH Request
Update existing data on the server. PUT replaces entire resources while PATCH updates specific fields, perfect for editing user profiles or settings.
final response = await http.put(
Uri.parse('https://api.example.com/users/1'),
body: jsonEncode({'name': 'Jane'})
);
DELETE Request
Remove data from the server. Use DELETE to remove users, posts, or any resources from your backend database through the API.
final response = await http.delete(
Uri.parse('https://api.example.com/users/1')
);
🔹 Setting Up HTTP Package
Add the http package to your Flutter project:
# pubspec.yaml
dependencies:
flutter:
sdk: flutter
http: ^1.1.0
// Import in your Dart file
import 'package:http/http.dart' as http;
import 'dart:convert';
Installation:
1. Add http to pubspec.yaml
2. Run:
flutter pub get
3. Import in your code
🔹 Fetching Data (GET)
Retrieve and display data from an API:
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
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'],
name: json['name'],
email: json['email'],
);
}
}
Future<List<User>> fetchUsers() async {
final response = await http.get(
Uri.parse('https://jsonplaceholder.typicode.com/users')
);
if (response.statusCode == 200) {
List jsonResponse = jsonDecode(response.body);
return jsonResponse.map((user) => User.fromJson(user)).toList();
} else {
throw Exception('Failed to load users');
}
}
class UserListScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Users')),
body: FutureBuilder<List<User>>(
future: fetchUsers(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(snapshot.data![index].name),
subtitle: Text(snapshot.data![index].email),
);
},
);
} else if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
}
return Center(child: CircularProgressIndicator());
},
),
);
}
}
Output:
✓ Displays a list of users from the API
✓ Shows loading indicator while fetching
✓ Handles errors gracefully
🔹 Sending Data (POST)
Create new resources on the server:
Future<User> createUser(String name, String email) async {
final response = await http.post(
Uri.parse('https://jsonplaceholder.typicode.com/users'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{
'name': name,
'email': email,
}),
);
if (response.statusCode == 201) {
return User.fromJson(jsonDecode(response.body));
} else {
throw Exception('Failed to create user');
}
}
// Usage in a widget
ElevatedButton(
onPressed: () async {
try {
final newUser = await createUser('John Doe', '[email protected]');
print('User created: ${newUser.name}');
} catch (e) {
print('Error: $e');
}
},
child: Text('Create User'),
)
What happens:
1. Sends user data to the server
2. Server creates new user
3. Returns created user with ID
4. Status code 201 means success
🔹 Updating Data (PUT)
Update existing resources:
Future<User> updateUser(int id, String name, String email) async {
final response = await http.put(
Uri.parse('https://jsonplaceholder.typicode.com/users/$id'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{
'name': name,
'email': email,
}),
);
if (response.statusCode == 200) {
return User.fromJson(jsonDecode(response.body));
} else {
throw Exception('Failed to update user');
}
}
// Usage
final updatedUser = await updateUser(1, 'Jane Doe', '[email protected]');
🔹 Deleting Data (DELETE)
Remove resources from the server:
Future<void> deleteUser(int id) async {
final response = await http.delete(
Uri.parse('https://jsonplaceholder.typicode.com/users/$id'),
);
if (response.statusCode == 200) {
print('User deleted successfully');
} else {
throw Exception('Failed to delete user');
}
}
// Usage with confirmation
IconButton(
icon: Icon(Icons.delete),
onPressed: () async {
final confirm = await showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Delete User?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: Text('Cancel'),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
child: Text('Delete'),
),
],
),
);
if (confirm == true) {
await deleteUser(userId);
}
},
)
🔹 Error Handling
Handle network errors and exceptions:
Future<List<User>> fetchUsersWithErrorHandling() async {
try {
final response = await http.get(
Uri.parse('https://jsonplaceholder.typicode.com/users'),
).timeout(Duration(seconds: 10));
if (response.statusCode == 200) {
List jsonResponse = jsonDecode(response.body);
return jsonResponse.map((user) => User.fromJson(user)).toList();
} else if (response.statusCode == 404) {
throw Exception('Resource not found');
} else if (response.statusCode == 500) {
throw Exception('Server error');
} else {
throw Exception('Failed to load users: ${response.statusCode}');
}
} on TimeoutException {
throw Exception('Request timeout - check your internet connection');
} on SocketException {
throw Exception('No internet connection');
} catch (e) {
throw Exception('Unexpected error: $e');
}
}