🚀 ApiClientPlus

Pub Version License: MIT Tests wakatime

ðŸ”Ĩ Enterprise-Grade HTTP Client with Blazing Fast Performance

Intelligent caching â€Ē Multi-API management â€Ē Zero memory leaks

Quick Start â€Ē Features â€Ē Docs â€Ē Examples


ðŸŽŊ Why ApiClientPlus?

⚡ Blazing Fast

~12ms overhead
225x faster with cache
0 memory leaks

ðŸŽĻ Developer Friendly

Clean API design
Minimal configuration
Type-safe responses

ðŸĒ Production Ready

Extensive testing
Battle-tested code
Enterprise features


âœĻ Features

ðŸŽŊ Core Capabilities

✓ Multi-API Configuration    // Manage multiple endpoints seamlessly
✓ Intelligent Caching         // 6 strategies with auto-expiration
✓ Token Authentication        // Auto-refresh & error handling
✓ Request Interceptors        // Transform requests/responses
✓ Error Fallback              // Graceful cache fallback
✓ Comprehensive Logging       // Debug with precision

🔄 Cache Strategies

Strategy Behavior Best For
ðŸŽŊ cacheFirst Cache → Network General purpose APIs
🌐 networkFirst Network → Cache Fresh data priority
ðŸ’ū cacheOnly Cache exclusive Offline-first apps
ðŸ”ī networkOnly No caching Real-time updates
⚡ staleWhileRevalidate Instant + refresh Performance critical
🔄 cacheThenNetwork Cache + background Progressive loading

ðŸ“Ķ Installation

Add to your pubspec.yaml:

dependencies:
  api_client_plus: ^1.0.0

Install:

flutter pub get

🚀 Quick Start

1ïļâƒĢ Initialize (One-Time Setup)

import 'package:api_client_plus/api_client_plus.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

   await ApiClientPlus().initialize(
    configs: [
      ApiConfig(
        name: 'dev',
        baseUrl: 'https://api.dev.example.com',
        requiresAuth: true,
      ),
      ApiConfig(
        name: 'api',
        baseUrl: 'https://api.example.com',
        requiresAuth: true,
      ),
      ApiConfig(
        name: 'auth',
        baseUrl: 'https://api.example.com',
        requiresAuth: false,
      ),
    ],
    defaultDomain: kReleaseMode ? 'prod' : 'dev',
    cacheConfig: CacheConfig(
      enableCache: true,
      defaultTtl: Duration(minutes: 10),
    ),
    logConfig: LogConfig(
      showLog: kReleaseMode,
      showCacheLog: false,
      messageLimit: 300,
      prettyJson: false,
      isColored: true,
      showCaller: false,
      logStyle: LogStyle.minimal,
      logLevel: "DEBUG",
    ),
    tokenGetter: () async {
      // final prefs = await SharedPreferences.getInstance();
      // return prefs.getString('access_token');
      return 'my_access_token';
    },
    onTokenInvalid: () async {
      // Redirect logic here
    },
    onRequest: (options) async {
      options.headers['User-Agent'] = 'MyApp/1.0.0';
    },
    onResponse: (response) async {
      debugPrint('✅ ${response.statusCode} ${response.requestOptions.path}');
    },
    onError: (error) async {
      debugPrint('❌ API Error: ${error.message}');
    },
  );

  runApp(MyApp());
}

2ïļâƒĢ Make API Calls

// Simple GET request with caching
final response = await ApiClientService.get(
  '/users',
  useCache: true,
  cacheStrategy: ApiClientCacheStrategy.cacheFirst,
);

// POST with authentication
final user = await ApiClientService.post(
  '/users',
  data: {'name': 'John Doe', 'email': '[email protected]'},
);

// PUT/PATCH updates
await ApiClientService.put('/users/123', data: updatedData);
await ApiClientService.patch('/users/123', data: partialData);

// DELETE
await ApiClientService.delete('/users/123');

3ïļâƒĢ Handle Responses

try {
  final response = await ApiClientService.get('/profile');

  if (response.statusCode == 200) {
    final user = response.data;
    print('Welcome ${user['name']}!');
  }
} on DioException catch (e) {
  if (e.response?.statusCode == 401) {
    // Token expired - auto-refresh triggered
  } else if (e.type == DioExceptionType.connectionError) {
    // Network error - cache fallback available
    final cached = await ApiClientService.get(
      '/profile',
      cacheStrategy: ApiClientCacheStrategy.cacheOnly,
    );
  }
}

ðŸŽĻ Advanced Usage

🔐 Multi-API Configuration

Manage different API environments effortlessly:

await ApiClientPlus().initialize(
  configs: [
    ApiConfig(
      name: 'auth',
      baseUrl: 'https://auth.company.com',
      requiresAuth: true,
      connectTimeout: Duration(seconds: 30),
    ),
    ApiConfig(
      name: 'public',
      baseUrl: 'https://api.company.com',
      requiresAuth: false,
      verboseLogging: false,
    ),
    ApiConfig(
      name: 'cdn',
      baseUrl: 'https://cdn.company.com',
      requiresAuth: false,
    ),
  ],
  defaultDomain: 'auth',
);

// Switch between APIs seamlessly
final profile = await ApiClientService.get('/me', domainName: 'auth');
final posts = await ApiClientService.get('/posts', domainName: 'public');
final image = await ApiClientService.get('/avatar.png', domainName: 'cdn');

