HTTP Requests
HTTP Requests
HTTP ប្រើសម្រាប់ទាញយកទិន្នន័យពី API (Application Programming Interface)។ Flutter ប្រើ http
package ដើម្បី communicate ជាមួយ backend servers។
� HTTP & REST API Theory
HTTP Request Lifecycle:
HTTP Request Flow
📱 Flutter App
↓
1️⃣ Make Request (GET, POST, PUT, DELETE)
↓
🌐 Internet
↓
2️⃣ Server receives & processes request
↓
3️⃣ Server sends Response (JSON data + status code)
↓
4️⃣ Flutter parses JSON → Dart objects
↓
5️⃣ Update UI with new data
HTTP Methods (CRUD Operations):
Method | CRUD | Purpose | Example |
---|---|---|---|
GET |
Read | ទាញយកទិន្នន័យ | Get list of products |
POST |
Create | បង្កើតទិន្នន័យថ្មី | Create new user |
PUT |
Update | ធ្វើបច្ចុប្បន្នភាពទាំងអស់ | Update entire profile |
PATCH |
Update | ធ្វើបច្ចុប្បន្នភាពមួយផ្នែក | Update only email |
DELETE |
Delete | លុបទិន្នន័យ | Delete a post |
HTTP Status Codes:
Code Range | Meaning | Examples |
---|---|---|
2xx | ✅ Success | 200 OK, 201 Created |
3xx | 🔄 Redirection | 301 Moved Permanently |
4xx | ❌ Client Error | 400 Bad Request, 404 Not Found, 401 Unauthorized |
5xx | 💥 Server Error | 500 Internal Server Error, 503 Service Unavailable |
�📡 http package (Setup)
# pubspec.yaml
dependencies:
http: ^1.1.0
🔽 GET Request (Read Data)
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) {
var data = jsonDecode(response.body);
print(data);
}
}
📤 POST Request (Create Data)
import 'package:http/http.dart' as http;
import 'dart:convert';
Future<void> createUser(String name, String email) async {
try {
final response = await http.post(
Uri.parse('https://api.example.com/users'),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_TOKEN',
},
body: jsonEncode({
'name': name,
'email': email,
}),
);
if (response.statusCode == 201) {
print('User created successfully!');
var data = jsonDecode(response.body);
print('New user ID: ' + data['id'].toString());
} else {
print('Failed to create user: ' + response.statusCode.toString());
}
} catch (e) {
print('Error: ' + e.toString());
}
}
🔄 PUT/PATCH Request (Update Data)
// PUT - Update entire resource
Future<void> updateUser(int id, Map<String, dynamic> userData) async {
final response = await http.put(
Uri.parse('https://api.example.com/users/' + id.toString()),
headers: {'Content-Type': 'application/json'},
body: jsonEncode(userData),
);
if (response.statusCode == 200) {
print('User updated successfully!');
}
}
// PATCH - Update specific fields
Future<void> updateEmail(int id, String newEmail) async {
final response = await http.patch(
Uri.parse('https://api.example.com/users/' + id.toString()),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({'email': newEmail}),
);
}
🗑️ DELETE Request
Future<void> deleteUser(int id) async {
final response = await http.delete(
Uri.parse('https://api.example.com/users/' + id.toString()),
headers: {'Authorization': 'Bearer YOUR_TOKEN'},
);
if (response.statusCode == 204) {
print('User deleted successfully!');
}
}
🎯 Complete Example with Model Class
// Model class
class User {
final int id;
final String name;
final String email;
User({required this.id, required this.name, required this.email});
// Create User from JSON
factory User.fromJson(Map<String, dynamic> json) {
return User(
id: json['id'],
name: json['name'],
email: json['email'],
);
}
// Convert User to JSON
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'email': email,
};
}
}
// API Service class
class UserService {
final String baseUrl = 'https://api.example.com';
Future<List<User>> getUsers() async {
final response = await http.get(Uri.parse(baseUrl + '/users'));
if (response.statusCode == 200) {
List jsonData = jsonDecode(response.body);
return jsonData.map((json) => User.fromJson(json)).toList();
} else {
throw Exception('Failed to load users');
}
}
Future<User> getUserById(int id) async {
final response = await http.get(
Uri.parse(baseUrl + '/users/' + id.toString()),
);
if (response.statusCode == 200) {
return User.fromJson(jsonDecode(response.body));
} else {
throw Exception('User not found');
}
}
}
// Usage in Widget
class UserListPage extends StatefulWidget {
@override
_UserListPageState createState() => _UserListPageState();
}
class _UserListPageState extends State<UserListPage> {
final UserService _userService = UserService();
List<User> users = [];
bool isLoading = true;
@override
void initState() {
super.initState();
loadUsers();
}
Future<void> loadUsers() async {
try {
final fetchedUsers = await _userService.getUsers();
setState(() {
users = fetchedUsers;
isLoading = false;
});
} catch (e) {
setState(() {
isLoading = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: ' + e.toString())),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Users')),
body: isLoading
? Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
final user = users[index];
return ListTile(
title: Text(user.name),
subtitle: Text(user.email),
);
},
),
);
}
}
⚡ Error Handling Best Practices
Future<T> makeRequest<T>(
Future<http.Response> Function() request,
T Function(dynamic) parser,
) async {
try {
final response = await request();
// Check status code
if (response.statusCode >= 200 && response.statusCode < 300) {
return parser(jsonDecode(response.body));
} else if (response.statusCode == 401) {
throw Exception('Unauthorized - Please login');
} else if (response.statusCode == 404) {
throw Exception('Resource not found');
} else {
throw Exception('Error: ' + response.statusCode.toString());
}
} on SocketException {
throw Exception('No internet connection');
} on TimeoutException {
throw Exception('Request timeout');
} on FormatException {
throw Exception('Invalid response format');
} catch (e) {
throw Exception('Unexpected error: ' + e.toString());
}
}
🔐 Authentication with Headers
class AuthService {
String? _token;
Map<String, String> get headers {
return {
'Content-Type': 'application/json',
if (_token != null) 'Authorization': 'Bearer ' + _token!,
};
}
Future<void> login(String email, String password) async {
final response = await http.post(
Uri.parse('https://api.example.com/login'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({'email': email, 'password': password}),
);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
_token = data['token'];
}
}
Future<dynamic> get(String endpoint) async {
final response = await http.get(
Uri.parse('https://api.example.com' + endpoint),
headers: headers,
);
if (response.statusCode == 200) {
return jsonDecode(response.body);
}
}
}
💾 Caching Strategy
class CachedApiService {
final Map<String, dynamic> _cache = {};
final Duration cacheDuration = Duration(minutes: 5);
final Map<String, DateTime> _cacheTime = {};
Future<dynamic> getCached(String url) async {
// Check if cache exists and is valid
if (_cache.containsKey(url)) {
final cacheAge = DateTime.now().difference(_cacheTime[url]!);
if (cacheAge < cacheDuration) {
print('Using cached data');
return _cache[url];
}
}
// Fetch new data
final response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
_cache[url] = data;
_cacheTime[url] = DateTime.now();
return data;
}
}
void clearCache() {
_cache.clear();
_cacheTime.clear();
}
}
💡 Best Practices:
- ✅ Always use try-catch for error handling
- ✅ Create model classes for JSON parsing
- ✅ Use separate service classes for API calls
- ✅ Show loading indicators during requests
- ✅ Handle different status codes properly
- ✅ Implement caching for frequently accessed data
- ✅ Use environment variables for API URLs
⚠️ Common Mistakes:
- ❌ Not handling errors (app will crash)
- ❌ Hardcoding API tokens in code (security risk)
- ❌ Making API calls in build() method (infinite loop)
- ❌ Not showing loading state to users
- ❌ Ignoring HTTP status codes
💡 ជំនួយ: ប្រើ async/await សម្រាប់ HTTP requests។ ប្រើ try-catch សម្រាប់ handle errors។ ប្រើ Model classes សម្រាប់ type-safe data។