dio_flow 2.0.0 copy "dio_flow: ^2.0.0" to clipboard
dio_flow: ^2.0.0 copied to clipboard

Flexible HTTP client for Flutter, built on Dio with mock support, GraphQL, file handling, caching, and token management.

๐ŸŒŠ Dio Flow #

pub package License: MIT Flutter Platform

A powerful, production-ready Flutter package that supercharges Dio HTTP client

Built for modern Flutter applications that demand robust, scalable API integration

๐Ÿ“– Documentation โ€ข ๐Ÿš€ Quick Start โ€ข ๐Ÿ’ก Examples โ€ข ๐Ÿ› Issues


๐ŸŽฏ Why Dio Flow? #

Dio Flow transforms your API integration experience by providing enterprise-grade features out of the box:

  • ๐Ÿ”ฅ Zero Configuration: Get started in minutes with sensible defaults
  • ๐Ÿ›ก๏ธ Production Ready: Battle-tested with comprehensive error handling
  • ๐Ÿš€ Performance First: Built-in caching, retry logic, and request optimization
  • ๐ŸŒ Universal: Works seamlessly across all Flutter platforms
  • ๐Ÿงช Developer Friendly: Extensive mocking support for testing
  • ๐Ÿ“Š Observable: Built-in metrics and detailed logging

๐Ÿ“‹ Table of Contents #

โœจ Features #

๐Ÿš€ Core ๐Ÿ”’ Security ๐Ÿ› ๏ธ Developer Experience
Modern HTTP Client Token Management Type-Safe Responses
Smart Response Handling Auto Token Refresh Comprehensive Testing
Intelligent Caching Request Authentication Built-in Mocking
Auto-Retry Logic Secure Token Storage Detailed Logging
๐ŸŒ Platform ๐Ÿ“Š Performance ๐Ÿ”ง Advanced
Universal Support Request Metrics GraphQL Support
Web Compatible Rate Limiting File Operations
Cross-Platform Network Awareness Pagination Utils
WASM Ready Connection Pooling JSON Utilities

๐ŸŽฏ Key Capabilities #

  • ๐Ÿš€ Modern HTTP Client: Enhanced Dio with production-grade features
  • ๐Ÿ”„ Smart Response Handling: Automatic conversion to strongly-typed models
  • ๐Ÿ’พ Intelligent Caching: Configurable TTL with automatic invalidation
  • ๐Ÿ”‘ Token Management: Robust authentication with automatic refresh
  • ๐Ÿ” Auto-Retry: Configurable retry logic with exponential backoff
  • โšก Rate Limiting: Built-in throttling to prevent API abuse
  • ๐Ÿ“ถ Network Awareness: Automatic connectivity change handling
  • ๐Ÿ“Š Request Metrics: Built-in performance tracking and analytics
  • ๐Ÿ” Detailed Logging: Complete request/response logging with cURL commands
  • ๐Ÿ“„ Pagination Support: Utilities for handling paginated API responses
  • ๐Ÿ›ก๏ธ Type Safety: Strong typing throughout the entire library
  • ๐ŸŽฏ Error Handling: Comprehensive error handling with typed responses
  • ๐Ÿงช Mock Support: Built-in mocking system for testing without real HTTP calls
  • ๐Ÿ”— GraphQL Support: Native GraphQL queries, mutations, and subscriptions
  • ๐Ÿ“ File Operations: Easy file upload/download with progress tracking
  • ๐Ÿ”ง Extensible Architecture: Plugin-based design for custom functionality

๐ŸŽฏ Platform Support #

๐ŸŒ Universal Flutter Support - Write Once, Run Everywhere #

Platform Support File Operations Network Checking WASM Compatible
๐Ÿ“ฑ iOS โœ… Full โœ… Complete โœ… Native โœ… Ready
๐Ÿค– Android โœ… Full โœ… Complete โœ… Native โœ… Ready
๐ŸŒ Web โœ… Full ๐Ÿ”„ Bytes Only* โœ… HTTP-based โœ… Compatible
๐ŸชŸ Windows โœ… Full โœ… Complete โœ… Native โœ… Ready
๐ŸŽ macOS โœ… Full โœ… Complete โœ… Native โœ… Ready
๐Ÿง Linux โœ… Full โœ… Complete โœ… Native โœ… Ready