⚡ Cache Optimization

// Stale-While-Revalidate: Instant response + background refresh
final data = await ApiClientService.get(
  '/dashboard',
  cacheStrategy: ApiClientCacheStrategy.staleWhileRevalidate,
  useCache: true,
  maxStale: Duration(hours: 1),
);

// Cache-Then-Network: Progressive enhancement
final products = await ApiClientService.get(
  '/products',
  cacheStrategy: ApiClientCacheStrategy.cacheThenNetwork,
  onCachedResponse: (cached) {
    // Show cached data immediately
    updateUI(cached.data);
  },
);

🔒 Authentication Flow

await ApiClientPlus().initialize(
  configs: [...],
  tokenGetter: () async {
    // Retrieve token from secure storage
    return await SecureStorage.read('auth_token');
  },
  onTokenInvalid: () async {
    // Handle expired tokens
    await SecureStorage.delete('auth_token');
    Navigator.pushReplacementNamed(context, '/login');
  },
);

ðŸŽŊ Custom Headers & Options

final response = await ApiClientService.get(
  '/data',
  headers: {
    'X-Custom-Header': 'value',
    'X-Request-ID': uuid.v4(),
  },
  query: {
    'page': 1,
    'limit': 20,
    'sort': 'desc',
  },
  timeout: Duration(seconds: 60),
);

📊 Performance Benchmarks

Real-World Results

╔═══════════════════════════════════════════════════════════╗
║  Operation              │  Time      │  Rating             ║
╠═══════════════════════════════════════════════════════════â•Ģ
║  API Call Overhead      │  ~12ms     │  ✅ Excellent       ║
║  Route Matching         │  ~600Ξs    │  🚀 Blazing Fast    ║
║  Cache Retrieval        │  ~2ms      │  ⚡ Instant         ║
║  Plugin Initialization  │  ~13ms     │  🏎ïļ Quick           ║
║  Memory Leaks           │  0 growth  │  ðŸ›Ąïļ Rock Solid      ║
╚═══════════════════════════════════════════════════════════╝

Cache Performance Impact

// 🌐 First Request (Network)
ðŸ“Ĩ Response Time: 450ms | Status: 200 | from_cache: false

// ⚡ Second Request (Cache)
ðŸ“Ĩ Response Time: 2ms | Status: 200 | from_cache: true

// 🎉 Result: 225x FASTER!

Load Testing

✓ 100 sequential calls:   1.1 seconds  (11ms avg)
✓ 50 domain switches:     549ms        (10.98ms avg)
✓ 1000 route matches:     627ms        (0.6ms avg)
✓ 10 client instances:    0ms          (instant)
✓ 20 configs setup:       1ms          (blazing)

🔧 Configuration Reference

ApiConfig

ApiConfig(
  name: 'myapi',                    // Unique identifier
  baseUrl: 'https://api.example.com',
  connectTimeout: Duration(seconds: 30),
  receiveTimeout: Duration(seconds: 30),
  sendTimeout: Duration(seconds: 30),
  requiresAuth: true,               // Requires token
  verboseLogging: false,            // Detailed logs
  maxRetries: 3,                    // Retry failed requests
  defaultHeaders: {                 // Custom headers
    'Accept': 'application/json',
    'X-App-Version': '1.0.0',
  },
  extra: {'priority': 'high'},      // Custom metadata
)

CacheConfig

CacheConfig(
  enableCache: true,
  defaultTtl: Duration(minutes: 15),
  priority: CachePriority.normal,
  hitCacheOnNetworkFailure: true,   // Fallback on error
  hitCacheOnErrorCodes: [500, 502, 503, 401, 403],
)

LogConfig

LogConfig(
  showLog: true,
  showCacheLog: true,
  logLevel: "DEBUG",                // TRACE, DEBUG, INFO, WARN, ERROR
  prettyJson: true,
  isColored: true,
  messageLimit: 300,
  showTime: true,
  showCaller: false,
  logStyle: LogStyle.minimal,       // minimal, standard, none
)

🐛 Debugging

Enable Comprehensive Logging

await ApiClientPlus().initialize(
  configs: [...],
  logConfig: LogConfig(
    showLog: true,
    showCacheLog: true,
    logLevel: "DEBUG",
    prettyJson: true,
    isColored: true,
  ),
);

Sample Log Output

INFO ðŸ’ū Cache Strategy: cache_first for /users
INFO ðŸ’ū ✅ CACHE HIT: /users (age: 2m 34s)
INFO ðŸ“Ĩ Response: 2ms | 200 | from_cache: true

INFO 🌐 Cache Strategy: network_first for /posts
INFO 🌐 Making network request...
INFO ðŸ“Ĩ Response: 156ms | 200 | from_cache: false
INFO ðŸ’ū ✅ Cached: /posts (ttl: 10m)

Screenshots

Performance Test Cache Syetem Test


ðŸĪ Contributing

We welcome contributions! Here's how:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing)
  3. Commit changes (git commit -m 'Add amazing feature')
  4. Push to branch (git push origin feature/amazing)
  5. Open a Pull Request

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.


🆘 Support & Resources

📖
Documentation
🐛
Report Bug
ðŸ’Ą
Request Feature
⭐
Star on GitHub

Built with âĪïļ for the Flutter Community

pub.dev â€Ē GitHub â€Ē Issues

If this package helped you, consider giving it a ⭐ on GitHub!

Libraries

api_client_plus