dio_network_toolkit 1.0.2 copy "dio_network_toolkit: ^1.0.2" to clipboard
dio_network_toolkit: ^1.0.2 copied to clipboard

Production-ready network layer for Flutter & Dart with auth refresh, smart retry, offline queue, response cache, deduplication, and upload progress using sealed Result types.

example/lib/main.dart

import 'package:dio_network_toolkit/dio_network_toolkit.dart';
import 'package:flutter/foundation.dart';

// ── 1. Define your models ─────────────────────────────────────────────

class User {
  final String id;
  final String name;
  final String email;

  User({required this.id, required this.name, required this.email});

  factory User.fromJson(dynamic json) => User(
        id: json['id'],
        name: json['name'],
        email: json['email'],
      );
}

class Post {
  final String id;
  final String title;

  Post({required this.id, required this.title});

  factory Post.fromJson(dynamic json) => Post(
        id: json['id'],
        title: json['title'],
      );
}

// ── 2. Create the toolkit (once, in your DI container) ────────────────

final api = NetworkToolkit(
  NetworkToolkitConfig(
    baseUrl: 'https://api.example.com/v1',

    // Auth: works with ANY storage (SharedPrefs, SecureStorage, Hive, etc.)
    auth: AuthConfig(
      tokenProvider: () async {
        // return await YourStorage.read('access_token');
        return 'your-access-token';
      },
      refreshToken: (dio) async {
        // final res = await dio.post('/auth/refresh', data: {...});
        // return res.data['accessToken'];
        return 'new-token';
      },
      onTokenExpired: () {
        // Navigate to login screen
        debugPrint('Token expired — redirect to login');
      },
    ),

    // Retry: 3 attempts with exponential backoff
    retry: const RetryConfig(
      maxAttempts: 3,
      retryableStatusCodes: {500, 502, 503, 504, 429},
    ),

    // Cache: network-first for GET requests
    cache: const CacheConfig(
      strategy: CacheStrategy.networkFirst,
      maxAge: Duration(minutes: 5),
    ),

    // Offline queue: auto-replay mutations when back online
    offlineQueue: OfflineQueueConfig(
      enabled: true,
      onReplayComplete: (success, fail) {
        debugPrint('Replayed: $success ok, $fail failed');
      },
    ),

    enableLogging: kDebugMode,

    // Global error handler — show toast, log to analytics, etc.
    onError: (error) {
      debugPrint('Error ${error.type}: ${error.userMessage}');
    },
  ),
);

// ── 3. Repository layer (Clean Architecture) ──────────────────────────

class UserRepository {
  final NetworkToolkit _api;
  UserRepository(this._api);

  Future<Result<User>> getProfile() =>
      _api.get('/me', fromJson: User.fromJson);

  Future<Result<User>> updateProfile(Map<String, dynamic> data) =>
      _api.put('/me', data: data, fromJson: User.fromJson);
}

class PostRepository {
  final NetworkToolkit _api;
  PostRepository(this._api);

  Future<Result<List<Post>>> getPosts({int page = 1}) =>
      _api.getList('/posts',
          fromJson: Post.fromJson,
          dataKey: 'data',
          queryParameters: {'page': page});

  // Public endpoint (no auth header)
  Future<Result<List<Post>>> getFeatured() =>
      _api.getList('/posts/featured',
          fromJson: Post.fromJson, dataKey: 'data', isPublic: true);
}

// ── 4. Main ───────────────────────────────────────────────────────────

void main() async {
  // Simple usage
  final result = await api.get<User>('/me', fromJson: User.fromJson);

  result.when(
    success: (user, statusCode, raw) {
      debugPrint('Hello, ${user.name}!');
    },
    failure: (error) {
      debugPrint('Error: ${error.userMessage}');
      if (error.isRetryable) debugPrint('Show retry button');
    },
  );

  // List with pagination
  final posts = await api.getList<Post>(
    '/posts',
    fromJson: Post.fromJson,
    dataKey: 'data',
    queryParameters: {'page': 1, 'limit': 20},
  );

  posts.when(
    success: (data, _, __) => debugPrint('Got ${data.length} posts'),
    failure: (error) => debugPrint('Failed: ${error.userMessage}'),
  );

  // Functional chaining
  final userName = (await api.get<User>('/me', fromJson: User.fromJson))
      .mapSuccess((user) => user.name)
      .dataOr('Anonymous');

  debugPrint('User: $userName');
}
4
likes
0
points
200
downloads

Publisher

unverified uploader

Weekly Downloads

Production-ready network layer for Flutter & Dart with auth refresh, smart retry, offline queue, response cache, deduplication, and upload progress using sealed Result types.

Repository (GitHub)
View/report issues

Topics

#dio #networking #http-client #clean-architecture #api

License

unknown (license)

Dependencies

connectivity_plus, dio, flutter

More

Packages that depend on dio_network_toolkit