{"id":13526012,"url":"https://github.com/GoodRequest/GoodNetworking","last_synced_at":"2025-04-01T06:31:01.511Z","repository":{"id":81791941,"uuid":"593148968","full_name":"GoodRequest/GoodNetworking","owner":"GoodRequest","description":"📡 GoodNetworking is an iOS library written in Swift that simplifies HTTP networking by using GRSession and Encodable/DataRequest extensions. It supports latest Swift and all iOS devices, making it a powerful solution for managing network interactions and data encoding/decoding. The library is easy to install with SPM.","archived":false,"fork":false,"pushed_at":"2024-10-17T08:37:09.000Z","size":521,"stargazers_count":31,"open_issues_count":5,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-10-20T01:09:38.305Z","etag":null,"topics":["ios","library","swift"],"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/GoodRequest.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","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":"2023-01-25T11:00:30.000Z","updated_at":"2024-10-17T08:34:34.000Z","dependencies_parsed_at":"2024-01-11T11:45:44.645Z","dependency_job_id":"24e81a48-b118-4a13-97f6-b3c274cd9481","html_url":"https://github.com/GoodRequest/GoodNetworking","commit_stats":null,"previous_names":[],"tags_count":29,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GoodRequest%2FGoodNetworking","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GoodRequest%2FGoodNetworking/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GoodRequest%2FGoodNetworking/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GoodRequest%2FGoodNetworking/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GoodRequest","download_url":"https://codeload.github.com/GoodRequest/GoodNetworking/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":222703737,"owners_count":17025838,"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","library","swift"],"created_at":"2024-08-01T06:01:24.303Z","updated_at":"2024-11-02T10:31:25.173Z","avatar_url":"https://github.com/GoodRequest.png","language":"Swift","funding_links":[],"categories":["Libs"],"sub_categories":["Network"],"readme":"![Logo](good-networking.png)\n\n# GoodNetworking\n\n[![iOS Version](https://img.shields.io/badge/iOS_Version-\u003e=_13.0-brightgreen?logo=apple\u0026logoColor=green)]() \n[![Swift Version](https://img.shields.io/badge/Swift_Version-6.0-green?logo=swift)](https://docs.swift.org/swift-book/)\n[![Supported devices](https://img.shields.io/badge/Supported_Devices-iPhone/iPad-green)]()\n[![Contains Test](https://img.shields.io/badge/Tests-YES-blue)]()\n[![Dependency Manager](https://img.shields.io/badge/Dependency_Manager-SPM-red)](#swiftpackagemanager)\n\nGoodNetworking is a powerful Swift library designed to simplify HTTP networking by leveraging the capabilities of Swift’s concurrency model, Combine, and Alamofire. It provides a flexible and easy-to-use API for handling complex network operations, making it easier to perform tasks such as sending requests, downloading, and uploading data.\n\nKey Features\n\n    • NetworkSession: A powerful and flexible mechanism for managing HTTP sessions, providing built-in support for sending requests, downloading, and uploading files. It uses a session provider to handle session configuration and lifecycle management.\n\n    • Request Validation: Support for validating responses using custom validation providers.\n\n    • Flexible Endpoint Handling: Define your own endpoint configurations with ease, allowing for a clean and maintainable way to manage network requests.\n\n## Documentation\nCheck out GoodNetworking documentation [here](https://goodrequest.github.io/GoodNetworking/documentation/goodnetworking/)\n\n## Installation\n### Swift Package Manager\n\nCreate a `Package.swift` file and add the package dependency into the dependencies list.\nOr to integrate without package.swift add it through the Xcode add package interface.\n\n[//]: \u003c\u003e (Don't forget add the version once available.')\n```swift\nimport PackageDescription\n\nlet package = Package(\n    name: \"SampleProject\",\n    dependencies: [\n        .package(url: \"https://github.com/GoodRequest/GoodNetworking\" from: \"addVersion\")\n    ]\n     targets: [\n        .target(\n            name: \"Sample Target\",\n            dependencies: [\n                .product(name: \"GoodNetworking\", package: \"GoodNetworking\"),\n            ],\n        ),\n    ]\n)\n```\n\n## Usage\n\n### Quick start session\nCreate an session actor best handled with dependency injection pattern\n```swift\nextension NetworkSession {\n\n    static var sampleSession: NetworkSession(baseUrl: \"https://reqres.in/api\")\n\n}\n```\n\nCreate a sample endpoint\n```swift\nimport GoodNetworking\n\nenum SampleEndpoint: Endpoint {\n\n    case singleUser(id: Int)\n\n    var path: String {\n        switch self {\n        case .singleUser(let id):\n            \"users/\\(id)\"\n    }\n\n}\n```\n\nCreate a viewmodel where you call the async function to fetch the user.\n```swift\n@MainActor\nfinal class UserProfileViewModel {\n\n    var userProfile: Result\u003cUser, Error\u003e!\n\n    func fetchUser() async {\n        do {\n            let result: User = try await NetworkSession.sampleSession.request(endpoint: SampleEndpoint.singleUser(id: 1))\n            userProfile = .success(result)\n        } catch {\n            userProfile = .failure(error)\n        }\n    }\n\n}\n\n```\n### Rich sample session\nOfcourse the is much more\n\nOur session works with alamofire session wrapping it easy to use.\n\n### Initilize session\nThere are 3 different initializers for our session\n\nYou can initilize with the parameter `baseUrlProvider` comforming to `BaseUrlProviding` protocol serving as `baseUrl` to your API calls where `String` is overloaded comform to it so any string `baseUrl` will work, but you can also provide more intricate logic that handles runtime `baseUrl` swapping.\n\nThe next parameter `sessionProvider` similarly to the first one as by default works with a `DefaultSessionProvider` that holds just a session with a default `UrlSessionConfiguration` so you can omit it, but you can also user `DefaultSessionProvider`'s configuration init parameter and provide your own `NetworkSessionConfiguration`.\nThe other initializers serve as convenience to initializer these 2 values indirectly through other types.\n\nDefault\n```swift\n    public init(\n        baseUrlProvider: BaseUrlProviding? = nil,\n        sessionProvider: NetworkSessionProviding = DefaultSessionProvider(configuration: .default)\n    ) {\n        self.baseUrlProvider = baseUrlProvider\n        self.sessionProvider = sessionProvider\n    }\n```\nBackwards compatibility for our older projects\n```swift\n    public init(\n        baseUrl: BaseUrlProviding? = nil,\n        configuration: NetworkSessionConfiguration = .default\n    ) {\n        self.baseUrlProvider = baseUrl\n        self.sessionProvider = DefaultSessionProvider(configuration: configuration)\n    }\n```\nCustomizable session if you need more than just the basic session parameters provided by `NetworkSessionConfiguration`\n```swift\n    public init(\n        baseUrlProvider: BaseUrlProviding? = nil,\n        session: Alamofire.Session\n    ) {\n        self.baseUrlProvider = baseUrlProvider\n        self.sessionProvider = DefaultSessionProvider(session: session)\n    }\n```\n\n### Requests in views\n\nWith this library you can directly call the request and update the state for a more straithforward way to update the UI\n\n```swift\nimport Alamofire\nimport GoodNetworking\nimport SwiftUI\n\nstruct UserScreen: View {\n\n    @State private var user = Resource(session: .sampleSession, remote: RemoteUser.self)\n\n    let userId: Int\n\n    var body: some View {\n        ScrollView {\n            VStack(spacing: 24) {\n                userView(user: user.state)\n            }\n            .padding()\n        }\n        .refreshable {\n            try? await user.read(forceReload: true)\n        }\n        .task {\n            try? await user.read(request: UserRequest(id: userId))\n        }\n    }\n\n    private func loadingView() -\u003e some View {\n        HStack(spacing: 8) {\n            ProgressView()\n            Text(\"Loading...\")\n        }\n    }\n\n    @ViewBuilder private func userView(user: ResourceState\u003cUser, NetworkError\u003e) -\u003e some View {\n        switch user {\n        case .idle:\n            Text(\"Resource idle\")\n\n        case .loading:\n            HStack(spacing: 8) {\n                ProgressView()\n                Text(\"Loading...\")\n            }\n\n        case .failure(let e):\n            Text(e.localizedDescription)\n\n        case .available(let user):\n            let fields = [\n                \"ID\", \"First name\", \"Last name\", \"Email\"\n            ]\n            let values = [\n                String(user.id), user.firstName, user.lastName, user.email\n            ]\n\n            LazyVGrid(columns: [GridItem(), GridItem()]) {\n                ForEach(Array(zip(fields, values)), id: \\.0) { field, value in\n                    Text(field)\n                    Text(value)\n                }\n\n                Text(\"Avatar\")\n\n                AsyncImage(url: user.avatar)\n                    .aspectRatio(1, contentMode: .fit)\n            }\n\n        default:\n            Text(\"Unknown state\")\n        }\n    }\n\n}\n```\n\nAnd you define yourself a model\n\n```swift\nstruct User: Codable {\n\n    var id: Int\n    var email: String\n    var firstName: String\n    var lastName: String\n    var avatar: URL?\n\n}\n\nstruct UserRequest: Encodable {\n\n    let id: Int\n\n}\n\nstruct UserResponse: Decodable {\n\n    let data: User\n\n}\n\nextension User: Placeholdable {\n\n    static let placeholder: User = User(\n        id: 0,\n        email: \"empty@example.com\",\n        firstName: \"John\",\n        lastName: \"Apple\",\n        avatar: nil\n    )\n\n}\n\nstruct RemoteUser: Readable {\n\n    typealias Resource = User\n    typealias ReadRequest = UserRequest\n    typealias ReadResponse = UserResponse\n\n    nonisolated static func endpoint(_ request: ReadRequest) throws(NetworkError) -\u003e Endpoint {\n        SampleEndpoint.singleUser(id: request.id)\n    }\n\n    nonisolated static func request(from resource: Resource?) throws(NetworkError) -\u003e ReadRequest? {\n        guard let resource else { throw .missingLocalData }\n        return UserRequest(id: resource.id)\n    }\n\n    nonisolated static func resource(from response: ReadResponse) throws(NetworkError) -\u003e Resource {\n        response.data\n    }\n\n}\n```\nAnd voila, all is setup. You can update the user directly with a state variable. The library also support all the CRUD operations with protocols `Creatable`, `Readable`, `Updatable`, `Deletable` and also more like `Listable` for pagination of lists. \n\n## License\nGoodNetworking is released under the MIT license. See [LICENSE](LICENSE.md) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FGoodRequest%2FGoodNetworking","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FGoodRequest%2FGoodNetworking","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FGoodRequest%2FGoodNetworking/lists"}