{"id":18239983,"url":"https://github.com/egzonarifi/netflex","last_synced_at":"2025-04-11T12:53:12.890Z","repository":{"id":260780618,"uuid":"882271617","full_name":"EgzonArifi/NetFlex","owner":"EgzonArifi","description":"Flexible Networking library in Swift","archived":false,"fork":false,"pushed_at":"2025-01-09T13:08:41.000Z","size":109,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-25T09:11:40.140Z","etag":null,"topics":["authorization","interceptor","ios","networking","parameter-encoding","swift","urlrequest"],"latest_commit_sha":null,"homepage":"","language":"Swift","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/EgzonArifi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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":"2024-11-02T11:20:01.000Z","updated_at":"2025-01-09T13:08:45.000Z","dependencies_parsed_at":"2024-11-02T15:22:39.106Z","dependency_job_id":"a301217c-cb9f-40b5-bef8-dce601112ed3","html_url":"https://github.com/EgzonArifi/NetFlex","commit_stats":null,"previous_names":["egzonarifi/netflex"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EgzonArifi%2FNetFlex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EgzonArifi%2FNetFlex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EgzonArifi%2FNetFlex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EgzonArifi%2FNetFlex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/EgzonArifi","download_url":"https://codeload.github.com/EgzonArifi/NetFlex/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248403458,"owners_count":21097509,"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":["authorization","interceptor","ios","networking","parameter-encoding","swift","urlrequest"],"created_at":"2024-11-05T04:04:22.440Z","updated_at":"2025-04-11T12:53:12.872Z","avatar_url":"https://github.com/EgzonArifi.png","language":"Swift","readme":"\u003cp align=\"center\"\u003e\n    \u003ca href=\"Resources/Docs/README.md\"\u003e\n      \u003cimg src=\"Resources/Images/netflex.png\" width=\"50%\" alt=\"Lingua\" /\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://www.swift.org\" alt=\"Swift\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/Swift-5.9-orange.svg\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"./LICENSE\" alt=\"License\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/Licence-MIT-green.svg\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/egzonarifi/netflex/actions/workflows/tests.yml\" alt=\"Tests Status\"\u003e\n        \u003cimg src=\"https://github.com/egzonarifi/netflex/actions/workflows/tests.yml/badge.svg\" /\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\n# NetFlex\n\nA simple, scalable, and testable networking library for Swift.\n\n## Features\n\n- 🏗 **Modular Architecture**: Easily customize and extend the networking layer.\n- 💪 **Type-Safe Requests**: Strong typing for API requests and responses.\n- 📦 **Lightweight**: Built on top of URLSession for minimal overhead.\n- 🚀 **Modern Concurrency**: Supports async/await in Swift.\n- 🔄 **Interceptor Support**: Modify requests and responses globally.\n- 🔐 **Automatic Token Refresh**: Built-in support for token refreshing.\n- 📝 **Logging**: Customizable logging for debugging and monitoring.\n- 🔄 **Retry Mechanism**: Implement retries with customizable policies.\n- 🔧 **Unit Tested**: Comprehensive tests for reliability.\n\n## Components\n\n### HTTPClient\n\nThe `HTTPClient` protocol is responsible for making raw HTTP requests and returning the data and response. It abstracts the underlying URLSession and can be easily mocked for testing.\n\n### URLSessionHTTPClient\n\n`URLSessionHTTPClient` is a concrete implementation of `HTTPClient` that uses URLSession to make network requests. It can be configured with custom URLSession instances.\n\n### RequestExecutor\n\n`RequestExecutor` is a protocol for executing API requests and decoding responses into specified Swift model types.\n\n### APIRequestExecutor\n\n`APIRequestExecutor` is a concrete implementation of `RequestExecutor`. It uses the provided `HTTPClient` to fetch data and decodes it into the specified model types.\n\n### Interceptors\n\nInterceptors allow you to modify requests and responses globally. This is useful for adding headers, logging, error handling, token refreshing, and more.\n\n- **RequestInterceptor**: A protocol for intercepting and modifying requests and responses.\n- **AuthorizationInterceptor**: Adds authentication credentials to requests.\n- **TokenRefreshInterceptor**: Handles automatic token refreshing upon receiving unauthorized responses.\n- **LoggingInterceptor**: Provides customizable logging for requests and responses.\n- **RetryInterceptor**: Implements retry logic for transient errors with customizable policies.\n\n## Usage\n\nThis networking library provides a convenient way to make API requests using `APIRequestExecutor` and `RequestExecutor`. Below, you will find examples of how to use these components to create and send API requests.\n\n### 1. Create a Request\n\nFirst, define a custom request type that conforms to the `Request` protocol. Include all necessary information for the API endpoint, such as the HTTP method, path, query parameters, and request body.\n\n```swift\nstruct GetUserByIdRequest: Request {\n    typealias Response = User\n\n    let id: String\n\n    var method: HTTPMethod {\n        .get\n    }\n\n    var path: String {\n        \"/users/\\(id)\"\n    }\n}\n```\n\n### 2. Initialize the APIRequestExecutor\n\n#### Without Interceptors\n\n```swift\nlet baseURL = URL(string: \"https://api.example.com\")!\nlet requestBuilder = DefaultURLRequestBuilder(baseURL: baseURL)\nlet httpClient = URLSessionHTTPClient()\nlet apiExecutor = APIRequestExecutor(\n    requestBuilder: requestBuilder,\n    httpClient: httpClient\n)\n```\n\n#### With Interceptors\n\nTo utilize interceptors like authentication, logging, and retries:\n\n```swift\n// Token provider and refresher\nlet tokenProvider = { () -\u003e String? in\n    return TokenStorage.shared.accessToken\n}\n\nlet tokenRefresher = {\n    try await AuthService.refreshToken()\n}\n\n// Initialize interceptors\nlet authorizationInterceptor = AuthorizationInterceptor(\n    tokenProvider: tokenProvider,\n    headerField: \"Authorization\",\n    tokenFormatter: { \"Bearer \\($0)\" }\n)\n\nlet tokenRefreshInterceptor = TokenRefreshInterceptor(\n    tokenProvider: tokenProvider,\n    tokenRefresher: tokenRefresher,\n    headerField: \"Authorization\",\n    tokenFormatter: { \"Bearer \\($0)\" },\n    statusCodesToRefresh: [401]\n)\n\nlet loggingInterceptor = LoggingInterceptor()\nlet retryInterceptor = RetryInterceptor(maxRetryCount: 3)\n\nlet interceptors: [RequestInterceptor] = [\n    tokenRefreshInterceptor,\n    authorizationInterceptor,\n    loggingInterceptor,\n    retryInterceptor\n]\n\n// Create an InterceptableHTTPClient\nlet httpClient = InterceptableHTTPClient(\n    httpClient: URLSessionHTTPClient(),\n    interceptors: interceptors,\n    maxRetryCount: 3\n)\n\nlet apiExecutor = APIRequestExecutor(\n    requestBuilder: requestBuilder,\n    httpClient: httpClient\n)\n```\n\n### 3. Send the Request\n\nUse the `send(_:)` function to send your request.\n\n```swift\nlet getUserRequest = GetUserByIdRequest(id: \"123\")\n\ndo {\n    let user = try await apiExecutor.send(getUserRequest)\n    print(\"User: \\(user)\")\n} catch {\n    print(\"Error: \\(error)\")\n}\n```\n\n## Advanced Usage\n\n### Customizing Authentication\n\nIf your API requires a different authentication scheme, customize the `AuthorizationInterceptor`.\n\n#### Custom Header and Token Format\n\n```swift\nlet authorizationInterceptor = AuthorizationInterceptor(\n    tokenProvider: tokenProvider,\n    headerField: \"X-API-Key\",\n    tokenFormatter: { $0 } // Use the token as is\n)\n```\n\n#### Adding Token to Query Parameters\n\n```swift\nlet authorizationInterceptor = AuthorizationInterceptor(\n    tokenProvider: tokenProvider,\n    headerField: nil, // Do not add to headers\n    addTokenToQuery: true,\n    queryParameterName: \"api_key\"\n)\n```\n\n### Token Refreshing\n\nHandle automatic token refreshing with `TokenRefreshInterceptor`:\n\n```swift\nlet tokenRefreshInterceptor = TokenRefreshInterceptor(\n    tokenProvider: tokenProvider,\n    tokenRefresher: tokenRefresher,\n    headerField: \"Authorization\",\n    tokenFormatter: { \"Bearer \\($0)\" },\n    statusCodesToRefresh: [401, 403]\n)\n```\n\n### Logging\n\nUse `LoggingInterceptor` to log requests and responses:\n\n```swift\nlet loggingInterceptor = LoggingInterceptor()\n```\n\n### Retry Mechanism\n\nImplement retries for transient errors:\n\n```swift\nlet retryInterceptor = RetryInterceptor(maxRetryCount: 3, retryDelay: 1.0)\n```\n\n### Combining Interceptors\n\nCombine multiple interceptors:\n\n```swift\nlet interceptors: [RequestInterceptor] = [\n    tokenRefreshInterceptor,\n    authorizationInterceptor,\n    loggingInterceptor,\n    retryInterceptor\n]\n\nlet httpClient = InterceptableHTTPClient(\n    httpClient: URLSessionHTTPClient(),\n    interceptors: interceptors,\n    maxRetryCount: 3\n)\n```\n\n## Customization\n\n- **Interceptors**: Create custom interceptors by conforming to the `RequestInterceptor` protocol.\n- **Error Handling**: Provide an `APIErrorHandler` to handle API-specific errors.\n- **Custom HTTPClient**: Create a class conforming to `HTTPClient` for specific configurations.\n\n## Testing\n\n- **Unit Tests**: NetFlex includes comprehensive unit tests for all components.\n- **Mocking**: Use `MockHTTPClient` and `MockURLProtocol` for testing.\n- **Testing Interceptors**: Write unit tests for interceptors to verify their behavior.\n\n## Installation\n\nAdd NetFlex to your project using Swift Package Manager:\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/egzonarifi/NetFlex.git\", from: \"1.0.1\")\n]\n```\n\n## License\n\nNetFlex is released under the MIT license. See LICENSE for details.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fegzonarifi%2Fnetflex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fegzonarifi%2Fnetflex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fegzonarifi%2Fnetflex/lists"}