Versatile HTTP Networking in Swift

Overview

Twitter Version License Platform Swift Carthage compatible Swift Package Manager Compatible Build Status Help Contribute to Open Source

Net is a versatile HTTP networking library written in Swift.

๐ŸŒŸ Features

  • URL / JSON / Property List Parameter Encoding
  • Upload File / Data / Stream / Multipart Form Data
  • Download File using Request or Resume Data
  • Authentication with URLCredential
  • Basic, Bearer and Custom Authorization Handling
  • Default and Custom Cache Controls
  • Default and Custom Content Types
  • Upload and Download Progress Closures with Progress (only iOS >= 11)
  • cURL Command Debug Output
  • Request and Response Interceptors
  • Asynchronous and synchronous task execution
  • Inference of response object type
  • Network reachability
  • TLS Certificate and Public Key Pinning
  • Retry requests
  • Codable / Decodable / Encodable protocols compatible (JSON / Property List)
  • Customizable acceptable status codes range
  • watchOS Compatible
  • tvOS Compatible
  • macOS Compatible
  • Alamofire Implementation
  • MoyaProvider Extension
  • Kommander Extension
  • RxSwift Extension
  • Stub Implementation

๐Ÿ“‹ Requirements

  • iOS 8.0+ / macOS 10.9+ / tvOS 9.0+ / watchOS 2.0+
  • Xcode 9.0+
  • Swift 4.0+

๐Ÿ“ฒ Installation

Net is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod 'NetClient'

For Swift 3 compatibility use:

pod 'NetClient', '~> 0.2'

Or you can install it with Carthage:

github "intelygenz/NetClient-iOS"

Or install it with Swift Package Manager:

dependencies: [
    .package(url: "https://github.com/intelygenz/NetClient-iOS.git")
]

๐Ÿ’ Usage

Build a NetRequest

import Net

do {
    let request = try NetRequest.builder("YOUR_URL")!
                .setAccept(.json)
                .setCache(.reloadIgnoringLocalCacheData)
                .setMethod(.PATCH)
                .setTimeout(20)
                .setJSONBody(["foo", "bar"])
                .setContentType(.json)
                .setServiceType(.background)
                .setCacheControls([.maxAge(500)])
                .setURLParameters(["foo": "bar"])
                .setAcceptEncodings([.gzip, .deflate])
                .setContentEncodings([.gzip])
                .setBasicAuthorization(user: "user", password: "password")
                .setHeaders(["foo": "bar"])
                .build()
} catch {
    print("Request error: \(error)")
}

Request asynchronously

import Net

let net = NetURLSession()

net.data(URL(string: "YOUR_URL")!).async { (response, error) in
    do {
        if let object: [AnyHashable: Any] = try response?.object() {
            print("Response dictionary: \(object)")
        } else if let error = error {
            print("Net error: \(error)")
        }
    } catch {
        print("Parse error: \(error)")
    }
}

Request synchronously

import Net

let net = NetURLSession()

do {
    let object: [AnyHashable: Any] = try net.data("YOUR_URL").sync().object()
    print("Response dictionary: \(object)")
} catch {
    print("Error: \(error)")
}

Request from cache

import Net

let net = NetURLSession()

do {
    let object: [AnyHashable: Any] = try net.data("YOUR_URL").cached().object()
    print("Response dictionary: \(object)")
} catch {
    print("Error: \(error)")
}

Track progress

import Net

let net = NetURLSession()

do {
    let task = try net.data("YOUR_URL").progress({ progress in
        print(progress)
    }).sync()
} catch {
    print("Error: \(error)")
}

Add interceptors for all requests

import Net

let net = NetURLSession()

net.addRequestInterceptor { request in
    request.addHeader("foo", value: "bar")
    request.setBearerAuthorization(token: "token")
    return request
}

Retry requests

import Net

let net = NetURLSession()

net.retryClosure = { response, _, _ in response?.statusCode == XXX }

do {
    let task = try net.data("YOUR_URL").retry({ response, error, retryCount in
        return retryCount < 2
    }).sync()
} catch {
    print("Error: \(error)")
}

๐Ÿง™โ€โ™‚๏ธ Codable

Encodable

import Net

let request = NetRequest.builder("YOUR_URL")!
            .setJSONObject(Encodable())
            .build()

Decodable

import Net

let net = NetURLSession()

do {
    let object: Decodable = try net.data("YOUR_URL").sync().decode()
    print("Response object: \(object)")
} catch {
    print("Error: \(error)")
}

๐Ÿค Integrations

Love Alamofire?

pod 'NetClient/Alamofire'
import Net

let net = NetAlamofire()

...

Love Moya?

pod 'NetClient/Moya'
import Net
import Moya

let request = NetRequest("YOUR_URL")!
let provider = MoyaProvider<NetRequest>()
provider.request(request) { result in
    switch result {
    case let .success(response):
        print("Response: \(response)")
    case let .failure(error):
        print("Error: \(error)")
    }
}

Love Kommander?