๐Ÿ’ก Web Platform Note: File operations use Uint8List instead of File objects due to browser security restrictions. This ensures maximum compatibility while maintaining functionality.

๐Ÿ“ฆ Installation #

Get started in seconds with a single dependency #

๐Ÿ“‹ Add Dependency #

dependencies:
  dio_flow: ^2.0.0

๐Ÿ”„ Install #

flutter pub get

๐Ÿ“ฑ Import #

import 'package:dio_flow/dio_flow.dart';

๐Ÿ“ฆ Development Dependencies (Optional)

For enhanced development experience:

dev_dependencies:
  dio_flow: ^2.0.0
  # For testing with mocks
  mockito: ^5.4.0
  # For integration testing
  integration_test:
    sdk: flutter

๐Ÿš€ Getting Started #

โšก From zero to API calls in under 2 minutes #

๐ŸŽฏ Quick Setup #

import 'package:dio_flow/dio_flow.dart';

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

  // ๐Ÿ”ง Configure Dio Flow
  DioFlowConfig.initialize(
    baseUrl: 'https://api.example.com',
    connectTimeout: const Duration(seconds: 30),
    receiveTimeout: const Duration(seconds: 30),
    sendTimeout: const Duration(seconds: 30),
  );

  // ๐Ÿš€ Initialize the client
  await ApiClient.initialize();

  // ๐Ÿ”‘ Initialize token management
  await TokenManager.initialize();

  runApp(MyApp());
}

๐ŸŽฏ Your First API Call #

// ๐Ÿ“ก Make your first request
final response = await DioRequestHandler.get('users');

if (response is SuccessResponseModel) {
  print('โœ… Success: ${response.data}');
} else {
  print('โŒ Error: ${response.error?.message}');
}

๐ŸŽฏ Core Components #

DioRequestHandler #

The main class for making HTTP requests:

// GET request
final response = await DioRequestHandler.get(
  'users',
  parameters: {'role': 'admin'},
  requestOptions: RequestOptionsModel(
    hasBearerToken: true,
    cacheOptions: CacheOptions(
      shouldCache: true,
      cacheDuration: const Duration(minutes: 5),
    ),
    retryOptions: RetryOptions(
      maxAttempts: 3,
      retryInterval: const Duration(seconds: 1),
    ),
  ),
);

// POST request with typed response
final loginResponse = await DioRequestHandler.post<LoginResponse>(
  'auth/login',
  data: {
    'email': '[email protected]',
    'password': '********',
  },
  requestOptions: RequestOptionsModel(
    hasBearerToken: false,
  ),
);

Response Models #

All responses are wrapped in typed models:

if (response is SuccessResponseModel) {
  final data = response.data;
  // Handle success
} else {
  final error = response.error;
  switch (error.errorType) {
    case ErrorType.network:
      // Handle network error
      break;
    case ErrorType.validation:
      // Handle validation error
      break;
    case ErrorType.unauthorized:
      // Handle auth error
      break;
    // ... handle other error types
  }
}

Interceptors #

The package includes several built-in interceptors that are automatically configured:

  1. MetricsInterceptor: Tracks request performance and timing
  2. CacheInterceptor: Manages response caching with SharedPreferences
  3. RateLimitInterceptor: Prevents API throttling (30 requests per minute by default)

These interceptors are automatically added to the Dio instance when ApiClient.initialize() is called. No additional configuration is required.

๐Ÿ”‘ Authentication #

๐Ÿ›ก๏ธ Enterprise-grade authentication with automatic token management #

Dio Flow provides a comprehensive authentication system with persistent storage, automatic token refresh, and seamless integration:

