dart_acdc 0.3.0
dart_acdc: ^0.3.0 copied to clipboard
Zero-config HTTP client for Flutter with built-in auth, caching, logging, and error handling. Integrates with OpenAPI-generated code.
Dart ACDC #
Authentication, Caching, Debugging, Client - A zero-config, opinionated HTTP client for Flutter mobile apps.
Overview #
Dart-ACDC provides a production-ready HTTP client built on top of Dio with:
- Authentication: Automatic token injection, refresh, and revocation (OAuth 2.1)
- Caching: Intelligent HTTP caching with user isolation and offline support
- Logging: Environment-aware logging with sensitive data redaction
- Error Handling: Type-safe exceptions with developer-friendly messages
Designed to be the "missing link" between OpenAPI Generator Dart clients and production-ready Flutter apps.
Features #
- ✅ Zero-config default: Works out of the box with sensible defaults
- ✅ Builder pattern: Progressive disclosure for advanced configuration
- ✅ Type-safe: Full Dart type safety and null safety
- ✅ Testable: Easy mocking and testing
- ✅ Production-ready: Battle-tested patterns for mobile apps
- ✅ Efficient: Automatic request deduplication to save bandwidth
Installation #
Add to your pubspec.yaml:
dependencies:
dart_acdc: ^0.1.0
Then run:
flutter pub get
Quick Start #
Basic Usage #
import 'package:dart_acdc/dart_acdc.dart';
// Zero-config client
final dio = AcdcClientBuilder().build();
// Make requests
final response = await dio.get('https://api.example.com/data');
With Authentication (Zero-Config) #
Dart-ACDC comes with a secure, encrypted token store (SecureTokenProvider) out of the box. You don't need to write any storage code.
import 'package:dart_acdc/dart_acdc.dart';
final dio = AcdcClientBuilder()
.withBaseUrl('https://api.example.com')
// Automatically uses FlutterSecureStorage
.withTokenRefreshEndpoint(
url: 'https://api.example.com/oauth/token',
clientId: 'your-client-id',
)
.withInitialTokens(
accessToken: '...',
refreshToken: '...',
)
.build();
// All subsequent requests will have the token injected and refreshed automatically
final response = await dio.get('/protected/endpoint');
// Logout: clears tokens from secure storage and revokes them if endpoint provided
await dio.auth.logout();
With OpenAPI Generator #
- Generate your client using
openapi-generator-cli(dart-dio generator). - Create your configured Dio instance with Dart-ACDC.
- Pass it to your generated API client.
import 'package:your_openapi_client/api.dart';
import 'package:dart_acdc/dart_acdc.dart';
final dio = AcdcClientBuilder()
.withBaseUrl('https://api.example.com')
.withTokenRefreshEndpoint(...)
.build();
// Inject into OpenAPI-generated client
// The generated DefaultApi (and others) accept a Dio instance in the constructor.
final api = DefaultApi(dio);
// Now all API calls have auth, caching, logging, and error handling!
final users = await api.getUsers();
Advanced Usage #
Custom Token Storage #
If you need to store tokens somewhere other than flutter_secure_storage (e.g., Hive or SharedPreferences), implement TokenProvider:
class MyTokenProvider implements TokenProvider {
@override
Future<String?> getAccessToken() async { ... }
// ... implement other methods
}
final dio = AcdcClientBuilder()
.withTokenProvider(MyTokenProvider())
.build();
Configuration #
Logging & Redaction #
By default, logs are pretty-printed to the console. You can redact sensitive keys to prevent leaking secrets.
final dio = AcdcClientBuilder()
.withLogLevel(LogLevel.debug)
.withSensitiveFields(['password', 'accessToken', 'secret']) // Redacts these keys in JSON
.withLogger((message, level, metadata) {
// Optional: pipe logs to Crashlytics or Datadog
Crashlytics.instance.log(message);
})
.build();
Caching #
final dio = AcdcClientBuilder()
.withCache(CacheConfig(
ttl: Duration(hours: 1),
maxSize: 10 * 1024 * 1024, // 10 MB
// Encrypted on disk by default
inMemory: true,
))
.build();
// Manually clear cache if needed
await dio.auth.clearCache();
Timeouts #
final dio = AcdcClientBuilder()
.withTimeout(Duration(seconds: 30))
.build();
Request Deduplication #
By default, Dart-ACDC deduplicates simultaneous identical requests (same method, URL, headers, and data) to prevent redundant network calls.
final dio = AcdcClientBuilder()
// Disable deduplication if needed
.withDeduplication(enabled: false)
.build();
Error Handling #
Dart-ACDC provides type-safe exception handling:
try {
await dio.get('/endpoint');
} on AcdcAuthException catch (e) {
// Handle authentication errors (401, 403)
print('Auth error: ${e.message}');
} on AcdcNetworkException catch (e) {
// Handle network errors (timeout, no connection)
print('Network error: ${e.message}');
} on AcdcServerException catch (e) {
// Handle server errors (5xx)
print('Server error: ${e.statusCode}');
} on AcdcClientException catch (e) {
// Handle client errors (4xx except 401)
print('Client error: ${e.statusCode}');
}
Requirements #
- Dart SDK:
>=3.0.0 <4.0.0 - Flutter:
>=3.10.0
Development #
Running Tests #
dart test
Code Coverage #
Run tests with coverage reporting:
./scripts/coverage.sh
Current coverage: 91.76% ✅ (exceeds 80% target)
Security Best Practices #
Dart-ACDC is built with security as a priority:
- Secure Storage: All tokens are stored using specific OS-level encryption (Keychain on iOS, EncryptedSharedPreferences on Android) by default.
- Memory Protection: Authentication headers are stripped from logs by default.
- Cache Encryption: Response data cached on disk is always AES-256 encrypted.
- Least Privilege: The library only requests the permissions it needs.
Documentation #
License #
MIT License - see LICENSE file for details.
Contributing #
Contributions are welcome! Please read our contributing guidelines before submitting PRs.