{"id":25895587,"url":"https://github.com/moein-dev/dio_flow","last_synced_at":"2025-07-30T08:09:02.532Z","repository":{"id":280277343,"uuid":"941438281","full_name":"Moein-dev/dio_flow","owner":"Moein-dev","description":"A powerful Flutter package that enhances Dio HTTP client with built-in support for caching, authentication, pagination, error handling, and standardized JSON utilities.","archived":false,"fork":false,"pushed_at":"2025-03-17T01:27:14.000Z","size":360,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-17T01:35:51.756Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/dio_flow","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Moein-dev.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-03-02T09:44:15.000Z","updated_at":"2025-03-17T01:27:17.000Z","dependencies_parsed_at":"2025-03-02T13:28:02.466Z","dependency_job_id":"9d5f4a5a-63a1-4f64-aa58-88796a35eef3","html_url":"https://github.com/Moein-dev/dio_flow","commit_stats":null,"previous_names":["moein-dev/dio_flow"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Moein-dev/dio_flow","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Moein-dev%2Fdio_flow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Moein-dev%2Fdio_flow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Moein-dev%2Fdio_flow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Moein-dev%2Fdio_flow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Moein-dev","download_url":"https://codeload.github.com/Moein-dev/dio_flow/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Moein-dev%2Fdio_flow/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267834806,"owners_count":24151642,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-30T02:00:09.044Z","response_time":70,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-02T22:32:06.858Z","updated_at":"2025-07-30T08:09:02.520Z","avatar_url":"https://github.com/Moein-dev.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🌊 Dio Flow\n\n[![pub package](https://img.shields.io/pub/v/dio_flow.svg)](https://pub.dev/packages/dio_flow)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)\n[![Flutter](https://img.shields.io/badge/Flutter-3.7.0+-02569B?logo=flutter)](https://flutter.dev)\n\nA powerful Flutter package that enhances Dio HTTP client with built-in support for caching, authentication, pagination, error handling, and standardized JSON utilities. Built for modern Flutter applications that need robust API integration.\n\n## 📋 Table of Contents\n\n- [Features](#-features)\n- [Installation](#-installation)\n- [Getting Started](#-getting-started)\n- [Core Components](#-core-components)\n- [Making Requests](#-making-requests)\n- [Response Handling](#-response-handling)\n- [Authentication](#-authentication)\n- [Advanced Features](#-advanced-features)\n- [Best Practices](#-best-practices)\n- [Troubleshooting](#-troubleshooting)\n- [Contributing](#-contributing)\n- [License](#-license)\n\n## ✨ Features\n\n- **🚀 Modern HTTP Client**: Built on top of Dio with enhanced features\n- **🔄 Smart Response Handling**: Automatic conversion of responses to strongly-typed models\n- **💾 Intelligent Caching**: Built-in response caching with configurable TTL\n- **🔑 Token Management**: Robust authentication with token refresh support\n- **🔁 Auto-Retry**: Configurable retry logic for failed requests\n- **⚡ Rate Limiting**: Prevent API throttling with built-in rate limiting\n- **📶 Network Awareness**: Automatic handling of connectivity changes\n- **📊 Request Metrics**: Built-in performance tracking\n- **🔍 Detailed Logging**: Complete request/response logging with cURL commands\n- **📄 Pagination Support**: Built-in utilities for handling paginated responses\n- **🛡️ Type Safety**: Strong typing throughout the library\n- **🎯 Error Handling**: Comprehensive error handling with typed error responses\n\n## 📦 Installation\n\nAdd to your pubspec.yaml:\n\n```yaml\ndependencies:\n  dio_flow: ^1.1.7\n```\n\n## 🚀 Getting Started\n\n### Basic Setup\n\n```dart\nimport 'package:dio_flow/dio_flow.dart';\n\nvoid main() async {\n  WidgetsFlutterBinding.ensureInitialized();\n  \n  // 1. Configure the client\n  DioFlowConfig.initialize(\n    baseUrl: 'https://api.example.com',\n    connectTimeout: const Duration(seconds: 30),\n    receiveTimeout: const Duration(seconds: 30),\n    sendTimeout: const Duration(seconds: 30),\n  );\n  \n  // 2. Initialize the client\n  await ApiClient.initialize();\n  \n  runApp(MyApp());\n}\n```\n\n## 🎯 Core Components\n\n### DioRequestHandler\n\nThe main class for making HTTP requests:\n\n```dart\n// GET request\nfinal response = await DioRequestHandler.get(\n  'users',\n  parameters: {'role': 'admin'},\n  requestOptions: RequestOptionsModel(\n    hasBearerToken: true,\n    shouldCache: true,\n    retryOptions: RetryOptions(\n      maxAttempts: 3,\n      retryInterval: const Duration(seconds: 1),\n    ),\n  ),\n);\n\n// POST request with typed response\nfinal loginResponse = await DioRequestHandler.post\u003cLoginResponse\u003e(\n  'auth/login',\n  data: {\n    'email': 'user@example.com',\n    'password': '********',\n  },\n  requestOptions: RequestOptionsModel(\n    hasBearerToken: false,\n  ),\n);\n```\n\n### Response Models\n\nAll responses are wrapped in typed models:\n\n```dart\nif (response.isSuccess) {\n  final data = response.data;\n  // Handle success\n} else {\n  final error = response.error;\n  switch (error.errorType) {\n    case ErrorType.network:\n      // Handle network error\n      break;\n    case ErrorType.validation:\n      // Handle validation error\n      break;\n    case ErrorType.unauthorized:\n      // Handle auth error\n      break;\n    // ... handle other error types\n  }\n}\n```\n\n### Interceptors\n\nThe package includes several built-in interceptors:\n\n1. **MetricsInterceptor**: Tracks request performance\n2. **RateLimitInterceptor**: Prevents API throttling\n3. **DioInterceptor**: Handles authentication and headers\n4. **RetryInterceptor**: Manages request retries\n5. **ConnectivityInterceptor**: Handles network state\n6. **CacheInterceptor**: Manages response caching\n\n## 🔑 Authentication\n\nThe package provides robust token management with persistent storage:\n\n```dart\n// Initialize token manager (call this in your main.dart)\nvoid main() async {\n  WidgetsFlutterBinding.ensureInitialized();\n  await TokenManager.initialize();\n  runApp(MyApp());\n}\n\n// Setting tokens with persistence\nawait TokenManager.setTokens(\n  accessToken: 'your_access_token',\n  refreshToken: 'your_refresh_token',\n  expiry: DateTime.now().add(Duration(hours: 1)),\n);\n\n// Getting access token (automatically handles refresh if needed)\nfinal token = await TokenManager.getAccessToken();\n\n// Clearing tokens\nawait TokenManager.clearTokens();\n```\n\nKey features:\n- Persistent token storage using SharedPreferences\n- Automatic token loading on app initialization\n- Token expiry tracking and automatic refresh\n- Secure token management with proper error handling\n- Asynchronous operations for better performance\n\n### Protected Requests\n\n```dart\n// Make authenticated request\nfinal response = await DioRequestHandler.get(\n  'user/profile',\n  requestOptions: RequestOptionsModel(\n    hasBearerToken: true, // This will automatically include the token\n  ),\n);\n\n// Handle token expiration\nif (response.error?.errorType == ErrorType.unauthorized) {\n  // Token expired, handle refresh or logout\n}\n```\n\n## 🌐 Endpoint Configuration\n\n### Basic Endpoints\n\n```dart\n// Register endpoints\nEndpointProvider.instance.register('login', '/auth/login');\nEndpointProvider.instance.register('users', '/api/users');\n\n// Use registered endpoints\nfinal response = await DioRequestHandler.post(\n  'login',\n  data: {'email': email, 'password': password},\n);\n```\n\n### Dynamic Endpoints\n\n```dart\n// Register endpoint with parameters\nEndpointProvider.instance.register('user_details', '/api/users/{id}');\n\n// Use with path parameters\nfinal response = await DioRequestHandler.get(\n  'user_details',\n  pathParameters: {'id': '123'},\n);\n```\n\n## 🔄 Advanced Features\n\n### Caching\n\n```dart\n// Enable caching for a request\nfinal response = await DioRequestHandler.get(\n  'users',\n  requestOptions: RequestOptionsModel(\n    shouldCache: true,\n    cacheMaxAge: const Duration(minutes: 5),\n  ),\n);\n\n// Clear cache\nawait ApiClient.clearCache();\n```\n\n### Pagination\n\n```dart\n// Using pagination utilities\nfinal paginatedResponse = await DioRequestHandler.get(\n  'posts',\n  parameters: {\n    'page': 1,\n    'per_page': 20,\n  },\n);\n\nfinal pagination = PaginationHelper.fromResponse(paginatedResponse);\nfinal hasMore = pagination.hasNextPage;\nfinal totalPages = pagination.totalPages;\n```\n\n### JSON Utilities\n\n```dart\n// Safe JSON parsing\nfinal jsonData = JsonUtils.tryParseJson(rawJson);\n\n// Access nested values safely\nfinal nestedValue = JsonUtils.getNestedValue(\n  jsonData,\n  'user.profile.name',\n  'Default Name',\n);\n```\n\n### Request Queueing\n\n```dart\n// Queue multiple requests\nfinal responses = await Future.wait([\n  DioRequestHandler.get('users'),\n  DioRequestHandler.get('posts'),\n  DioRequestHandler.get('comments'),\n]);\n\n// Handle rate limiting automatically\nfinal rateLimitedResponse = await DioRequestHandler.get(\n  'high-frequency-endpoint',\n  requestOptions: RequestOptionsModel(\n    shouldRateLimit: true,\n    rateLimit: 30, // requests per minute\n  ),\n);\n```\n\n### Custom Response Types\n\n```dart\nclass PaginatedResponse\u003cT\u003e {\n  final List\u003cT\u003e items;\n  final int total;\n  final int page;\n  \n  PaginatedResponse.fromJson(\n    Map\u003cString, dynamic\u003e json,\n    T Function(Map\u003cString, dynamic\u003e) converter,\n  )   : items = (json['data'] as List)\n            .map((item) =\u003e converter(item))\n            .toList(),\n        total = json['total'] ?? 0,\n        page = json['page'] ?? 1;\n}\n\n// Use with typed response\nfinal response = await DioRequestHandler.get\u003cPaginatedResponse\u003cUser\u003e\u003e(\n  'users',\n  converter: (json) =\u003e PaginatedResponse.fromJson(\n    json,\n    (item) =\u003e User.fromJson(item),\n  ),\n);\n```\n\n## 🛠️ Best Practices\n\n1. **Initialize Early**:\n   ```dart\n   void main() async {\n     await ApiClient.initialize();\n     // ... rest of your app initialization\n   }\n   ```\n\n2. **Handle Errors Consistently**:\n   ```dart\n   try {\n     final response = await DioRequestHandler.get('endpoint');\n     if (response.isSuccess) {\n       // Handle success\n     } else {\n       // Use the typed error handling\n       handleError(response.error);\n     }\n   } catch (e) {\n     // Handle unexpected errors\n   }\n   ```\n\n3. **Use Type-Safe Responses**:\n   ```dart\n   class UserResponse {\n     final String id;\n     final String name;\n     \n     UserResponse.fromJson(Map\u003cString, dynamic\u003e json)\n         : id = json['id'],\n           name = json['name'];\n   }\n   \n   final response = await DioRequestHandler.get\u003cUserResponse\u003e(\n     'users/me',\n     converter: (json) =\u003e UserResponse.fromJson(json),\n   );\n   ```\n\n### Error Handling Patterns\n\n```dart\n// Create a reusable error handler\nFuture\u003cT\u003e handleApiResponse\u003cT\u003e(ResponseModel response) async {\n  if (response.isSuccess) {\n    return response.data as T;\n  }\n\n  switch (response.error?.errorType) {\n    case ErrorType.network:\n      throw NetworkException(response.error!.message);\n    case ErrorType.unauthorized:\n      await handleUnauthorized();\n      throw AuthException(response.error!.message);\n    case ErrorType.validation:\n      throw ValidationException(response.error!.message);\n    default:\n      throw ApiException(response.error?.message ?? 'Unknown error');\n  }\n}\n\n// Use in your code\ntry {\n  final users = await handleApiResponse\u003cList\u003cUser\u003e\u003e(\n    await DioRequestHandler.get('users'),\n  );\n  // Use users data\n} on NetworkException catch (e) {\n  // Handle network error\n} on AuthException catch (e) {\n  // Handle auth error\n} on ValidationException catch (e) {\n  // Handle validation error\n} on ApiException catch (e) {\n  // Handle other API errors\n}\n```\n\n### Repository Pattern\n\n```dart\nclass UserRepository {\n  Future\u003cUser\u003e getCurrentUser() async {\n    final response = await DioRequestHandler.get\u003cUser\u003e(\n      'users/me',\n      requestOptions: RequestOptionsModel(\n        hasBearerToken: true,\n        shouldCache: true,\n        cacheMaxAge: const Duration(minutes: 5),\n      ),\n      converter: (json) =\u003e User.fromJson(json),\n    );\n    \n    return handleApiResponse\u003cUser\u003e(response);\n  }\n  \n  Future\u003cvoid\u003e updateProfile(UserUpdateRequest request) async {\n    final response = await DioRequestHandler.put(\n      'users/me',\n      data: request.toJson(),\n      requestOptions: RequestOptionsModel(hasBearerToken: true),\n    );\n    \n    await handleApiResponse(response);\n  }\n}\n```\n\n## 🔍 Troubleshooting\n\nCommon issues and solutions:\n\n1. **Authentication Issues**:\n   - Ensure `hasBearerToken` is set correctly in `RequestOptionsModel`\n   - Check if tokens are properly managed in `TokenManager`\n\n2. **Caching Problems**:\n   - Verify `shouldCache` is enabled in request options\n   - Check cache duration settings\n   - Try clearing cache with `ApiClient.clearCache()`\n\n3. **Network Errors**:\n   - Check connectivity status\n   - Verify retry options are configured\n   - Examine cURL logs for request details\n\n### Debug Mode\n\n```dart\n// Enable detailed logging\nDioFlowConfig.initialize(\n  baseUrl: 'https://api.example.com',\n  debugMode: true, // This will enable detailed logging\n);\n\n// Log specific requests\nfinal response = await DioRequestHandler.get(\n  'users',\n  requestOptions: RequestOptionsModel(\n    shouldLogRequest: true, // Log this specific request\n  ),\n);\n```\n\n## 🤝 Contributing\n\nContributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.\n\n## 📄 License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoein-dev%2Fdio_flow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmoein-dev%2Fdio_flow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoein-dev%2Fdio_flow/lists"}