// Initialize token manager (call this in your main.dart)
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await TokenManager.initialize();

  // Register refresh logic (consumer-side). Optional โ€” if you don't set it,
  // automatic refresh will be disabled and TokenManager will return null on expired token.
  TokenManager.setRefreshHandler((refreshToken) async {
    final refreshResp = await DioRefreshTokenRequestHandle.post(
      ApiEndpointsKey.refreshToken,
      data: {'refreshToken': refreshToken},
    );

    if (refreshResp is! SuccessResponseModel) {
      // go to login page
    }

    final data = refreshResp.data!;

    return RefreshTokenResponse(
      accessToken: data['accessToken'] as String,
      refreshToken: data['refreshToken'] as String?,
      expiry: DateTime.now().add(Duration(days: 29)),
      );
  });

  runApp(MyApp());
}

// Setting tokens with persistence
await TokenManager.setTokens(
  accessToken: 'your_access_token',
  refreshToken: 'your_refresh_token',
  expiry: DateTime.now().add(Duration(hours: 1)),
);

// Check presence/validity (auto-refresh performed if expired and handler is set)
final hasToken = await TokenManager.hasAccessToken(); // returns true/false

// Getting access token (will automatically refresh if expired and a handler is configured)
final token = await TokenManager.getAccessToken(); // can be null if no handler and expired

// Clearing tokens
await TokenManager.clearTokens();

Key features:

  • Persistent token storage using SharedPreferences (tokens survive app restarts).

  • RefreshTokenHandler typedef โ€” consumer provides a small callback that receives the refresh token and returns a RefreshTokenResponse (access, refresh, expiry). This keeps the package network-agnostic.

  • TokenManager.setRefreshHandler(...) โ€” register refresh logic at startup or runtime (optional).

  • Automatic refresh behavior โ€” hasAccessToken() and getAccessToken() will automatically attempt to refresh when the access token is expired only if a refresh handler has been set. If no handler is provided, expired tokens are treated as absent (methods return false/null).

-Single-flight refresh protection โ€” internal _refreshCompleter ensures only one refresh request runs at a time; concurrent callers wait for that single result.

  • Tokens returned by the refresh handler are persisted via setTokens() (keeps state consistent across restarts).

  • All token operations are asynchronous for non-blocking startup and safer IO.

  • getAccessToken() behavior is unified: it either returns a valid token, triggers refresh (if handler exists), or returns null (if expired and no handler).

Protected Requests #

// Make authenticated request
final response = await DioRequestHandler.get(
  'user/profile',
  requestOptions: RequestOptionsModel(
    hasBearerToken: true, // This will automatically include the token
  ),
);

// Handle token expiration
if (response.error?.errorType == ErrorType.unauthorized) {
  // Token expired, handle refresh or logout
}

๐ŸŒ Endpoint Configuration #

Basic Endpoints #

// Register endpoints
EndpointProvider.instance.register('login', '/auth/login');
EndpointProvider.instance.register('users', '/api/users');

// Use registered endpoints
final response = await DioRequestHandler.post(
  'login',
  data: {'email': email, 'password': password},
);

Dynamic Endpoints #

// Register endpoint with parameters
EndpointProvider.instance.register('user_details', '/api/users/{id}');

// Use with path parameters
final response = await DioRequestHandler.get(
  'user_details',
  pathParameters: {'id': '123'},
);

๐Ÿ”„ Advanced Features #

Caching #

// Enable caching for a request
final response = await DioRequestHandler.get(
  'users',
  requestOptions: RequestOptionsModel(
    cacheOptions: CacheOptions(
      shouldCache: true,
      cacheDuration: const Duration(minutes: 5),
    ),
  ),
);

// Use predefined cache options
final shortCacheResponse = await DioRequestHandler.get(
  'frequent-data',
  requestOptions: RequestOptionsModel(
    cacheOptions: CacheOptions.shortApiCache, // 1 minute cache
  ),
);

final longCacheResponse = await DioRequestHandler.get(
  'static-data',
  requestOptions: RequestOptionsModel(
    cacheOptions: CacheOptions.longApiCache, // 1 hour cache
  ),
);

