A type-safe, high-level networking solution for Swift apps

Overview

Netswift Header

Build Status Version License Platform Swift Package Manager

What

Type-safe network calls made easy

Netswift offers an easy way to perform network calls in a structured and type-safe way.

Why

Networking in Swift can be tedious from the get go. Type safety & 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.

Using Netswift

TL;DR?

This is how easy it is to perform network calls with Netswift:

Netswift().peform(StripeAPI.Charges.get(byID: "1234")) { result in
  switch result {
  case .failure(let error):
    // Our request failed: we can use the error to debug it
    print(error)
    
  case .success(let charge):
    // Our request succeeded: we now have a Charge object from the Stripe API
    print(charge.amount)
  }
}

Prerequisites

I'm assuming you have an available iOS project set up with this cocoapod, ready to go. If not, please follow the installation steps.

Writing our first request

As all reputable tutorials, the following steps will help you set up our first Hello World request.

What we'll do

  • Step 1: Define a container which will act as the base of implementation for our API.
  • Step 2: Implement NetswiftRoute, which defines the different URLComponents of our endpoints.
  • Step 3: Implement NetswiftRequest, which defines how your container can be turned into a URLRequest
  • Step 4: Passing it all to the generic Netswift class and performing your first request 🙌
  • Step 5: ????
  • Step 6: Profit 👍

Endpoint

To 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

Step 1

In 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.

So 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:

import Netswift

enum MyAPI {
  case helloWorld
}

And that's pretty much it. Now, since our API only has one endpoint, there's really nothing more to this. The 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 & structured. Neat 👌

Step 2

So we have our enum. Great. But it doesn't do much. Let's fix that.

Go ahead and define an extension for it which implements the NetswiftRoute protocol:

extension MyAPI: NetswiftRoute {
}

Immediately, the compiler starts complaining. Pressing 'Add protocol stubs' will make it happy again. This will add two variables:

  • host: This defines the domain of our API, usually something like www.example.com.
  • path: A specific resource on our API. Unless you're just GET-ing a website, you'll need to define a path.

So let's go ahead and implement those two.

var host: String {
  return "my-json-server.typicode.com"
}

var path: String? {
  switch self {
    case .helloWorld: return "MrSkwiggs/Netswift-HelloWorld/Netswift"
  }
}

What did we just do ?

Our 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.

For 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 👍

And 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!

Step 3

Now that we have our route setup, all we need to do is implement the NetswiftRequest protocol. Let us do just that in another extension:

extension MyAPI: NetswiftRequest {
}

This 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;

  • 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 👍

So for now, let's just add an internal type named Response in our extension:

struct Response: Decodable {
  let title: String
}

Again, what did we just write?

Well, 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.

Then, 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.

Yet, 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.

So let us implement our URLRequest serialisation then, shall we ?

func serialise(_ handler: @escaping NetswiftHandler<URLRequest>) {
  handler(.success(URLRequest(url: self.url)))
}

Alright 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 ?

This 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 & return a URL object.

Again, a lot of default implementation there, but all you need to know is that, for our current .helloWorld case, self.url will be using <scheme><host>/<path><query>.

Great, that's us pretty much done now!

Step 4

Now's the moment we've been waiting for: sending out our request!

All 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:

Netswift().perform(MyAPI.helloWorld) { result in
  switch result {
  case .failure(let error):
    // Our request failed: we can use the error to debug it
    print(error)
    
  case .success(let value):
    // Our request succeeded: we now have an object of type MyAPI.Response available to use
    print(value.title)
  }
}

And 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 👌

Example Project

To 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.

Installation

Netswift is available through:

  • CocoaPods: To install it, simply add the following line to your Podfile
pod 'Netswift'
  • Swift Package Manager: To install it, simply search for it through XCode's integrated package navigator

Author

Dorian Grolaux, https://skwiggs.dev

License

Netswift is available under the MIT license. See the LICENSE file for more info.

