{"id":18409034,"url":"https://github.com/objcio/tiny-networking","last_synced_at":"2025-04-09T06:10:42.423Z","repository":{"id":36395125,"uuid":"191357721","full_name":"objcio/tiny-networking","owner":"objcio","description":"Tiny Networking Library","archived":false,"fork":false,"pushed_at":"2024-09-25T09:46:16.000Z","size":32,"stargazers_count":261,"open_issues_count":4,"forks_count":37,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-02T04:06:22.077Z","etag":null,"topics":["networking","swift"],"latest_commit_sha":null,"homepage":"http://talk.objc.io/collections/networking","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/objcio.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2019-06-11T11:27:17.000Z","updated_at":"2025-02-07T22:10:30.000Z","dependencies_parsed_at":"2024-06-21T15:37:31.708Z","dependency_job_id":"4cca432f-0edd-407e-85c5-b79ba22a33f7","html_url":"https://github.com/objcio/tiny-networking","commit_stats":{"total_commits":33,"total_committers":9,"mean_commits":"3.6666666666666665","dds":0.4242424242424242,"last_synced_commit":"ee700f5d88ebabf59c9685563c2e2553b5120bc0"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/objcio%2Ftiny-networking","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/objcio%2Ftiny-networking/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/objcio%2Ftiny-networking/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/objcio%2Ftiny-networking/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/objcio","download_url":"https://codeload.github.com/objcio/tiny-networking/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247987285,"owners_count":21028895,"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":["networking","swift"],"created_at":"2024-11-06T03:23:14.495Z","updated_at":"2025-04-09T06:10:42.404Z","avatar_url":"https://github.com/objcio.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TinyNetworking\n\nThis package contains a tiny networking library. It provides a struct `Endpoint`, which combines a URL request and a way to parse responses for that request. Because `Endpoint` is generic over the parse result, it provides a type-safe way to use HTTP endpoints.\n\nHere are some examples:\n\n## A Simple Endpoint\n\nThis is an endpoint that represents a user's data (note that there are more fields in the JSON, left out for brevity):\n\n```swift\nstruct User: Codable {\n    var name: String\n    var location: String?\n}\n\nfunc userInfo(login: String) -\u003e Endpoint\u003cUser\u003e {\n    return Endpoint(json: .get, url: URL(string: \"https://api.github.com/users/\\(login)\")!)\n}\n\nlet sample = userInfo(login: \"objcio\")\n```\n\nThe code above is just a description of an endpoint, it does not load anything. `sample` is a simple struct, which you can inspect (for example, in a unit test).\n\nHere's how you can load an endpoint. The `result` is of type `Result\u003cUser, Error\u003e`.\n\n```swift\nURLSession.shared.load(endpoint) { result in\n   print(result)\n}\n```\n\nAlternatively, you can use the async/await option.\n```swift\nlet result = try await URLSession.shared.load(endpoint)\n``` \n\n## Authenticated Endpoints\n\nHere's an example of how you can have authenticated endpoints. You initialize the `Mailchimp` struct with an API key, and use that to compute an `authHeader`. You can then use the `authHeader` when you create endpoints.\n\n```swift\nstruct Mailchimp {\n    let base = URL(string: \"https://us7.api.mailchimp.com/3.0/\")!\n    var apiKey = env.mailchimpApiKey\n    var authHeader: [String: String] { \n        [\"Authorization\": \"Basic \" + \"anystring:\\(apiKey)\".base64Encoded] \n    }\n\n    func addContent(for episode: Episode, toCampaign campaignId: String) -\u003e Endpoint\u003c()\u003e {\n        struct Edit: Codable {\n            var plain_text: String\n            var html: String\n        }\n        let body = Edit(plain_text: plainText(episode), html: html(episode))\n        let url = base.appendingPathComponent(\"campaigns/\\(campaignId)/content\")\n        return Endpoint\u003c()\u003e(json: .put, url: url, body: body, headers: authHeader)\n    }\n}\n```\n\n## Custom Parsing\n\nThe JSON encoding and decoding are added as conditional extensions on top of the Codable infrastructure. However, `Endpoint` itself is not at all tied to that. Here's the type of the parsing function:\n\n```\nvar parse: (Data?, URLResponse?) -\u003e Result\u003cA, Error\u003e\n```\n\nHaving `Data` as the input means that you can write our own functionality on top. For example, here's a resource that parses images:\n\n```swift\nstruct ImageError: Error {}\n\nextension Endpoint where A == UIImage {\n    init(imageURL: URL) {\n        self = Endpoint(.get, url: imageURL) { data in\n            Result {\n                guard let d = data, let i = UIImage(data: d) else { throw ImageError() }\n                return i\n            }\n        }\n    }\n}\n```\n\nYou can also write extensions that do custom JSON serialization, or parse XML, or another format.\n\n## Testing Endpoints\n\nBecause an `Endpoint` is a plain struct, it's easy to test synchronously without a network connection. For example, you can test the image endpoint like this:\n\n```swift\nXCTAssertThrows(try Endpoint(imageURL: someURL).parse(nil, nil).get())\nXCTAssertThrows(try Endpoint(imageURL: someURL).parse(invalidData, nil).get())\nXCTAssertNoThrow(try Endpoint(imageURL: someURL).parse(validData, nil).get())\n```\n\n## Combine\n\nHsieh Min Che created a library that adds Combine endpoints to this library: https://github.com/Hsieh-1989/CombinedEndpoint\n\n## More Examples\n\n- In the [Swift Talk](https://talk.objc.io) backend, this is used to wrap [third-party services](https://github.com/objcio/swift-talk-backend/tree/master/Sources/SwiftTalkServerLib/ThirdPartyServices).\n\n## More Documentation\n\nThe design and implementation of this library is covered extensively on [Swift Talk](http://talk.objc.io/). There's a collection with all the relevant episodes:\n\n**[Networking](https://talk.objc.io/collections/networking)**\n\n[\u003cimg src=\"https://talk.objc.io/assets/images/collections/Networking.svg\"\u003e](https://talk.objc.io/collections/networking)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fobjcio%2Ftiny-networking","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fobjcio%2Ftiny-networking","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fobjcio%2Ftiny-networking/lists"}