// Clear cache
await ApiClient.clearCache();

Pagination #

// Using pagination utilities
final paginatedResponse = await DioRequestHandler.get(
  'posts',
  parameters: {
    'page': 1,
    'per_page': 20,
  },
);

final pagination = PaginationHelper.fromResponse(paginatedResponse);
final hasMore = pagination.hasNextPage;
final totalPages = pagination.totalPages;

JSON Utilities #

// Safe JSON parsing
final jsonData = JsonUtils.tryParseJson(rawJson);

// Access nested values safely
final nestedValue = JsonUtils.getNestedValue(
  jsonData,
  'user.profile.name',
  'Default Name',
);

Request Queueing #

// Queue multiple requests
final responses = await Future.wait([
  DioRequestHandler.get('users'),
  DioRequestHandler.get('posts'),
  DioRequestHandler.get('comments'),
]);

// Rate limiting is handled automatically by RateLimitInterceptor
// Configure in ApiClient initialization (30 requests per minute by default)
final rateLimitedResponse = await DioRequestHandler.get(
  'high-frequency-endpoint',
  requestOptions: RequestOptionsModel(hasBearerToken: true),
);

Retry Configuration #

// Use predefined retry options for slow networks
final response = await DioRequestHandler.get(
  'unreliable-endpoint',
  requestOptions: RequestOptionsModel(
    retryOptions: RetryOptions.slowNetwork, // 5 attempts, 2 second intervals
  ),
);

// Custom retry configuration
final customRetryResponse = await DioRequestHandler.get(
  'custom-endpoint',
  requestOptions: RequestOptionsModel(
    retryOptions: RetryOptions(
      maxAttempts: 5,
      retryInterval: const Duration(seconds: 2),
      retryStatusCodes: [408, 429, 500, 502, 503, 504],
    ),
  ),
);

Cancell Request #

// Use canceel token for Cancell Request every time
final CancelToken testCancellToken = CancelToken();

final response = await DioRequestHandler.get(
  'test-endpoint',
  ccancelToken: testCancelToken,
);

// For use :
testCancelToken?.cancel('test_request_cancelled');

Custom Response Types #

class PaginatedResponse<T> {
  final List<T> items;
  final int total;
  final int page;

  PaginatedResponse.fromJson(
    Map<String, dynamic> json,
    T Function(Map<String, dynamic>) converter,
  )   : items = (json['data'] as List)
            .map((item) => converter(item))
            .toList(),
        total = json['total'] ?? 0,
        page = json['page'] ?? 1;
}

// Use with typed response
final response = await DioRequestHandler.get<PaginatedResponse<User>>(
  'users',
  converter: (json) => PaginatedResponse.fromJson(
    json,
    (item) => User.fromJson(item),
  ),
);

๐Ÿ› ๏ธ Best Practices #

๐Ÿ’ก Production-tested patterns for robust API integration #

๐Ÿš€ Essential Patterns #

1. Initialize Early

void main() async {
  await ApiClient.initialize();
  // ... rest of your app initialization
}

2. Handle Errors Consistently

try {
  final response = await DioRequestHandler.get('endpoint');
  if (response is SuccessResponseModel) {
    // Handle success
  } else {
    // Use the typed error handling
    handleError(response.error);
  }
} catch (e) {
  // Handle unexpected errors
}

3. Use Type-Safe Responses

class UserResponse {
  final String id;
  final String name;

  UserResponse.fromJson(Map<String, dynamic> json)
      : id = json['id'],
        name = json['name'];
}

final response = await DioRequestHandler.get<UserResponse>(
  'users/me',
  converter: (json) => UserResponse.fromJson(json),
);

Error Handling Patterns #

