{"id":27144211,"url":"https://github.com/vb10/vexana","last_synced_at":"2025-05-16T13:08:14.541Z","repository":{"id":37871162,"uuid":"297217854","full_name":"VB10/vexana","owner":"VB10","description":"Vexana is network manager project with dio.","archived":false,"fork":false,"pushed_at":"2025-05-16T08:37:14.000Z","size":6861,"stargazers_count":148,"open_issues_count":12,"forks_count":43,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-05-16T13:08:12.054Z","etag":null,"topics":["dio","flutter","network"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/vexana","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/VB10.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,"zenodo":null}},"created_at":"2020-09-21T03:24:48.000Z","updated_at":"2025-05-03T10:11:32.000Z","dependencies_parsed_at":"2023-11-19T15:33:20.869Z","dependency_job_id":"eacd0902-78bd-4763-b768-76722195f823","html_url":"https://github.com/VB10/vexana","commit_stats":{"total_commits":218,"total_committers":18,"mean_commits":12.11111111111111,"dds":"0.37155963302752293","last_synced_commit":"ac0444580facd8ccebac6a3bc2ec12ea0940e827"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VB10%2Fvexana","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VB10%2Fvexana/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VB10%2Fvexana/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VB10%2Fvexana/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/VB10","download_url":"https://codeload.github.com/VB10/vexana/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254535828,"owners_count":22087399,"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","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":["dio","flutter","network"],"created_at":"2025-04-08T08:58:28.524Z","updated_at":"2025-05-16T13:08:14.525Z","avatar_url":"https://github.com/VB10.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n\u003cp align=\"center\"\u003e\n\u003ca href=\"https://pub.dev/packages/vexana\"\u003e\u003cimg src=\"https://img.shields.io/pub/v/vexana.svg\" alt=\"Pub\"\u003e\u003c/a\u003e\n\u003ca href=\"https://pub.dev/packages/vexana\"\u003e\u003cimg src=\"https://img.shields.io/badge/vexana-package-blue\" alt=\"Pub\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/VB10/vexana\"\u003e\u003cimg src=\"https://img.shields.io/github/stars/vb10/vexana.svg?style=flat\u0026logo=github\u0026colorB=deeppink\u0026label=stars\" alt=\"Star on Github\"\u003e\u003c/a\u003e \n\u003ca href=\"https://opensource.org/licenses/MIT\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-MIT-purple.svg\" alt=\"License: MIT\"\u003e\u003c/a\u003e   \n\u003ca href=\"https://www.youtube.com/hardwareandro\"\u003e\u003cimg src=\"https://img.shields.io/youtube/channel/subscribers/UCdUaAKTLJrPZFStzEJnpQAg\" alt=\"Youtube: HardwareAndro\"\u003e\u003c/a\u003e\n\u003ca href=\"https://medium.com/@vbacik-10\"\u003e \u003cimg src=\"https://img.shields.io/badge/Medium-12100E?style=for-the-badge\u0026logo=medium\u0026logoColor=white\" alt=\"Medium: Vbacik\"\u003e  \u003c/a\u003e \n \n[![](https://dcbadge.vercel.app/api/server/T6hGJhRN27?style=flat)](https://discord.gg/T6hGJhRN27)\n\n\u003c/p\u003e\n\n# vexana\n\nVexana is easy to use network process with dio. You can do dynamic model parsing, base error model, timeout and many utility functions.\n\n![Vexana-Game](https://i.redd.it/ds3z4kobyp871.jpg)\n\n\n## Getting Started 🔥\n\nLet's talk about usage details. **You can learn more detail about vexana in test folder.** Please check it out before using this package. I'm not good to write a readme 😅\n\n### **Network Manager** 😎\n\nHave a lot of options: baseurl, logger, interceptors, base model etc.\n\n\u003e If you want to manage your error model, you just declare your model so it's way getting the error model everywhere.\n\n```dart\nINetworkManager  networkManager = NetworkManage\u003cNull or UserErrorModel\u003e(isEnableLogger: true, errorModel: UserErrorModel(),\n options: BaseOptions(baseUrl: \"https://jsonplaceholder.typicode.com/\"));\n```\n\n### **Model Parse** ⚔️\n\n- First, you have to provide the parse model, then the result model. (Result model could be a list, model or primitive)\n- \"You have two options: you can use either the `send` method or the `sendRequest` method.\"\n\n### `send`\n```dart\n    final response = await networkManager.send\u003cTodo, List\u003cTodo\u003e\u003e(\n      \"/todos\",\n      parseModel: Todo(),\n      method: RequestType.GET,\n    );\n```\n\n### `sendRequest`\n\nThis method is designed to improve the 'send' method. The response is a 'NetworkResult' object, which is a `sealed class`. You can use it however you like, either with pattern matching or other methods.\n\n```dart\n  final response = await networkManager.sendRequest\u003cTodo, List\u003cTodo\u003e\u003e(\n    '/todos',\n    parseModel: Todo(),\n    method: RequestType.GET,\n  );\n\n  // usage 1:\n  response.fold(\n    onSuccess: (data) {\n      // handle success case\n    },\n    onError: (error) {\n      // handle error case\n    },\n  );\n\n  // usage 2\n  final _ = switch (response) {\n    NetworkSuccessResult(:final data) =\u003e data,\n    NetworkErrorResult(:final error) =\u003e error,\n  };\n\n  // usage 3\n  if (response is NetworkSuccessResult\u003cList\u003cTodo\u003e, EmptyModel\u003e) {\n    final List\u003cTodo\u003e todos = response.data;\n    // use the data\n  }\n\n  // You can check the response using the `isSuccess` and `isError` getters. \n  if (response.isSuccess) {\n    final data = (response as NetworkSuccessResult\u003cList\u003cTodo\u003e,EmptyModel\u003e).data;\n    // handle success case\n    return;\n  }\n\n  if (response.isError) {\n    final error = (response as NetworkErrorResult\u003cList\u003cTodo\u003e,EmptyModel\u003e).error;\n    // handle error case\n    return;\n  }\n```\n\n### **Base Headers** 📍\n\nYou could be add key values to your every request directly.(add authentication key)\n\n```dart\n\nnetworkManager.addBaseHeader(MapEntry(HttpHeaders.authorizationHeader, response.data?.first.title ?? ''));\n// Clear single header\nnetworkManager.removeHeader('\\${response.data?.first.id}');\n// Clear all header\nnetworkManager.clearHeader();\n```\n\n### **FormData Upload and Response** 📤\n\nYou can send FormData and parse responses using IFormDataModel. This is particularly useful when uploading files or handling multipart/form-data requests.\n\n#### **Sending FormData**\n\nCreate your form data model by extending `INetworkModel` and using the `IFormDataModel` mixin:\n\n```dart\nclass UserFormData extends INetworkModel\u003cUserFormData\u003e with IFormDataModel\u003cUserFormData\u003e {\n  UserFormData({required this.name, required this.avatar});\n  \n  final String name;\n  final File avatar;\n\n  @override\n  Map\u003cString, dynamic\u003e toJson() {\n    return {\n      'name': name,\n      'avatar': MultipartFile.fromFileSync(avatar.path),\n    };\n  }\n\n  @override\n  UserFormData fromJson(Map\u003cString, dynamic\u003e json) {\n    // Implement fromJson if needed for response parsing\n    throw UnimplementedError();\n  }\n}\n```\n\nThen use it with the uploadFile method:\n\n```dart\nfinal formData = UserFormData(\n  name: 'John Doe',\n  avatar: File('path/to/avatar.jpg'),\n).toFormData();\n\nfinal response = await networkManager.uploadFile\u003cUserResponse\u003e(\n  '/upload',\n  formData,\n  headers: {'Content-Type': 'multipart/form-data'},\n);\n```\n\n### **Download File** 📍\n\n#### **Download File Simple**\n\nYou can download any file format like pdf, png or etc with progress indicator.\n\n```dart\nfinal response = await networkManager.downloadFileSimple('http://www.africau.edu/images/default/sample.pdf', (count, total) {\n      print('${count}');\n});\n\n//Example: Image.memory(response.data)\n```\n\n#### **Download File**\n\nYou can download by specifying model and request type.\n\n```dart\nfinal response = await networkManager.downloadFile(\n    'financial-report',\n    (count, total) {\n      print('${count}');\n    },\n    method: RequestType.POST,\n    data: FileDownloadModel(),\n);\n```\n\n### **HTTP Post Request with Request Body** 🚀\n\nThe model found in the request body must extend the abstract class INetworkModel, as follows.\n\n```dart\nclass TodoPostRequestData extends INetworkModel\u003cTodoPostRequestData\u003e\n```\n\nThen, since the model will have toJson and fromJson properties, you can create the object and pass it directly to the send method.\n\n\u003e So, it is sufficient to send only the request body object into the send method. You don't need to use toJson.\n\n```dart\nfinal todoPostRequestBody = TodoPostRequestData();\nfinal response =\nawait networkManager.send\u003cTodo, List\u003cTodo\u003e\u003e(\"/todosPost\", parseModel: Todo(), method: RequestType.POST, data: todoPostRequestBody);\n```\n\n### **Cancel Request** ❌\n\nYou can implement cancel token when need to invoke your request during to complete.\n\n```dart\n  final cancelToken = CancelToken();\n    networkManager\n        .send\u003cReqResModel, ReqResModel\u003e('/users?delay=5',\n            parseModel: ReqResModel(), method: RequestType.GET, canceltoken: cancelToken)\n        .catchError((err) {\n      if (CancelToken.isCancel(err)) {\n        print('Request canceled! ' + err.message);\n      }\n    });\n\n    cancelToken.cancel('canceled');\n\n    await Future.delayed(const Duration(seconds: 8));\n```\n\n### **Primitive Request** 🌼\n\nSometimes we need to parse only primitive types for instance List\u003cString\u003e, String, int etc. You can use this method.\n\n```dart\n//\n[\n  \"en\",\n  \"tr\",\n  \"fr\"\n]\n//\nnetworkManager.sendPrimitive\u003cList\u003e(\"languages\");\n```\n\n### **Network Model** 🛒\n\nYou must wrap your model with INetworkModel so that, we understand model has toJson and fromJson methods.\n\n```dart\nclass Todo extends INetworkModel\u003cTodo\u003e\n```\n\n### **Refresh Token** ♻️\n\nMany projects use authentication structure for mobile security (like a jwt). It could need to renew an older token when the token expires. This time provided a refresh token option, we can lock all requests until the token refresh process is complete.\n\n\u003e Since i locked all requests, I am giving a new service instance.\n\n```dart\nINetworkManager  networkManager = NetworkManager(\n        isEnableLogger: true,\n        options: BaseOptions(baseUrl: \"https://jsonplaceholder.typicode.com/\"),\n        onRefreshFail: () {\n            //Navigate to login \n        }, \n        onRefreshToken: (error, newService) async {\n             \u003c!-- Write your refresh token business --\u003e\n             \u003c!-- Then update error.req.headers to new token --\u003e\n          return error;\n        }\n);\n```\n\n### **Caching** 🧲\n\nYou need to write a response model in the mobile device cache sometimes. It's here now. You can say expiration date and lay back 🙏\n\n```dart\n    await networkManager.send\u003cTodo, List\u003cTodo\u003e\u003e(\"/todos\",\n        parseModel: Todo(),\n        expiration: Duration(seconds: 3),\n        method: RequestType.GET);\n```\n\n\u003e You must declare a caching type. It has FileCache and SharedCache options now. `NetworkManager(fileManager: LocalFile());`\n\u003e If you want more implementation details about the cache, you should read [this article](https://medium.com/flutter-community/cache-manager-with-flutter-5a5db0d3a3e6)\n\n### **Without Network connection** 🧲\n\nEspecially, mobile device many times lost connection for many reasons so if you want to retry your request, you need to add this code and that's it. Your app user can be show bottom sheet dialog and they will be use this features only tree times because i added this rule.\n\n```dart\n    // First you must be initialize your context with NoNetwork class\n    networkManager = NetworkManager(\n      isEnableLogger: true,\n      noNetwork: NoNetwork(context),\n      options: BaseOptions(baseUrl: 'https://jsonplaceholder.typicode.com'),\n\n      errorModelFromData: _errorModelFromData, //This is optional.\n    );\n\n    // If you want to create custom widget, you can add in no network class with callback function.\n      networkManager = NetworkManager(\n      isEnableLogger: true,\n      noNetwork: NoNetwork(\n        context,\n        customNoNetwork: (onRetry) {\n          // You have to call this retry method your custom widget\n          return NoNetworkSample(onPressed: onRetry);\n        },\n      ),\n      options: BaseOptions(baseUrl: 'https://jsonplaceholder.typicode.com'),\n\n      //Example request\n       final response = await networkManager.send\u003cPost, List\u003cPost\u003e\u003e('/posts',\n        parseModel: Post(), method: RequestType.GET, isErrorDialog: true);\n```\n\n**And result!!**\n\n![alt](https://github.com/user-attachments/assets/6f236181-ad00-41da-98bf-02213f84216d)\n\n\n### **Error model handle** ❎\n\nThis point so important for many apps. Some business operation want to show any message or logic when user did a mistake like wrong password etc. You can manage very easily to error model for whole project with this usage.\n\n```dart\nINetworkManager  networkManager = NetworkManage\u003cUserErrorModel\u003e(isEnableLogger: true, errorModel: UserErrorModel(),\n options: BaseOptions(baseUrl: \"https://jsonplaceholder.typicode.com/\"));\n\n IResponseModel\u003cList\u003cPost\u003e?, BaseErrorModel?\u003e response =  networkManager.send\u003cPost, List\u003cPost\u003e\u003e('/posts',\n        parseModel: Post(), method: RequestType.GET);\n      \u003c!-- Error.model came from your backend with your declaration --\u003e\n      showDialog(response.error?.model?.message)\n```\n\n### Tasks\n\n---\n\n- [x] Example project\n- [x] Unit Test with json place holder\n- [x] Unit Test with custom api\n- [x] Handle network problem\n- [x] Make a unit test all layers(%70).\n- [x] Cache Option\n  - [ ] Hive Support\n  - [x] Web Cache Support\n- [x] Refresh Token Architecture\n- [x] Usage Utility\n- [ ] Readme Update\n\n## License\n\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)](/LICENSE)\n\n2020 created for @VB10\n\n## Youtube Channel\n\n---\n\n[![Youtube](https://yt3.ggpht.com/a/AATXAJyul3hpzl86GIjF-EZxBzy6T62PJxpvzRwz9AbUOw=s288-c-k-c0xffffffff-no-rj-mo)](https://www.youtube.com/c/HardwareAndro)\n\n# Contributors\n\n\u003ca href=\"https://github.com/VB10/vexana/graphs/contributors\"\u003e\n  \u003cimg src=\"https://contrib.rocks/image?repo=VB10/vexana\" /\u003e\n\u003c/a\u003e\n\nMade with [contrib.rocks](https://contrib.rocks).\n\n## **EARTHQUAKE 7.8 and 7.6 6Feb2023**\n\n![help](https://github.com/user-attachments/assets/a4f59e46-67e6-46e4-97c2-90b252f1e4d2)\n\nTurkey has recently been struck by a devastating earthquake with a magnitude of 7.8. The impact has been widespread and many communities have been severely affected. In this difficult time, we are reaching out to ask for your support. Any donation, no matter how small, will help us provide much-needed aid to those affected by the earthquake. Your generosity will help provide shelter, food, and medical supplies to those in need. Your contribution will make a real difference in the lives of those affected by this disaster. Thank you for your kindness and support.\n\nYou can donate for AHBAP with this site\n[AHBAP_DONATE](https://bagis.ahbap.org/bagis)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvb10%2Fvexana","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvb10%2Fvexana","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvb10%2Fvexana/lists"}