flutter_api_helper
Um poderoso e fácil de usar ajudante de API para Flutter que cuida de tudo, desde simples requisições GET até tratamento complexo de erros, cache e gerenciamento de tokens.
ranahammad7/flutter_api_helper open-source repository details.
{"sdk":"flutter"}^1.1.0^2.2.2^5.0.1^1.9.1{"sdk":"flutter"}^3.0.0^5.4.2^2.4.7Texto original em inglês. Visite o GitHub para a versão atual.
pub package License: MIT GitHub stars Flutter
Built-in caching • Smart retry logic • Seamless widget integration
|
✅ Simple API - Intuitive methods for all HTTP operations |
✅ Network Aware - Built-in connectivity checking |
| 🆚 Comparison | Built-in HTTP | Flutter API Helper |
|---|---|---|
| Setup | Complex boilerplate | ✨ One-line configuration |
| Caching | Manual implementation | 🧠 Smart auto-caching |
| Retries | Custom retry logic | 🔄 Exponential backoff |
| Errors | Generic exceptions | 🛡️ Typed error handling |
| Files | Complex multipart | 📁 Simple upload/download |
| Widgets | Custom FutureBuilder | 🎯 Ready ApiBuilder |
Add this to your package's pubspec.yaml file:
dependencies:
flutter_api_helper: ^1.0.0
Then run:
flutter pub get
import 'package:flutter_api_helper/flutter_api_helper.dart';
void main() {
// 🔧 Configure once, use everywhere
ApiHelper.configure(
ApiConfig(
baseUrl: 'https://api.yourapp.com',
enableLogging: true,
timeout: Duration(seconds: 30),
// 🧠 Smart caching out of the box
cacheConfig: CacheConfig(duration: Duration(minutes: 5)),
// 🔄 Auto-retry with exponential backoff
retryConfig: RetryConfig(maxRetries: 3),
),
);
runApp(MyApp());
}
// GET request with automatic type casting
final users = await ApiHelper.get<List<User>>('/users');
// POST request with smart error handling
final newUser = await ApiHelper.post('/users', data: {
'name': 'John Doe',
'email': 'john@example.com',
});
// PUT request with caching
final updatedUser = await ApiHelper.put('/users/1',
data: {'name': 'Jane Doe'},
cache: CacheConfig(duration: Duration(minutes: 10)),
);
// DELETE request with retry logic
await ApiHelper.delete('/users/1',
retry: RetryConfig(maxRetries: 5),
);
Transform your UI with the ApiBuilder widget:
class UsersList extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ApiBuilder<List<User>>(
future: ApiHelper.get('/users'),
builder: (users) => ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
final user = users[index];
return ListTile(
leading: CircleAvatar(child: Text(user.name[0])),
title: Text(user.name),
subtitle: Text(user.email),
);
},
),
loading: Center(child: CircularProgressIndicator()),
error: (error) => ErrorWidget('Failed to load users: ${error.message}'),
empty: Center(child: Text('No users found')),
);
}
}
// 🧠 Cache response for 10 minutes
final posts = await ApiHelper.get(
'/posts',
cache: CacheConfig(duration: Duration(minutes: 10)),
);
// 🗑️ Clear cache when needed
await ApiHelper.clearCache();
await ApiHelper.clearCacheForUrl('/posts');
ApiHelper.configure(
ApiConfig(
baseUrl: 'https://api.yourapp.com',
// 🔑 Automatic token injection
getToken: () async => await TokenStorage.getToken(),
// 🔄 Automatic token refresh
onTokenExpired: () async => await AuthService.refreshToken(),
),
);
// 📤 Upload with real-time progress
final file = File('/path/to/image.jpg');
final response = await ApiHelper.uploadFile(
'/upload',
file,
fieldName: 'image',
fields: {'description': 'Profile picture'},
onProgress: (sent, total) {
final percentage = (sent / total * 100).round();
print('Upload Progress: $percentage%');
},
);
// 📥 Download with progress tracking
await ApiHelper.downloadFile(
'/files/document.pdf',
'/local/path/document.pdf',
onProgress: (received, total) {
final percentage = (received / total * 100).round();
print('Download Progress: $percentage%');
},
);
try {
final data = await ApiHelper.get('/api/data');
// Handle success
} catch (e) {
if (e is ApiError) {
switch (e.type) {
case ApiErrorType.network:
showSnackBar('Check your internet connection');
break;
case ApiErrorType.server:
showSnackBar('Server is temporarily unavailable');
break;
case ApiErrorType.timeout:
showSnackBar('Request timed out. Please try again');
break;
case ApiErrorType.authentication:
redirectToLogin();
break;
default:
showSnackBar('Something went wrong: ${e.message}');
}
}
}
final data = await ApiHelper.get(
'/unstable-endpoint',
retry: RetryConfig(
maxRetries: 5,
retryDelay: Duration(seconds: 2),
useExponentialBackoff: true, // 2s, 4s, 8s, 16s, 32s
maxRetryDelay: Duration(seconds: 30),
),
);
class AuthInterceptor extends ApiInterceptor {
@override
Future<void> onRequest(String method, String url,
Map<String, String>? headers, dynamic data) async {
headers?['Authorization'] = 'Bearer ${await getToken()}';
headers?['User-Agent'] = 'MyApp/1.0';
}
@override
Future<void> onResponse(http.Response response) async {
if (response.statusCode == 401) {
await refreshToken();
}
// Log analytics
Analytics.trackApiCall(response.request?.url.toString());
}
}
// Add the interceptor
ApiHelper.instance.addInterceptor(AuthInterceptor());
ApiConfig(
baseUrl: 'https://api.example.com', // 🌐 Base URL for all requests
defaultHeaders: {'Accept': 'application/json'}, // 📋 Default headers
timeout: Duration(seconds: 30), // ⏱️ Request timeout
enableLogging: true, // 📝 Enable request/response logging
getToken: () async => 'your-token', // 🔑 Token getter function
onTokenExpired: () async => refreshToken(), // 🔄 Token refresh callback
onError: (error) => handleError(error), // 🚨 Global error handler
retryConfig: RetryConfig(...), // 🔄 Default retry configuration
cacheConfig: CacheConfig(...), // 💾 Default cache configuration
)
CacheConfig(
duration: Duration(minutes: 5), // ⏰ How long to cache responses
keyPrefix: 'myapp_', // 🏷️ Prefix for cache keys
useMemoryCache: true, // 🧠 Enable in-memory cache
useDiskCache: true, // 💽 Enable persistent disk cache
maxCacheSize: 10 * 1024 * 1024, // 📏 Maximum cache size (10MB)
)
RetryConfig(
maxRetries: 3, // 🔢 Maximum retry attempts
retryDelay: Duration(seconds: 1), // ⏱️ Initial delay between retries
useExponentialBackoff: true, // 📈 Use exponential backoff strategy
maxRetryDelay: Duration(seconds: 30), // ⏰ Maximum delay between retries
retryStatusCodes: [408, 429, 500, 502, 503, 504], // 📋 HTTP status codes to retry
)
The package provides detailed error classification:
| Error Type | Description | Common Causes |
|---|---|---|
ApiErrorType.network |
Network connectivity issues | No internet, DNS issues |
ApiErrorType.timeout |
Request timeout errors | Slow connection, server overload |
ApiErrorType.server |
Server errors (5xx status codes) | Internal server error, maintenance |
ApiErrorType.client |
Client errors (4xx status codes) | Bad request, unauthorized |
ApiErrorType.authentication |
Authentication/authorization errors | Invalid token, expired session |
ApiErrorType.parsing |
JSON parsing errors | Malformed response, unexpected format |
ApiErrorType.unknown |
Unclassified errors | Unexpected exceptions |
The package is designed to be testable. You can easily mock API responses:
void main() {
group('API Tests', () {
test('should fetch users successfully', () async {
// Mock your API calls here
final users = await ApiHelper.get<List<User>>('/users');
expect(users, isA<List<User>>());
expect(users.isNotEmpty, true);
});
test('should handle network errors gracefully', () async {
expect(
() => ApiHelper.get('/invalid-endpoint'),
throwsA(isA<ApiError>()),
);
});
});
}
| Platform | Status | Notes |
|---|---|---|
| Android | ✅ | Full support |
| iOS | ✅ | Full support |
| Web | ✅ | Full support |
| macOS | ✅ | Full support |
| Windows | ✅ | Full support |
| Linux | ✅ | Full support |
>=3.0.0>=2.17.0For complete examples, check out the example folder which includes:
We welcome contributions! Please see our Contributing Guide for details.
git checkout -b feature/amazing-feature)git commit -m 'Add amazing feature')git push origin feature/amazing-feature)See CHANGELOG.md for a detailed history of changes.
This project is licensed under the MIT License - see the LICENSE file for details.
If this package helped you, please consider giving it a ⭐ on GitHub!