// Create a reusable error handler
Future<T> handleApiResponse<T>(ResponseModel response) async {
  if (response is SuccessResponseModel) {
    return response.data as T;
  }

  switch (response.error?.errorType) {
    case ErrorType.network:
      throw NetworkException(response.error!.message);
    case ErrorType.unauthorized:
      await handleUnauthorized();
      throw AuthException(response.error!.message);
    case ErrorType.validation:
      throw ValidationException(response.error!.message);
    default:
      throw ApiException(response.error?.message ?? 'Unknown error');
  }
}

// Use in your code
try {
  final users = await handleApiResponse<List<User>>(
    await DioRequestHandler.get('users'),
  );
  // Use users data
} on NetworkException catch (e) {
  // Handle network error
} on AuthException catch (e) {
  // Handle auth error
} on ValidationException catch (e) {
  // Handle validation error
} on ApiException catch (e) {
  // Handle other API errors
}

๐Ÿ—๏ธ Repository Pattern #

class UserRepository {
  Future<User> getCurrentUser() async {
    final response = await DioRequestHandler.get<User>(
      'users/me',
      requestOptions: RequestOptionsModel(
        hasBearerToken: true,
        shouldCache: true,
        cacheMaxAge: const Duration(minutes: 5),
      ),
      converter: (json) => User.fromJson(json),
    );

    return handleApiResponse<User>(response);
  }

  Future<void> updateProfile(UserUpdateRequest request) async {
    final response = await DioRequestHandler.put(
      'users/me',
      data: request.toJson(),
      requestOptions: RequestOptionsModel(hasBearerToken: true),
    );

    await handleApiResponse(response);
  }
}

โšก Performance Tips #

๐Ÿš€ Optimization strategies for production apps

// ๐Ÿ’พ Use caching strategically
final response = await DioRequestHandler.get(
  'static-data',
  requestOptions: RequestOptionsModel(
    cacheOptions: CacheOptions(
      shouldCache: true,
      cacheDuration: const Duration(hours: 1), // Cache static data longer
    ),
  ),
);

// ๐Ÿ”„ Batch requests when possible
final futures = [
  DioRequestHandler.get('users'),
  DioRequestHandler.get('posts'),
  DioRequestHandler.get('comments'),
];
final responses = await Future.wait(futures);

// โšก Use pagination for large datasets
final paginatedResponse = await PaginationUtils.fetchAllPages(
  'large-dataset',
  parameters: {'per_page': 50}, // Optimal page size
  maxPages: 10, // Limit to prevent memory issues
);

// ๐ŸŽฏ Optimize file uploads
final uploadResponse = await FileHandler.uploadBytes(
  'upload',
  compressedBytes, // Compress before upload
  'file.jpg',
  onProgress: (sent, total) {
    // Update UI efficiently
    if (sent % 1024 == 0) { // Update every KB
      updateProgressUI(sent / total);
    }
  },
);

๐Ÿงช Mock Support #

๐ŸŽญ Powerful mocking system for comprehensive testing #

Dio Flow includes a sophisticated mocking system that makes testing your API integrations effortless:

void main() {
  // Enable mock mode
  MockDioFlow.enableMockMode();

  // Register mock responses
  MockDioFlow.mockResponse(
    'users',
    MockResponse.success([
      {'id': 1, 'name': 'John Doe'},
      {'id': 2, 'name': 'Jane Smith'},
    ]),
  );

  // Register response queue for testing pagination
  MockDioFlow.mockResponseQueue('posts', [
    MockResponse.success({'page': 1, 'data': [...]}),
    MockResponse.success({'page': 2, 'data': [...]}),
  ]);

  // Your tests will now use mocked responses
  final response = await DioRequestHandler.get('users');

  // Disable mock mode
  MockDioFlow.disableMockMode();
}

๐Ÿ”— GraphQL Support #

โšก Native GraphQL integration with powerful query building #

Dio Flow provides first-class GraphQL support with an intuitive query builder and comprehensive operation handling:

// Simple query
final response = await GraphQLHandler.query('''
  query GetUser($id: ID!) {
    user(id: $id) {
      id
      name
      email
    }
  }
''', variables: {'id': '123'});

