{"id":21511995,"url":"https://github.com/strvcom/ios-networking","last_synced_at":"2025-04-09T18:21:16.017Z","repository":{"id":82559818,"uuid":"346012499","full_name":"strvcom/ios-networking","owner":"strvcom","description":"Repository for networking library","archived":false,"fork":false,"pushed_at":"2024-03-01T15:43:03.000Z","size":1353,"stargazers_count":5,"open_issues_count":2,"forks_count":1,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-03-16T09:06:01.841Z","etag":null,"topics":["ios","ios-library","ios-research"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/strvcom.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2021-03-09T13:17:44.000Z","updated_at":"2024-08-04T11:20:29.545Z","dependencies_parsed_at":"2023-10-03T17:05:50.436Z","dependency_job_id":"438db711-ebf6-4e22-803a-7f2186da76da","html_url":"https://github.com/strvcom/ios-networking","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strvcom%2Fios-networking","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strvcom%2Fios-networking/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strvcom%2Fios-networking/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strvcom%2Fios-networking/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/strvcom","download_url":"https://codeload.github.com/strvcom/ios-networking/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248085470,"owners_count":21045167,"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":["ios","ios-library","ios-research"],"created_at":"2024-11-23T22:24:50.224Z","updated_at":"2025-04-09T18:21:16.000Z","avatar_url":"https://github.com/strvcom.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Networking\n\n![Coverage](https://img.shields.io/badge/Coverage-100%25-darkgreen?style=flat-square)\n![Platforms](https://img.shields.io/badge/Platforms-iOS_iPadOS_macOS_watchOS-lightgrey?style=flat-square)\n![Swift](https://img.shields.io/badge/Swift-5.9+-blue?style=flat-square)\n\nA networking layer using native `URLSession` and Swift concurrency.\n\n- [Requirements](#requirements)\n- [Installation](#installation)\n- [Overview](#overview)\n- [Making requests](#making-requests)\n- [Downloading files](#downloading-files)\n- [Uploading files](#uploading-files)\n- [Request authorization](#request-authorization)\n- [Retry-ability](#retry-ability)\n- [Modifiers](#modifiers)\n- [Associated array query parameters](#associated-array-query-parameters)\n\n## Requirements\n\n- iOS/iPadOS 15.0+, macOS 12.0+, watchOS 9.0+\n- Xcode 14+\n- Swift 5.9+\n\n## Installation\n\nYou can install the library with [Swift Package Manager](https://swift.org/package-manager/). Once you have your Swift package set up, adding Dependency Injection as a dependency is as easy as adding it to the `dependencies` value of your `Package.swift`.\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/strvcom/ios-networking.git\", .upToNextMajor(from: \"0.0.4\"))\n]\n```\n\n## Overview\nHeavily inspired by Moya, the networking layer's philosophy is focused on creating individual endpoint routers, transforming them into a valid URLRequest objects and applying optional adapters and processors in the network call pipeline utilising native `URLSession` under the hood.\n\n## Making requests\nThere is no 1 line way of making a request from scratch in order to ensure consistency and better structure. First we need to define a Router by conforming to [Requestable](https://strvcom.github.io/ios-networking/documentation/networking/requestable) protocol. Which in the simplest form can look like this:\n```swift\nenum UserRouter: Requestable {\n    case getUser\n    \n    var baseURL: URL { \n        URL(string: \"https://reqres.in/api\")!\n    }\n\n    var path: String { \n        switch self {\n        case .getUser: \"/user\"\n        }\n    }\n\n    var method: HTTPMethod { \n        switch self {\n        case .getUser: .get\n        }\n    }\n}\n```\n\nThen we can make a request on an [APIManager](https://strvcom.github.io/ios-networking/documentation/networking/apimanager) instance, which is responsible for handling the whole request flow.\n```swift\nlet response = try await APIManager().request(UserRouter.getUser)\n```\nIf you specify object type, the [APIManager](https://strvcom.github.io/ios-networking/documentation/networking/apimanager) will automatically perform the decoding (given the received JSON correctly maps to the decodable). You can also specify a custom json decoder.\n\n```swift\nlet userResponse: UserResponse = try await apiManager.request(UserRouter.getUser)\n```\n\n## Downloading files\nDownloads are being handled by a designated [DownloadAPIManager](https://strvcom.github.io/ios-networking/documentation/networking/downloadapimanager). Here is an example of a basic form of file download from a `URL`. It returns a tuple of `URLSessionDownloadTask` and [Response](https://strvcom.github.io/ios-networking/documentation/networking/response) (result for the HTTP handshake).\n```swift\nlet (task, response) = try await DownloadAPIManager().request(url: URL)\n```\n\nYou can then observe the download progress for a given `URLSessionDownloadTask`\n```swift\nfor try await downloadState in downloadAPIManager.shared.progressStream(for: task) {\n    ...\n}\n```\n\nIn case you need to provide some specific info in the request, you can define a type conforming to [Requestable](https://strvcom.github.io/ios-networking/documentation/networking/requestable) protocol and pass that to the [DownloadAPIManager](https://strvcom.github.io/ios-networking/documentation/networking/downloadapimanager) instead of the `URL`.\n\n## Uploading files\nUploads are being handled by a designated [UploadAPIManager](https://strvcom.github.io/ios-networking/documentation/networking/uploadapimanager). Here is an example of a basic form of file upload to a `URL`. It returns an [UploadTask](https://strvcom.github.io/ios-networking/documentation/networking/uploadtask) which is a struct that represents + manages a `URLSessionUploadTask` and provides its state.\n```swift\nlet uploadTask = try await uploadManager.upload(.file(fileUrl), to: \"https://upload.com/file\")\n```\n\nYou can then observe the upload progress for a given [UploadTask](https://strvcom.github.io/ios-networking/documentation/networking/uploadtask)\n```swift\nfor await uploadState in await uploadManager.stateStream(for: task.id) {\n...\n}\n```\n\nIn case you need to provide some specific info in the request, you can define a type conforming to [Requestable](https://strvcom.github.io/ios-networking/documentation/networking/requestable) protocol and pass that to the [UploadAPIManager](https://strvcom.github.io/ios-networking/documentation/networking/uploadapimanager) instead of the upload `URL`.\n\n## Retry-ability\nBoth [APIManager](https://strvcom.github.io/ios-networking/documentation/networking/apimanager) and [DownloadAPIManager](https://strvcom.github.io/ios-networking/documentation/networking/downloadapimanager) allow for configurable retry mechanism. You can provide a custom after failure [RetryConfiguration](https://strvcom.github.io/ios-networking/documentation/networking/retryconfiguration), specifying the count of retries, delay and a handler that determines whether the request should be tried again. Otherwise, [RetryConfiguration.default](https://strvcom.github.io/ios-networking/documentation/networking/retryconfiguration/default) configuration is used.\n\n```swift\nlet retryConfiguration = RetryConfiguration(retries: 2, delay: .constant(1)) { error in \n    // custom logic here\n}\nlet userResponse: UserResponse = try await apiManager.request(\n    UserRouter.getUser,\n    retryConfiguration: retryConfiguration\n)\n``` \n\n## Modifiers\nModifiers are useful pieces of code that modify request/response in the network request pipeline.\n![Interceptors diagram](Sources/Networking/Documentation.docc/Resources/interceptors-diagram.png)\n\nThere are three types you can leverage:\u003cbr\u003e\n\n[RequestAdapting](https://strvcom.github.io/ios-networking/documentation/networking/requestadapting)\n\nAdapters are request transformable components that perform operations on the URLRequest before it is dispatched. They are used to further customise HTTP requests before they are carried out by editing the URLRequest (e.g updating headers).\n\n[ResponseProcessing](https://strvcom.github.io/ios-networking/documentation/networking/responseprocessing)\n\nResponse processors are handling the ``Response`` received after a successful network request.\n\n[ErrorProcessing](https://strvcom.github.io/ios-networking/documentation/networking/errorprocessing)\n\nError processors are handling the `Error` received after a failed network request.\n\n[RequestInterceptor](https://strvcom.github.io/ios-networking/documentation/networking/requestinterceptor)\n\nInterceptors handle both adapting and response/error processing.\n\nBy conforming to these protocols, you can create your own adaptors/processors/interceptors.\n\nHere is list of classes provided by this library which implement these protocols:\n- [StatusCodeProcessor](https://strvcom.github.io/ios-networking/documentation/networking/statuscodeprocessor)\n- [EndpointRequestStorageProcessor](https://strvcom.github.io/ios-networking/documentation/networking/endpointrequeststorageprocessor)\n- [LoggingInterceptor](https://strvcom.github.io/ios-networking/documentation/networking/logginginterceptor)\n- [AuthorizationTokenInterceptor](https://strvcom.github.io/ios-networking/documentation/networking/authorizationtokeninterceptor)\n\n## Request authorization\nNetworking provides a default authorization handling for OAuth scenarios. In order to utilise this we\nhave to first create our own implementation of [AuthorizationStorageManaging](https://strvcom.github.io/ios-networking/documentation/networking/authorizationstoragemanaging) and [AuthorizationManaging](https://strvcom.github.io/ios-networking/documentation/networking/authorizationmanaging) which we inject into to  [AuthorizationTokenInterceptor](https://strvcom.github.io/ios-networking/documentation/networking/authorizationtokeninterceptor) and then pass\nit to the [APIManager](https://strvcom.github.io/ios-networking/documentation/networking/apimanager) as both adapter and processor.\n\n```swift\nlet authManager = AuthorizationManager()\nlet authorizationInterceptor = AuthorizationTokenInterceptor(authorizationManager: authManager)\nlet apiManager = APIManager(\n            requestAdapters: [authorizationInterceptor],\n            responseProcessors: [authorizationInterceptor]\n        )\n```\n\nAfter login we have to save the [AuthorizationData](https://strvcom.github.io/ios-networking/documentation/networking/authorizationdata) to the [AuthorizationManager](https://strvcom.github.io/ios-networking/documentation/networking/authorizationmanager).\n\n```swift\nlet response: UserAuthResponse = try await apiManager.request(\n    UserRouter.loginUser(request)\n)\ntry await authManager.storage.saveData(response.authData)\n```\n\nThen we can simply define which request should be authorised via `isAuthenticationRequired` property of [Requestable](https://strvcom.github.io/ios-networking/documentation/networking/requestable) protocol.  \n\n```swift\nextension UserRouter: Requestable {\n    ...\n    var isAuthenticationRequired: Bool {\n        switch self {\n        case .getUser, .updateUser:\n            return true\n        }\n    }\n}\n```\n\n## Associated array query parameters\nWhen specifying urlParameters in the endpoint definition, use an [ArrayParameter](https://strvcom.github.io/ios-networking/documentation/networking/arrayparameter) to define multiple values for a single URL query parameter. The struct lets you decide which [ArrayEncoding](https://strvcom.github.io/ios-networking/documentation/networking/arrayencoding) will be used during the creation of the URL.\n\nThere are two currently supported encodings:\n\n1. Comma separated\n```swift\nhttp://example.com?filter=1,2,3\n```\n\n2. Individual (default)\n```swift\nhttp://example.com?filter=1\u0026filter=2\u0026filter=3\n```\n\n### Example\n```swift\nvar urlParameters: [String: Any]? { \n     [\"filter\": ArrayParameter([1, 2, 3], arrayEncoding: .individual)]\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstrvcom%2Fios-networking","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstrvcom%2Fios-networking","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstrvcom%2Fios-networking/lists"}