Dio API Services
A comprehensive Flutter package that provides a robust HTTP client service built on top of Dio, featuring automatic retry mechanisms, intelligent logging, connectivity checking, and error handling for seamless API integration.
Features
✨ Smart HTTP Client: Built on Dio with enhanced functionality
🔄 Automatic Retry: Configurable retry logic with exponential backoff
📱 Connectivity Aware: Automatic network status checking
📝 Advanced Logging: Comprehensive request/response logging with overlay UI
🛡️ Error Handling: Intelligent error parsing and user-friendly messages
⚡ Performance Optimized: Efficient request/response handling
🎯 Type Safe: Full TypeScript-like safety with Dart
Installation
Add this package to your pubspec.yaml:
dependencies:
dio_api_services: ^1.2.0
Then run:
flutter pub get
Quick Start
Basic Setup
import 'package:dio_api_services/dio_api_services.dart';
// Initialize the service with optional automatic authentication
final apiService = DioApiService(
baseUrl: 'https://api.example.com',
connectTimeout: Duration(seconds: 30),
receiveTimeout: Duration(seconds: 30),
getToken: () async {
// Return your token here (e.g., from secure storage)
return 'your_bearer_token';
},
);
Making API Calls
// GET request
final response = await apiService.call(
'/users',
method: MethodRequest.GET,
);
// POST request with JSON data
final response = await apiService.call(
'/users',
method: MethodRequest.POST,
request: {
'name': 'John Doe',
'email': 'john@example.com',
},
);
// POST request with form data
final response = await apiService.call(
'/upload',
method: MethodRequest.POST,
request: {
'file': await MultipartFile.fromFile('/path/to/file.jpg'),
'description': 'Profile picture',
},
useFormData: true,
);
Core Features
1. HTTP Methods Support
The package supports all standard HTTP methods:
// GET Request
await apiService.call('/endpoint', method: MethodRequest.GET);
// POST Request
await apiService.call('/endpoint', method: MethodRequest.POST, request: data);
// PUT Request
await apiService.call('/endpoint', method: MethodRequest.PUT, request: data);
// DELETE Request
await apiService.call('/endpoint', method: MethodRequest.DELETE);
2. Automatic Retry Mechanism
Built-in smart retry with configurable delays:
final apiService = DioApiService(
baseUrl: 'https://api.example.com',
);
// The service automatically retries failed requests:
// - 1st retry: after 1 second
// - 2nd retry: after 2 seconds
// - 3rd retry: after 3 seconds
3. Connectivity Checking
Automatic network status verification before making requests:
// The service automatically checks connectivity
// Returns offline message if no internet connection
final response = await apiService.call('/endpoint');
if (response.statusCode == 00) {
print('Offline: ${response.data['message']}');
}
4. Advanced Logging
Comprehensive logging with customizable options:
final response = await apiService.call(
'/endpoint',
logRequestUrl: true, // Log request URL
logRequestHeader: true, // Log request headers
logRequestBody: true, // Log request body
logResponseBody: true, // Log response body
logResponseHeader: false, // Skip response headers
logResponseError: true, // Log errors
);
5. Custom Headers
Easy header management:
final response = await apiService.call(
'/protected-endpoint',
header: {
'Authorization': 'Bearer $token',
'Content-Type': 'application/json',
'X-Custom-Header': 'custom-value',
},
);
Advanced Usage
Error Handling
The package provides intelligent error handling:
try {
final response = await apiService.call('/endpoint');
if (response.statusCode == 200) {
// Success
final data = response.data;
} else {
// Handle API errors
final errorMessage = response.data['message'];
print('API Error: $errorMessage');
}
} catch (e) {
print('Network Error: $e');
}
Form Data and File Uploads
// File upload with form data
final response = await apiService.call(
'/upload',
method: MethodRequest.POST,
useFormData: true,
request: {
'file': await MultipartFile.fromFile(
filePath,
filename: 'image.jpg',
),
'userId': '123',
'category': 'profile',
},
);
Query Parameters
// GET request with query parameters
final response = await apiService.call(
'/users',
method: MethodRequest.GET,
request: {
'page': 1,
'limit': 10,
'search': 'john',
},
);
Configuration Options
Timeout Configuration
final apiService = DioApiService(
baseUrl: 'https://api.example.com',
connectTimeout: Duration(seconds: 30), // Connection timeout
receiveTimeout: Duration(seconds: 60), // Response timeout
);
Retry Configuration
The retry mechanism is pre-configured but can be customized by extending the service:
- Retries: 3 attempts
- Delays: 1s, 2s, 3s between retries
- Conditions: Network errors, timeouts, 5xx status codes
API Reference
DioApiService
Constructor
DioApiService({
required String baseUrl,
Duration connectTimeout = const Duration(seconds: 90),
Duration? receiveTimeout = const Duration(seconds: 50),
Future<String?> Function()? getToken,
})
Methods
call()
Future<Response> call(
String url, {
MethodRequest method = MethodRequest.POST,
dynamic request,
Map<String, String>? header,
bool useFormData = false,
bool logRequestUrl = true,
bool logRequestHeader = false,
bool logRequestBody = false,
bool logResponseBody = true,
bool logResponseHeader = false,
bool logResponseError = true,
})
Parameters:
url: The endpoint URL (relative to baseUrl)method: HTTP method (GET, POST, PUT, DELETE)request: Request data (JSON object or query parameters)header: Custom headers mapuseFormData: Convert request to FormDatalog*: Logging configuration options
Returns: Future<Response> - Dio Response object
MethodRequest Enum
enum MethodRequest { POST, GET, PUT, DELETE }
Best Practices
1. Service Initialization
Create a singleton service instance:
class ApiClient {
static final _instance = DioApiService(
baseUrl: 'https://api.example.com',
);
static DioApiService get instance => _instance;
}
// Usage
final response = await ApiClient.instance.call('/endpoint');
2. Error Handling
Always handle both network and API errors:
Future<List<User>> getUsers() async {
try {
final response = await apiService.call('/users', method: MethodRequest.GET);
if (response.statusCode == 200) {
return (response.data as List)
.map((json) => User.fromJson(json))
.toList();
} else {
throw ApiException(response.data['message']);
}
} catch (e) {
throw NetworkException('Failed to fetch users: $e');
}
}
3. Authentication
The package now supports automatic token injection through an internal AuthInterceptor. Simply provide a getToken callback during initialization:
final apiService = DioApiService(
baseUrl: 'https://api.example.com',
getToken: () async => await storage.getToken(),
);
// Every request will now automatically include:
// Authorization: Bearer <your_token>
Example App
Check out the example directory for a complete implementation showing:
- Basic API calls
- Error handling
- Loading states
- Real-world usage patterns
Contributing
We welcome contributions! Please see our Contributing Guide for details.
Development Setup
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Changelog
See CHANGELOG.md for a detailed list of changes.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Support
- 📧 Issues: GitHub Issues
- 💬 Discussions: GitHub Discussions
- 🌐 Homepage: agisrh.github.io
Made with ❤️ by agisrh