pod 'NetClient/Kommander'
import Net
import Kommander

let net = NetURLSession()
let kommander = Kommander.default

net.data(URL(string: "YOUR_URL")!).execute(by: kommander, onSuccess: { object in
    print("Response dictionary: \(object as [AnyHashable: Any])")
}) { error in
    print("Error: \(String(describing: error?.localizedDescription))")
}

net.data(URL(string: "YOUR_URL")!).executeDecoding(by: kommander, onSuccess: { object in
	print("Response object: \(object as Decodable)")
}) { error in
    print("Error: \(String(describing: error?.localizedDescription))")
}

Love RxSwift?

pod 'NetClient/RxSwift'
import Net
import RxSwift

let request = NetRequest("YOUR_URL")!
_ = net.data(request).rx.response().observeOn(MainScheduler.instance).subscribe { print($0) }

Stub Implementation

pod 'NetClient/Stub'
import Net

let net = NetStub()

net.asyncBehavior = .delayed(.main, .seconds(10)) // If you want to delay the response.

net.nextResult = .response(NetResponse.builder()....build())

// Your test request here

net.nextResult = .error(.net(code: 500, message: "Your network error.", headers: ..., object: ..., underlying: ...))

// Your test request here

โค๏ธ Etc.

  • Contributions are very welcome.
  • Attribution is appreciated (let's spread the word!), but not mandatory.

๐Ÿ‘จโ€๐Ÿ’ป Authors

alexruperez, [email protected]

๐Ÿ‘ฎโ€โ™‚๏ธ License

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

Comments
  • Added NetStub with nextResult property.

    Added NetStub with nextResult property.

    Goals โšฝ

    Testing.

    Implementation Details ๐Ÿšง

    NetStub class conforming Net protocol and NetTaskStub NetTask subclass. Some open functions have changed to public.

    Testing Details ๐Ÿ”

    Just set nextResponse property of NetStub instance to desired test result.


    This change isโ€‚Reviewable

    enhancement question 
    opened by alexruperez 7
  • New removable interceptors API.

    New removable interceptors API.

    Issue Link :link:

    https://github.com/intelygenz/NetClient-iOS/pull/11

    Goals :soccer:

    Resolve @juantrias issues on https://github.com/intelygenz/NetClient-iOS/pull/11:


    Core/NetTask.swift, line 215 at r1 (raw file):

    Previously, RobertoEstrada (Roberto Estrada) wroteโ€ฆ

    Actually, reading the style guide, it does not rule nor rule out this edge case so we're in quite an alegal situation. For the moment I'm going to consider this OK but i'm going to propose an exception for cases like this in the style guide.

    I agree with @RobertoEstrada. In this case I see no real benefit on declaring protocol conformance in extensions, since this extensions need to be empty because of the problem with open members declared inside extensions https://gitlab.intelygenz.com/daniel.coello/igz-swift-styleguide/issues/4. Maybe we can put // MARK: comments to separate the implementation of the different protocols


    Stub/NetStub.swift, line 18 at r1 (raw file):

        open static var shared: Net = NetStub()
    
        open var requestInterceptors = [RequestInterceptor]()
    

    Could be requestInterceptors and responseInterceptors private? I understand that nextResult needs to be public because it's the way to mock a response


    Stub/NetStub.swift, line 42 at r1 (raw file):

            if let builder = requestBuilder {
                requestInterceptors.forEach({ interceptor in
                    requestBuilder = interceptor(builder)
    

    It seems like you are passing the same builder object to each interceptor in the chain, so you are overwriting the requestBuilder in each iteration ignoring the result of the previous interceptor


    Stub/NetStub.swift, line 46 at r1 (raw file):

            }
            guard let nextResult = nextResult else {
                return NetTaskStub(request: requestBuilder?.build())
    

    NetTaskStub.request should be optional? Can we have a NetTask without a request? The request parameter of stub() should be optional?


    Stub/NetTaskStub.swift, line 10 at r2 (raw file):

    import Foundation
    
    class NetTaskStub: NetTask {
    

    Could be NetTaskStub a protocol implementation instead of a NetTask subclass? I generally prefer implement protocols over inheritance for mocks, to clearly separate the mock from the production code and do not end calling by accident production code in the tests. Maybe in this case we need to reuse much of the NetTask code for the Stub and it is OK to inherit, or to place the common code in a NetTask protocol extension


    Stub/NetTaskStub.swift, line 15 at r2 (raw file):

            completionClosure = completion
            progressClosure?(Progress(totalUnitCount: 0))
            completion?(response, error)
    

    If we do not stub response or error we will call completion block with both params nil. Should we return a "Next result not specified." error like in sync()?


    URLSession/NetURLSession.swift, line 11 at r2 (raw file):

    import Foundation
    
    open class NetURLSession: Net {
    

    Should be open instead of public? Why a client would need to override instead of extend NetURLSession? Same for NetAlamofire and the rest of adapters


    Implementation Details ๐Ÿšง

    New removable interceptors API with unique tokens.


    This change isโ€‚Reviewable

    enhancement 
    opened by alexruperez 5
  • Release 0.4.1 with RxSwift extension. Resolves #2

    Release 0.4.1 with RxSwift extension. Resolves #2

    Issue Link :link:

    https://github.com/intelygenz/NetClient-iOS/issues/2

    Goals :soccer:

    Create a RxSwift extension for NetClient

    Implementation Details ๐Ÿšง

    NetTask rx extension


    This change isโ€‚Reviewable

    enhancement 
    opened by alexruperez 3
  • Release 0.4.0 URLSessionConfiguration builder

    Release 0.4.0 URLSessionConfiguration builder

    Issue Link :link:

    https://github.com/intelygenz/NetClient-iOS/issues/5

    Goals :soccer:

    Create a builder class for URLSessionConfiguration as NetRequest and NetResponse have.

    Implementation Details ๐Ÿšง

    URLSessionConfiguration extension with a builder class.

    Testing Details ๐Ÿ”

    Added NetMultipathServiceType tests.


    This change isโ€‚Reviewable

    enhancement help wanted 
    opened by alexruperez 3
  • [ci skip] Get more Open Source Helpers

    [ci skip] Get more Open Source Helpers

    CodeTriage is an app I have maintained for the past 4-5 years with the goal of getting people involved in Open Source projects like this one. The app sends subscribers a random open issue for them to help "triage". For some languages you can also suggested areas to add documentation.

    The initial approach was inspired by seeing the work of the small core team spending countless hours asking "what version was this in" and "can you give us an example app". The idea is to outsource these small interactions to a huge team of volunteers and let the core team focus on their work.

    I want to add a badge to the README of this project. The idea is to provide an easy link for people to get started contributing to this project. A badge indicates the number of people currently subscribed to help the repo. The color is based off of open issues in the project.

    Here are some examples of other projects that have a badge in their README:

    • https://github.com/crystal-lang/crystal
    • https://github.com/rails/rails
    • https://github.com/codetriage/codetriage

    Thanks for building open source software, I would love to help you find some helpers.


    This change isโ€‚Reviewable

    help wanted question 
    opened by schneems 0
  • RxNetClient

    RxNetClient

    opened by alexruperez 0
  • Package Resolution Failed:

    Package Resolution Failed: "NetClient-iOS" could not be resolved

    When adding the package Xcode 12.2 shows an error "Package Resolution Failed NetClient-iOS could not be resolved:"

    • Add Package: Resolving package dependencies because every version of NetClient-iOS contains incompatible tools version and root depends on NetClient-iOS 0.5.0..<1.0.0, version solving failed.
    • Failed to resolve dependencies

    Capture dโ€™รฉcran 2020-11-25 ร  14 10 20

    opened by Adobels 0
Releases(0.5.0)
Owner
Intelygenz
In Code We Trust - We deliver groundbreaking software solutions and applied AI that propel business growth.
Intelygenz
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
๐Ÿ‡ 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
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
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
Extensible HTTP Networking for iOS

Bridge Simple Typed JSON HTTP Networking in Swift 4.0 GET GET<Dict>("http://httpbin.org/ip").execute(success: { (response) in let ip: Dict = respo

null 90 Nov 19, 2022
QwikHttp is a robust, yet lightweight and simple to use HTTP networking library for iOS, tvOS and watchOS

QwikHttp is a robust, yet lightweight and simple to use HTTP networking library. It allows you to customize every aspect of your http requests within a single line of code, using a Builder style syntax to keep your code super clean.

Logan Sease 2 Mar 20, 2022
๐Ÿคต๐Ÿฝโ€โ™€๏ธ Janet โ€” A thin HTTP networking layer built on URLSession for simple, declarative endpoint specification leveraging the power of async/await.

????โ€โ™€๏ธ Janet โ€” Just another networking kit โ€” A thin HTTP networking layer built on URLSession for simple, declarative endpoint specification leveragi

Niklas Holloh 3 Sep 6, 2022
Http - Demo for Http Layer

http Example To run the example project, clone the repo, and run pod install fro

null 0 Jan 24, 2022
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
A type-safe, high-level networking solution for Swift apps

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

Dorian Grolaux 23 Apr 27, 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
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
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
AsyncHTTP - Generic networking library written using Swift async/await

Generic networking library written using Swift async/await

Laszlo Teveli 7 Aug 3, 2022
A lightweight generic networking API written purely in Swift

SwiftyNetworking SwiftyNetworking library is a generic networking library writte

Zaid Rahhawi 0 Dec 24, 2021
Swift implementation of libp2p, a modular & extensible networking stack

Swift LibP2P The Swift implementation of the libp2p networking stack Table of Contents Overview Disclaimer Install Usage Example API Contributing Cred

null 19 Dec 18, 2022
Type-safe networking abstraction layer that associates request type with response type.

APIKit APIKit is a type-safe networking abstraction layer that associates request type with response type. // SearchRepositoriesRequest conforms to Re

Yosuke Ishikawa 1.9k Dec 30, 2022