karna_network 0.1.0 copy "karna_network: ^0.1.0" to clipboard
karna_network: ^0.1.0 copied to clipboard

A stale-while-revalidate (SWR) caching layer for Dio: serves cached GET responses instantly, revalidates in the background, dedupes concurrent requests, and falls back to stale data on network failure.

example/main.dart

import 'package:dio/dio.dart';
import 'package:karna_network/karna_network.dart';

late final Dio dio;
late final SwrInterceptor swr;
late final OfflineMutationQueue offlineQueue;

/// Stub — wire this to your real auth/session storage.
class MyTokenProvider implements TokenProvider {
  String? _accessToken = 'initial-token';

  @override
  Future<String?> getAccessToken() async => _accessToken;

  @override
  Future<String?> refreshAccessToken() async {
    // call your refresh endpoint here; return the new token or null.
    _accessToken = 'refreshed-token';
    return _accessToken;
  }
}

void setup() {
  final circuitBreaker = CircuitBreaker(
    failureThreshold: 3,
    cooldown: const Duration(seconds: 30),
  );

  final auth = AuthInterceptor(
    dioProvider: () => dio,
    tokenProvider: MyTokenProvider(),
  );
  final retry = RetryInterceptor(
    dioProvider: () => dio,
    circuitBreaker: circuitBreaker,
    maxRetries: 2,
  );
  swr = SwrInterceptor(
    dioProvider: () => dio,
    store: MemoryCacheStore(maxEntries: 300),
    defaultOptions: const SwrOptions(
      freshDuration: Duration(seconds: 30),
      staleDuration: Duration(minutes: 5),
    ),
  );
  final errors = ErrorNormalizingInterceptor();

  dio = Dio(BaseOptions(baseUrl: 'https://api.example.com'))
    ..interceptors.addAll([
      auth, // 1. attach token, refresh on 401
      retry, // 2. retry/backoff + circuit breaker on real network attempts
      swr, // 3. serve/refresh cache
      errors, // 4. last: normalize whatever exception bubbles out
    ]);

  offlineQueue = OfflineMutationQueue(
    dio: dio,
    store: MemoryMutationQueueStore(),
    isOnline: () async => true, // replace with connectivity_plus or similar
  );

  swr.events.listen((event) {
    switch (event) {
      case SwrRevalidating():
        break; // show a subtle "refreshing" indicator for event.key
      case SwrRevalidated():
        break; // event.data is the fresh payload
      case SwrRevalidationFailed():
        break; // silent by design; log if you want visibility
    }
  });
}

Future<void> fetchProfile() async {
  try {
    final res = await dio.get<dynamic>('/me');
    print('fromCache=${res.extra['fromCache']} data=${res.data}');
  } on DioException catch (e) {
    final appError = e.error as AppError; // normalized regardless of upstream
    print('failed: ${appError.kind} ${appError.message}');
  }
}

Future<void> mutateThenInvalidate() async {
  try {
    await offlineQueue.send('POST', '/todos', data: {'title': 'write docs'});
  } on MutationQueuedException {
    print('offline — queued, will sync later');
  }
  final key = defaultCacheKeyBuilder(
    RequestOptions(baseUrl: dio.options.baseUrl, path: '/todos'),
  );
  await swr.invalidate(key);
}

/// Batching example: several widgets each ask for one user by id within
/// the same frame; only fires one request to a batch endpoint you already
/// have on the backend.
final BatchCollector<Map<String, dynamic>> userBatcher = BatchCollector(
  batchFetcher: (ids) async {
    final res = await dio
        .get<dynamic>('/users', queryParameters: {'ids': ids.join(',')});
    final list = (res.data as List).cast<Map<String, dynamic>>();
    return {for (final u in list) u['id'] as String: u};
  },
);

Future<Map<String, dynamic>> fetchUser(String id) => userBatcher.load(id);

Future<void> aggregatedDashboard() async {
  final aggregator = RequestAggregator(dio);
  final result = await aggregator.fetchAll({
    'profile': '/me',
    'notifications': '/notifications',
    'billing': '/billing/summary',
  });
  print(result['profile']?.data);
}
0
likes
150
points
84
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A stale-while-revalidate (SWR) caching layer for Dio: serves cached GET responses instantly, revalidates in the background, dedupes concurrent requests, and falls back to stale data on network failure.

Repository (GitHub)
View/report issues

Topics

#dio #cache #swr #networking #http

License

MIT (license)

Dependencies

dio, hive_ce

More

Packages that depend on karna_network