// Using query builder
final query = GraphQLQueryBuilder.query()
    .operationName('GetUsers')
    .variables({'first': 'Int'})
    .body('users(first: $first) { id name }')
    .build();

// Mutations
final mutationResponse = await GraphQLHandler.mutation('''
  mutation CreateUser($input: CreateUserInput!) {
    createUser(input: $input) {
      id
      name
    }
  }
''', variables: {'input': {'name': 'John', 'email': '[email protected]'}});

// Batch operations
final operations = [
  GraphQLOperation(query: 'query { users { id } }'),
  GraphQLOperation(query: 'query { posts { id } }'),
];
final batchResponse = await GraphQLHandler.batch(operations);

๐Ÿ“ File Operations #

๐Ÿ“ค๐Ÿ“ฅ Seamless file handling across all platforms with progress tracking #

Dio Flow provides comprehensive file operations that work consistently across all Flutter platforms, with intelligent platform-specific optimizations:

Mobile/Desktop Platforms (iOS, Android, Windows, macOS, Linux) #

// File upload from File object (Mobile/Desktop only)
final file = File('/path/to/file.jpg');
final uploadResponse = await FileHandler.uploadFile(
  'upload',
  file,
  fieldName: 'avatar',
  additionalData: {'userId': '123'},
  onProgress: (sent, total) {
    print('Upload: ${(sent/total*100).toStringAsFixed(1)}%');
  },
);

// File download to disk (Mobile/Desktop only)
final downloadResponse = await FileHandler.downloadFile(
  'files/123/download',
  '/local/path/file.pdf',
  onProgress: (received, total) {
    print('Download: ${(received/total*100).toStringAsFixed(1)}%');
  },
);

Web Platform #

// Upload from bytes (web-compatible)
final bytesUploadResponse = await FileHandler.uploadBytes(
  'upload',
  fileBytes, // Uint8List
  'filename.jpg',
  fieldName: 'avatar',
  additionalData: {'userId': '123'},
);

// Download as bytes (web-compatible)
final bytesResponse = await FileHandler.downloadBytes('files/123');
if (bytesResponse is SuccessResponseModel) {
  final bytes = bytesResponse.data['bytes'] as Uint8List;
  // Use bytes for web download (e.g., trigger browser download)
}

Cross-Platform File Operations #

// Multiple file upload (use bytes for web compatibility)
final files = {
  'document': documentBytes, // Uint8List for web
  'image': imageBytes,       // Uint8List for web
};
final multiUploadResponse = await FileHandler.uploadMultipleFiles(
  'upload-multiple',
  files,
);

// Upload from bytes (works on all platforms)
final bytesUploadResponse = await FileHandler.uploadBytes(
  'upload',
  fileBytes,
  'filename.jpg',
);

Note: On web platform, direct file system access is restricted by browser security. Use FileHandler.uploadBytes() and FileHandler.downloadBytes() for web-compatible file operations.

๐Ÿ” Troubleshooting #

๐Ÿ› ๏ธ Quick solutions to common issues #

๐Ÿšจ Common Issues & Solutions #

  1. Authentication Issues:

    • Ensure hasBearerToken is set correctly in RequestOptionsModel
    • Check if tokens are properly managed in TokenManager
  2. Caching Problems:

    • Verify shouldCache is enabled in request options
    • Check cache duration settings
    • Try clearing cache with ApiClient.clearCache()
  3. Network Errors:

    • Check connectivity status
    • Verify retry options are configured
    • Examine cURL logs for request details
  4. Mock Issues:

    • Ensure MockDioFlow.enableMockMode() is called before requests
    • Verify mock responses are registered for the correct endpoints
    • Check that endpoint paths match exactly
  5. GraphQL Errors:

    • Validate GraphQL syntax in queries
    • Check that variables match the schema
    • Ensure the GraphQL endpoint is correctly configured
  6. File Upload Issues:

    • Verify file permissions and paths
    • Check server file size limits
    • Ensure correct Content-Type headers for multipart uploads

๐Ÿ” Debug Mode #

