{"id":27024596,"url":"https://github.com/mrskwiggs/netswift","last_synced_at":"2025-04-04T21:29:40.009Z","repository":{"id":45412066,"uuid":"172932810","full_name":"MrSkwiggs/Netswift","owner":"MrSkwiggs","description":"A type-safe, high-level networking solution for Swift apps","archived":false,"fork":false,"pushed_at":"2025-03-26T15:11:20.000Z","size":308,"stargazers_count":25,"open_issues_count":0,"forks_count":5,"subscribers_count":4,"default_branch":"develop","last_synced_at":"2025-03-28T20:11:41.287Z","etag":null,"topics":["http","http-requests","network","networking","url","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/MrSkwiggs.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}},"created_at":"2019-02-27T14:42:34.000Z","updated_at":"2025-03-26T15:11:24.000Z","dependencies_parsed_at":"2024-01-02T23:56:07.371Z","dependency_job_id":null,"html_url":"https://github.com/MrSkwiggs/Netswift","commit_stats":{"total_commits":200,"total_committers":5,"mean_commits":40.0,"dds":0.375,"last_synced_commit":"6e26b26e367098aaf5c3f1ecc1ab2eb536534352"},"previous_names":[],"tags_count":29,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MrSkwiggs%2FNetswift","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MrSkwiggs%2FNetswift/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MrSkwiggs%2FNetswift/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MrSkwiggs%2FNetswift/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MrSkwiggs","download_url":"https://codeload.github.com/MrSkwiggs/Netswift/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247251709,"owners_count":20908559,"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":["http","http-requests","network","networking","url","urlrequest"],"created_at":"2025-04-04T21:29:39.306Z","updated_at":"2025-04-04T21:29:40.001Z","avatar_url":"https://github.com/MrSkwiggs.png","language":"Swift","readme":"![Netswift Header](header.png)\n\n[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FMrSkwiggs%2FNetswift%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/MrSkwiggs/Netswift)\n[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FMrSkwiggs%2FNetswift%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/MrSkwiggs/Netswift)\n\n## What\n**Type-safe network calls made easy**\n\nNetswift offers an easy way to perform network calls in a structured and type-safe way. \n\n## Why\nNetworking in Swift can be tedious from the get go. Type safety \u0026 reusability are often overlooked for the sake of getting up to speed. Have a huge file with all your API calls which is getting hard to maintain? This is where Netswift comes in.\n\n# Using Netswift\n\n## TL;DR?\nThis is how easy it is to perform network calls with Netswift:\n```swift\nNetswift().peform(StripeAPI.Charges.get(byID: \"1234\")) { result in\n  switch result {\n  case .failure(let error):\n    // Our request failed: we can use the error to debug it\n    print(error)\n    \n  case .success(let charge):\n    // Our request succeeded: we now have a Charge object from the Stripe API\n    print(charge.amount)\n  }\n}\n```\n\n## Prerequisites\nI'm assuming you have an available iOS project set up with this cocoapod, ready to go. If not, please follow the [installation steps](#installation).\n\n## Writing our first request\nAs all reputable tutorials, the following steps will help you set up our first Hello World request. \n\n#### What we'll do\n- [Step 1](#step-1): Define a container which will act as the base of implementation for our API.\n- [Step 2](#step-2): Implement `NetswiftRoute`, which defines the different `URLComponents` of our endpoints.\n- [Step 3](#step-3): Implement `NetswiftRequest`, which defines how your container can be turned into a `URLRequest`\n- [Step 4](#step-4): Passing it all to the generic `Netswift` class and performing your first request 🙌\n- Step 5: ????\n- Step 6: Profit 👍\n\n#### Endpoint\nTo facilitate this tutorial, I went ahead and set up a mock API for you to query. It only has one endpoint, which returns a single object that contains a title. [Give it a try](https://my-json-server.typicode.com/MrSkwiggs/Netswift-HelloWorld/Netswift)\n\n### Step 1\nIn this particular case, and to keep things simple, we can go ahead and define a new `enum`. We'll use it to implement the minimum required protocol functions which will allow us to perform our request.\n\nSo go ahead; add a new file to your project and name it however you like. I chose `MyAPI`. Then, don't forget to `import Netswift`, and create your API Container like such:\n```swift\nimport Netswift\n\nenum MyAPI {\n  case helloWorld\n}\n```\n\nAnd that's pretty much it. Now, since our API only has one endpoint, there's really nothing more to this. \nThe great thing about Swift's `enum` is that they can also have associated values. This comes in very handy when you need to pass additional data to your endpoint, all while keeping it type-safe \u0026 structured. Neat 👌\n\n### Step 2\nSo we have our enum. Great. But it doesn't do much. Let's fix that.\n\nGo ahead and define an extension for it which implements the `NetswiftRoute` protocol:\n```swift\nextension MyAPI: NetswiftRoute {\n}\n```\n\nImmediately, the compiler starts complaining. Pressing 'Add protocol stubs' will make it happy again. This will add two variables:\n- `host`: This defines the domain of our API, usually something like www.example.com.\n- `path`: A specific resource on our API. Unless you're just GET-ing a website, you'll need to define a path.\n\nSo let's go ahead and implement those two.\n```swift\nvar host: String {\n  return \"my-json-server.typicode.com\"\n}\n\nvar path: String? {\n  switch self {\n    case .helloWorld: return \"MrSkwiggs/Netswift-HelloWorld/Netswift\"\n  }\n}\n```\n\nWhat did we just do ?\n\nOur container is an `enum`, which means we can very easily define different return values given each case. For the `host`, we always want to return the same value. \n\nFor the `path` however, we are taking advantage of this feature. We set it up in a future-proof way so that we can always add paths later (as new enum cases). When that time comes, the compiler will yell at us for not covering all cases of our `enum` 👍\n\nAnd that's pretty much everything we need for now. A lot of work is done under the hood by default; we can always define more information such as scheme (http or https) and query it if we need it, but in the context of this tutorial we can just skip ahead!\n\n### Step 3\nNow that we have our route setup, all we need to do is implement the `NetswiftRequest` protocol. Let us do just that in another extension:\n```swift\nextension MyAPI: NetswiftRequest {\n}\n```\n\nThis time, we don't want to let the compiler add protocol stubs for us just yet. Before we do that, let me explain what other information we need to provide to `Netswift`;\n- A `Response` type. Since Netswift is generic, it doesn't know what kind of data we want from our API's endpoint. If our request defines a type called `Response`, we're good to go. And the best part is, we could also use a `typealias`, and it would just work 👍\n\nSo for now, let's just add an internal type named `Response` in our extension:\n```swift\nstruct Response: Decodable {\n  let title: String\n}\n```\n\nAgain, what did we just write? \n\nWell, first of all, we define a type that mimics our endpoint's response structure. That is, an object that contains a member named `title`, which is of type `String`.\n\nThen, we told the compiler that our `Response` type implements the `Decodable` protocol. `Netswift`,  uses Swift's generic `JSONDecoder`. This is all done behind the scenes by default implementations. \n\nYet, the compiler is still unhappy. Now's however a good time to let it 'Add protocol stubs'. We're now given a new function called `serialise`. This is the last part we need to define before we are good to go.\n\nSo let us implement our `URLRequest` serialisation then, shall we ?\n```swift\nfunc serialise(_ handler: @escaping NetswiftHandler\u003cURLRequest\u003e) {\n  handler(.success(URLRequest(url: self.url)))\n}\n```\n\nAlright what's all that, now ? Well, the `serialise` function lets `Netswift` get a useable `URLRequest` that it can send out. Since our implementation is so basic, though, all we need to do is instantiate a `URLRequest` with a given `URL`. But wait. Where's `self.url` coming from ?\n\nThis convenience computed variable comes from the `NetswiftRoute` protocol. All it does is to simply format all the URLComponents you've defined into a `String`, which it then uses to instantiate \u0026 return a `URL` object. \n\nAgain, a lot of default implementation there, but all you need to know is that, for our current `.helloWorld` case, `self.url` will be using `\u003cscheme\u003e\u003chost\u003e/\u003cpath\u003e\u003cquery\u003e`.\n\nGreat, that's us pretty much done now!\n\n### Step 4\nNow's the moment we've been waiting for: sending out our request!\n\nAll we need to do is to actually perform our request. To do so, we can use an instance of the default `Netswift` class. All we need to do is call this:\n```swift\nNetswift().perform(MyAPI.helloWorld) { result in\n  switch result {\n  case .failure(let error):\n    // Our request failed: we can use the error to debug it\n    print(error)\n    \n  case .success(let value):\n    // Our request succeeded: we now have an object of type MyAPI.Response available to use\n    print(value.title)\n  }\n}\n```\n\nAnd that's our first request done with `Netswift`! From here, you can take it further and start defining more complex requests. I'd also suggest reading up the documentation and overriding default implementations to see what this library can really achieve 👌\n\n## Example Project\n\nTo run the example project, clone the repo, and run `pod install` from the Example directory first. It contains the full implementation of the tutorial above, along a few other examples.\n\n## Installation\n\nNetswift is available through:\n- [CocoaPods](https://cocoapods.org): To install it, simply add the following line to your Podfile\n```ruby\npod 'Netswift'\n```\n- [Swift Package Manager](https://github.com/MrSkwiggs/Netswift): To install it, simply search for it through XCode's integrated package navigator\n\n## Author\n\n[Dorian Grolaux](mailto:dorian@skwiggs.dev?subject=Netswift%20-%20Cocoapods%3A%20), https://skwiggs.dev\n\n## License\n\nNetswift is available under the MIT license. See the LICENSE file for more info.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrskwiggs%2Fnetswift","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmrskwiggs%2Fnetswift","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrskwiggs%2Fnetswift/lists"}