Comments
  • 🚀 Release v0.6.0 - Async/Await support

    🚀 Release v0.6.0 - Async/Await support

    What's Changed

    • Feature/async await support by @Deco354 in https://github.com/MrSkwiggs/Netswift/pull/34
    • 💥 Add requirement for requests with deadlines (time-out) by @MrSkwiggs in https://github.com/MrSkwiggs/Netswift/pull/35

    Full Changelog: https://github.com/MrSkwiggs/Netswift/compare/0.5.1...0.6.0

    opened by MrSkwiggs 0
  • 💥 Add requirement for requests with deadlines (time-out)

    💥 Add requirement for requests with deadlines (time-out)

    NetswiftRequestPerformable now has an additional requirement so that they can be performed with time-out of your choice.

    Additionally, some further changes were done:

    Added

    • NetswiftHTTPMethod.head, a convenience accessor for HEAD http methods.
    • NetswiftRequest.curl, a convenience cURL string generator for any request.

    Changed

    • Made variables & constructor under NetswiftHTTPResponse public.
    opened by MrSkwiggs 0
  • 🚀 Release: v0.3.0

    🚀 Release: v0.3.0

    [0.3.0 (20200225)]

    Changed

    • NetswiftError has been refactored to always keep track of a network task's response payload, if any is available.
    • NetswiftRequest are now given a chance to intercept and handle a NetswiftError when performed.

    Fixed

    • Access control levels for NetswiftHTTPPerformer and NetswiftPerformer have been set to open to allow for overriding and extending.
    opened by MrSkwiggs 0
  • Netswift error refactor

    Netswift error refactor

    This refactor turns NetswiftError into a struct, rather than an enum. The main benefit of this change is that it allows to always have a reference to the original network payload data.

    Which brings us to the second benefit: NetswiftRequest now has an additional handling step which lets it intercept any NetswiftError and potentially handle them and still return a valid Response.

    This is handy if you use the generic NetswiftNetworkPerformer (Netswift) and your endpoint uses HTTP status codes for its business logic. When that happened, none of the NetswiftRequest's handling step would ever be called.

    opened by MrSkwiggs 0
  • 🚀 Release v0.2.1

    🚀 Release v0.2.1

    [0.2.1 (20200209)]

    Added

    • New Changelog file to keep track of updates!
    • JPEG Mime Type
    • NetswiftError now conforms to Equatable

    Changed

    • Updated Readme to remove some deprecated stuff
    • Renamed MimeType.plainText to MimeType.text

    Fixed

    • Access control for several classes has been made public
    • Fixed a typo for the .mailto Generic Scheme's rawValue
    • Added missing headers in default implementation of NetswiftRequest.serialise()
    opened by MrSkwiggs 0
Releases(0.6.0)
  • 0.6.0(Dec 13, 2021)

    What's Changed

    • Feature/async await support by @Deco354 in https://github.com/MrSkwiggs/Netswift/pull/34
    • Add requirement for requests with deadlines (time-out) by @MrSkwiggs in https://github.com/MrSkwiggs/Netswift/pull/35
    • [BREAKING] NetswiftRequestPerformable now has an additional requirement so that they can be performed with a time-out.
    • NetswiftHTTPMethod.head, a convenience accessor for HEAD http methods.
    • NetswiftRequest.curl, a convenience cURL string generator for any request.

    Full Changelog: https://github.com/MrSkwiggs/Netswift/compare/0.5.1...0.6.0

    Source code(tar.gz)
    Source code(zip)
  • 0.5.1(Aug 20, 2021)

  • 0.5.0(Aug 20, 2021)

    [0.5.0 (20210820)]

    Added

    • New NetswiftEncoder wrapper protocol for types such as JSONEncoder or PropertyListEncoder (those 2 are already made to conform to NetswiftEncoder)

    Changed

    • NetswiftRequest now has new requirements:
      • A bodyEncoder: NetswiftEncoder? var, which can be used to encode any data into the request's httpBody;
      • A body(encodedBy encoder: NetswiftEncoder?) -> Data? function that uses the given encoder to return Data?, if applicable.
    Source code(tar.gz)
    Source code(zip)
  • 0.4.0(Jun 29, 2021)

  • 0.3.1(Sep 3, 2020)

  • 0.3.0(Feb 25, 2020)

    [0.3.0 (20200225)]

    Changed

    • NetswiftError has been refactored to always keep track of a network task's response payload, if any is available.
    • NetswiftRequest are now given a chance to intercept and handle a NetswiftError when performed.

    Fixed

    • Access control levels for NetswiftHTTPPerformer and NetswiftPerformer have been set to open to allow for overriding and extending.
    Source code(tar.gz)
    Source code(zip)
  • 0.2.1(Feb 9, 2020)

    [0.2.1 (20200209)]

    Added

    • New Changelog file to keep track of updates!
    • JPEG Mime Type
    • NetswiftError now conforms to Equatable

    Changed

    • Updated Readme to remove some deprecated stuff
    • Renamed MimeType.plainText to MimeType.text

    Fixed

    • Access control for several classes has been made public
    • Fixed a typo for the .mailto Generic Scheme's rawValue
    • Added missing headers in default implementation of NetswiftRequest.serialise()
    Source code(tar.gz)
    Source code(zip)
  • 0.1.7(Jan 17, 2020)

    This update brings sensible deployment targets requirements for Netswift, as iOS 13.3 was unnecessarily restrictive.

    I've also fixed some of the examples which did not work as expected anymore.

    Source code(tar.gz)
    Source code(zip)
  • 0.1.6(Jan 16, 2020)

  • 0.1.5(Jan 15, 2020)

  • 0.1.4(Jan 15, 2020)

    This update re-enables specifying Content-Type & Accept headers on request level.

    This replaces specifying them as generic headers. Those have now been renamed to additionalHeaders

    Source code(tar.gz)
    Source code(zip)
  • 0.1.3(Jan 15, 2020)

  • 0.1.2(Jan 15, 2020)

  • 0.1.1(Jan 15, 2020)

  • 0.1.0(Jan 8, 2020)

  • 0.0.3(May 12, 2019)

  • 0.0.2(May 12, 2019)

  • 0.0.1(May 11, 2019)

