QuickApi
QuickApi is a powerful and easy-to-use Flutter package for seamless API integrations with advanced features like automatic retry, caching, interceptors, and network connectivity checks.
โจ Features
- ๐ Complete HTTP Methods - GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, and multipart uploads
- ๐ Smart Retry Mechanism - Configurable retries with exponential backoff support
- ๐พ Advanced Caching - Response caching with size limits and manual cache control
- ๐ Network Connectivity Checks - Automatic network availability validation
- ๐ง Powerful Interceptor System - Request/response/error interceptors with abort control
- ๐ Structured Logging - Level-based logging (INFO, ERROR, DEBUG, WARN)
- โก Fluent Builder Pattern - Easy configuration with method chaining
- ๐ก๏ธ Comprehensive Error Handling - Sealed error classes with endpoint context
- โฑ๏ธ Granular Timeout Control - Separate connect, read, and write timeouts
- ๐ฏ Query Parameters Support - Built-in query parameter handling
- ๐ซ Request Cancellation - CancelToken for canceling in-flight requests
- ๐ Upload Progress - Progress callbacks for file uploads
- ๐ฏ Customizable Headers - Default and per-request header management
๐ฆ Installation
Add the following dependency to your pubspec.yaml:
dependencies:
quickapi: ^2.0.0
Then run:
flutter pub get
๐ Quick Start
Basic Usage
import 'package:quickapi/quickapi.dart';
// Simple initialization
final api = QuickApi(
baseUrl: 'https://api.example.com',
logger: (level, message) => print('[$level] $message'),
);
// Make requests
final response = await api.get('/users');
final newUser = await api.post('/users', {
'name': 'John Doe',
'email': 'john@example.com'
});
Advanced Configuration with Builder Pattern
final api = QuickApi.builder()
.baseUrl('https://api.example.com')
.timeout(Duration(seconds: 15))
.retry(3, delay: Duration(seconds: 1), useExponentialBackoff: true)
.cache(Duration(minutes: 5), maxSize: 100)
.addInterceptor(LoggingInterceptor())
.logger((level, message) => print('[API $level] $message'))
.build();
๐ Usage Examples
1. Import Dependencies
import 'package:quickapi/quickapi.dart';
import 'package:http/http.dart' as http;
2. Initialize QuickApi
Simple Initialization
class _ApiTestPageState extends State<ApiTestPage> {
late QuickApi _api;
@override
void initState() {
super.initState();
_api = QuickApi(
baseUrl: 'https://jsonplaceholder.typicode.com',
logger: (message) => print('[QuickApi] $message'),
);
}
}
Advanced Configuration with Builder
_api = QuickApi.builder()
.baseUrl('https://jsonplaceholder.typicode.com')
.timeout(Duration(seconds: 15))
.retry(3, delay: Duration(seconds: 1))
.addInterceptor(LoggingInterceptor())
.logger((message) => print('[QuickApi] $message'))
.build();
3. Make API Calls
GET Request
void _testGet() async {
try {
// With query parameters
final result = await _api.get('/posts/1',
queryParameters: {'include': 'comments'}
);
print('GET Response: $result');
} catch (e) {
print('Error: $e');
}
}
POST Request
void _testPost() async {
final params = {
'title': 'New Post',
'body': 'This is a new post.',
'userId': 1,
};
try {
final result = await _api.post('/posts', params);
print('POST Response: $result');
} catch (e) {
print('Error: $e');
}
}
PUT Request
void _testPut() async {
try {
final result = await _api.put('/posts/1', {
'title': 'Updated Post',
'body': 'This is an updated post.',
'userId': 1,
});
print('PUT Response: $result');
} catch (e) {
print('Error: $e');
}
}
PATCH Request
void _testPatch() async {
try {
final result = await _api.patch('/posts/1', {
'title': 'Partially Updated Post',
});
print('PATCH Response: $result');
} catch (e) {
print('Error: $e');
}
}
DELETE Request
void _testDelete() async {
try {
final result = await _api.delete('/posts/1');
print('DELETE Response: $result');
} catch (e) {
print('Error: $e');
}
}
File Upload (Multipart POST)
void _testFileUpload() async {
try {
final file = await _pickFile();
if (file != null) {
final result = await _api.postMultipart('/upload', {
'description': 'Test File Upload'
}, [
http.MultipartFile.fromBytes('file', await file.readAsBytes(),
filename: 'file.jpg')
], onProgress: (sent, total) {
print('Upload progress: ${(sent / total * 100).toStringAsFixed(1)}%');
});
print('Upload Response: $result');
}
} catch (e) {
print('Error: $e');
}
}
๐ง Configuration Options
QuickApi Constructor Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
baseUrl |
String |
Required | Base URL for all API requests |
defaultHeaders |
Map<String, String>? |
null |
Default headers for all requests |
timeoutDuration |
Duration |
30 seconds |
Request timeout duration |
retryCount |
int |
3 |
Number of retry attempts |
retryDelay |
Duration |
2 seconds |
Delay between retry attempts |
cacheDuration |
Duration |
5 minutes |
Cache expiration duration |
interceptors |
List<QuickApiInterceptor> |
[] |
List of interceptors |
logger |
Function(String, String)? |
null |
Logging function (level, message) |
useExponentialBackoff |
bool |
true |
Use exponential backoff for retries |
maxBackoffDuration |
Duration |
60 seconds |
Maximum backoff duration |
maxCacheSize |
int? |
null |
Maximum number of cached responses |
connectTimeout |
Duration? |
null |
Connection timeout |
readTimeout |
Duration? |
null |
Read timeout |
writeTimeout |
Duration? |
null |
Write timeout |
httpClient |
http.Client? |
null |
Custom HTTP client |
Builder Pattern Methods
| Method | Description |
|---|---|
.baseUrl(String) |
Set the base URL |
.defaultHeaders(Map) |
Set default headers |
.timeout(Duration) |
Set timeout duration |
.retry(int, {Duration? delay}) |
Set retry count and delay |
.addInterceptor(Interceptor) |
Add an interceptor |
.logger(Function) |
Set logging function (level, message) |
.cache(Duration, {int? maxSize}) |
Configure cache duration and size |
.connectTimeout(Duration) |
Set connection timeout |
.readTimeout(Duration) |
Set read timeout |
.writeTimeout(Duration) |
Set write timeout |
.httpClient(http.Client) |
Set custom HTTP client |
๐ฏ Interceptors
Built-in Logging Interceptor
// Add logging to all requests
final api = QuickApi.builder()
.baseUrl('https://api.example.com')
.addInterceptor(LoggingInterceptor())
.build();
Custom Interceptor
class AuthInterceptor implements QuickApiInterceptor {
@override
Future<void> onRequest(RequestContext context) async {
// Add auth token to headers
context.data['headers'] = {'Authorization': 'Bearer $token'};
}
@override
Future<void> onResponse(ResponseContext context) async {
// Handle response (e.g., refresh token if 401)
if (context.data is Map && context.data['statusCode'] == 401) {
// Handle unauthorized
}
}
}
// Use custom interceptor
final api = QuickApi.builder()
.baseUrl('https://api.example.com')
.addInterceptor(AuthInterceptor())
.build();
๐จ Error Handling
QuickApi provides specific error types for different scenarios:
Error Types
TimeoutError- Request timeoutNetworkError- Network connectivity issuesAuthenticationError- 401 Unauthorized responsesValidationError- 422 Validation failuresRateLimitError- 429 Too Many RequestsClientError- 4xx client errorsServerError- 5xx server errorsUnknownError- Other status codes
Error Handling Example
try {
final response = await api.get('/users');
} on AuthenticationError catch (e) {
print('Auth failed: ${e.message}');
// Redirect to login
} on ValidationError catch (e) {
print('Validation failed: ${e.errors}');
// Show validation errors
} on NetworkError catch (e) {
print('Network issue: ${e.message}');
// Show offline message
} catch (e) {
print('Unexpected error: $e');
}
๐พ Caching
QuickApi automatically caches successful GET responses:
// Enable caching (default: true)
final response1 = await api.get('/users'); // Network request
final response2 = await api.get('/users'); // Cached response
// Disable caching for specific requests
final response3 = await api.get('/users', useCache: false);
// Clear all cache
api.clearCache();
// Check cache size
print('Cache size: ${api.cacheSize}');
๐ Retry Mechanism
Automatic retry for failed requests:
final api = QuickApi.builder()
.baseUrl('https://api.example.com')
.retry(3, delay: Duration(seconds: 1)) // 3 attempts, 1 second delay
.build();
// If a request fails, it will automatically retry up to 3 times
// With exponential backoff enabled by default
final response = await api.get('/users');
๐ Network Connectivity
QuickApi automatically checks network connectivity before making requests:
// No need to manually check - QuickApi handles this automatically
final response = await api.get('/users');
// If no internet, throws NetworkError immediately
// You can also cancel requests
final cancelToken = CancelToken();
api.get('/users', cancelToken: cancelToken);
// Later, cancel the request
cancelToken.cancel();
๐งช Testing
Run the test suite:
flutter test
The package includes comprehensive tests for all functionality including:
- Initialization and configuration
- Builder pattern
- Error handling
- Interceptor system
- Caching behavior
๐ Logging
Enable logging to monitor API requests:
final api = QuickApi(
baseUrl: 'https://api.example.com',
logger: (message) => print('[API] $message'),
);
// Or use the built-in logging interceptor
final api = QuickApi.builder()
.baseUrl('https://api.example.com')
.addInterceptor(LoggingInterceptor())
.build();
๐ค Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.