// Enable detailed logging
DioFlowConfig.initialize(
  baseUrl: 'https://api.example.com',
  // Debug logging is enabled by default in development
);

// All requests are automatically logged with cURL commands
final response = await DioRequestHandler.get(
  'users',
  requestOptions: RequestOptionsModel(hasBearerToken: true),
);

๐Ÿ“š Quick Reference #

โšก Common operations at a glance #

๐Ÿ”— API Calls Cheat Sheet

// GET request
final users = await DioRequestHandler.get('users');

// POST with data
final created = await DioRequestHandler.post('users', data: userData);

// PUT update
final updated = await DioRequestHandler.put('users/123', data: updates);

// DELETE
final deleted = await DioRequestHandler.delete('users/123');

// With authentication
final profile = await DioRequestHandler.get(
  'profile',
  requestOptions: RequestOptionsModel(hasBearerToken: true),
);

// With caching
final cached = await DioRequestHandler.get(
  'static-data',
  requestOptions: RequestOptionsModel(
    cacheOptions: CacheOptions(
      shouldCache: true,
      cacheDuration: Duration(minutes: 30),
    ),
  ),
);

๐Ÿ”‘ Authentication Cheat Sheet

// Set tokens
await TokenManager.setTokens(
  accessToken: 'access_token',
  refreshToken: 'refresh_token',
  expiry: DateTime.now().add(Duration(hours: 1)),
);

// Check if authenticated
final isAuthenticated = await TokenManager.hasAccessToken();

// Get current token (auto-refreshes if needed)
final token = await TokenManager.getAccessToken();

// Clear tokens (logout)
await TokenManager.clearTokens();

๐Ÿ“ File Operations Cheat Sheet

// Upload file (mobile/desktop)
final upload = await FileHandler.uploadFile('upload', file);

// Upload bytes (all platforms)
final upload = await FileHandler.uploadBytes('upload', bytes, 'file.jpg');

// Download file (mobile/desktop)
final download = await FileHandler.downloadFile('files/123', '/path/file.pdf');

// Download bytes (all platforms)
final download = await FileHandler.downloadBytes('files/123');

// Get file information without downloading
final fileInfo = await FileHandler.getFileInfo('files/123');

๐Ÿงช Testing Cheat Sheet

// Enable mocking
MockDioFlow.enableMockMode();

// Mock success response
MockDioFlow.mockResponse('users', MockResponse.success([...]));

// Mock error response
MockDioFlow.mockResponse('users', MockResponse.failure('Error message'));

// Mock network error
MockDioFlow.mockResponse('users', MockResponse.networkError());

// Disable mocking
MockDioFlow.disableMockMode();

๐Ÿค Contributing #

We love contributions! Help make Dio Flow even better ๐Ÿ’ช #

Contributions are welcome! Whether it's:

  • ๐Ÿ› Bug Reports: Found an issue? Let us know!
  • โœจ Feature Requests: Have an idea? We'd love to hear it!
  • ๐Ÿ“– Documentation: Help improve our docs
  • ๐Ÿ”ง Code Contributions: Submit a PR!

Please read our Contributing Guide for details on our code of conduct and the process for submitting pull requests.

๐ŸŒŸ Contributors #

Thanks to all our amazing contributors who help make Dio Flow better!


๐Ÿ“„ License #

๐Ÿ“œ MIT License - Free for everyone, everywhere #

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

Made with โค๏ธ by the Flutter community


๐ŸŒŸ Star us on GitHub if Dio Flow helped you #

GitHub stars

Happy coding! ๐Ÿš€

7
likes
0
points
14
downloads

Publisher

verified publishermoeinmoradi.ir

Weekly Downloads

Flexible HTTP client for Flutter, built on Dio with mock support, GraphQL, file handling, caching, and token management.

Repository (GitHub)
View/report issues

Documentation

Documentation

License

unknown (license)

Dependencies

colorful_log_plus, dio, flutter, log_curl_request, shared_preferences

More

Packages that depend on dio_flow