Owner
Dorian Grolaux
iOS Engineer working at @appannie
Dorian Grolaux
YTKNetwork is a high level request util based on AFNetworking.

YTKNetwork What YTKNetwork is a high level request util based on AFNetworking. It's developed by the iOS Team of YuanTiKu. It provides a High Level AP

猿辅导技术团队 6.5k Jan 6, 2023
A phantom type is a custom type that has one or more unused type parameters.

PhantomTypes A phantom type is a custom type that has one or more unused type parameters. Phantom types allow you to enforce type-safety without sacri

null 3 Nov 4, 2022
🌏 A zero-dependency networking solution for building modern and secure iOS, watchOS, macOS and tvOS applications.

A zero-dependency networking solution for building modern and secure iOS, watchOS, macOS and tvOS applications. ?? TermiNetwork was tested in a produc

Bill Panagiotopoulos 90 Dec 17, 2022
Swift-multipart-formdata - MultipartFormData: Build multipart/form-data type-safe in Swift

MultipartFormData Build multipart/form-data type-safe in Swift. A result builder

Felix Herrmann 21 Dec 29, 2022
A type-safe packet processor framework in Swift

PacketProcessor The Swift PacketProcessor provides a simple, type-safe way of handling structured packets given a data stream. PacketProcessor handles

Danny Sung 12 Oct 9, 2022
Postie - The Next-Level HTTP API Client using Combine

Postie - The Next-Level HTTP API Client using Combine Postie is a pure Swift library for building URLRequests using property wrappers.

kula 28 Jul 23, 2022
OctopusKit is a simplicity but graceful solution for invoke RESTful web service APIs

OctopusKit OctopusKit is a simplicity but graceful solution for invoke RESTful web service APIs,it can help coder develop app based MVC pattern, it ca

i ⚒  kit 3 Jul 29, 2021
High Performance (nearly)100% Swift Web server supporting dynamic content.

Dynamo - Dynamic Swift Web Server Starting this project the intention was to code the simplest possible Web Server entirely in Swift. Unfortunately I

John Holdsworth 68 Jul 25, 2022
Elegant HTTP Networking in Swift

Alamofire is an HTTP networking library written in Swift. Features Component Libraries Requirements Migration Guides Communication Installation Usage

Alamofire 38.7k Jan 8, 2023
Robust Swift networking for web APIs

Conduit Conduit is a session-based Swift HTTP networking and auth library. Within each session, requests are sent through a serial pipeline before bei

Mindbody 52 Oct 26, 2022
Versatile HTTP Networking in Swift

Net is a versatile HTTP networking library written in Swift. ?? Features URL / JSON / Property List Parameter Encoding Upload File / Data / Stream / M

Intelygenz 124 Dec 6, 2022
🏇 A Swift HTTP / HTTPS networking library just incidentally execute on machines

Thus, programs must be written for people to read, and only incidentally for machines to execute. Harold Abelson, "Structure and Interpretation of Com

John Lui 845 Oct 30, 2022
A Swift Multiplatform Single-threaded Non-blocking Web and Networking Framework

Serverside non-blocking IO in Swift Ask questions in our Slack channel! Lightning (formerly Edge) Node Lightning is an HTTP Server and TCP Client/Serv

SkyLab 316 Oct 6, 2022
Simple asynchronous HTTP networking class for Swift

YYHRequest YYHRequest is a simple and lightweight class for loading asynchronous HTTP requests in Swift. Built on NSURLConnection and NSOperationQueue

yayuhh 77 May 18, 2022
RSNetworking is a networking library written entirly for the Swift programming language.

RSNetworking is a networking library written entirly for the Swift programming language.

null 18 Feb 25, 2018
ServiceData is an HTTP networking library written in Swift which can download different types of data.

ServiceData Package Description : ServiceData is an HTTP networking library written in Swift which can download different types of data. Features List

Mubarak Alseif 0 Nov 11, 2021
Easy HTTP Networking in Swift a NSURLSession wrapper with image caching support

Networking was born out of the necessity of having a simple networking library that doesn't have crazy programming abstractions or uses the latest rea

Nes 1.3k Dec 17, 2022
A networking library for Swift

Nikka Nikka is a super simple Swift HTTP networking library that comes with many extensions to make it modular and really powerful. Installation Usage

Emilien Stremsdoerfer 29 Nov 4, 2022
Declarative and Reactive Networking for Swift.

Squid Squid is a declarative and reactive networking library for Swift. Developed for Swift 5, it aims to make use of the latest language features. Th

Oliver Borchert 69 Dec 18, 2022