A networking library for iOS, macOS, watchOS and tvOS

Overview

Thunder Request

Build Status Carthage Compatible Swift 5.3.2 Apache 2

Thunder Request is a Framework used to simplify making http and https web requests.

Installation

Setting up your app to use ThunderBasics is a simple and quick process. You can choose between a manual installation, or use Carthage.

Carthage

  • Add github "3sidedcube/ThunderRequest" == 2.3.1 to your Cartfile.
  • Run carthage update --platform ios to fetch the framework.
  • Drag ThunderRequest into your project's Linked Frameworks and Libraries section from the Carthage/Build folder.
  • Add the Build Phases script step as defined here.

Manual

  • Clone as a submodule, or download this repo
  • Import ThunderRequest.xcproject into your project
  • Add ThunderRequest.framework to your Embedded Binaries.
  • Wherever you want to use ThunderBasics use import ThunderRequest if you're using swift.

Authentication Support

Support for authentication protocols such as OAuth2 is available via the Authenticator protocol which when set on RequestController will have it's delegate methods called to refresh the user's token when it either expires or a 403 is sent by the server.

When authenticator is set on RequestController any current credentials will be pulled from the user's keychain by the service identifier provided by authIdentifier on the protocol object.

To register a credential for the first time to the user's keychain, use the method set(sharedRequestCredentials:savingToKeychain:) after having set the delegate. This will store the credential to the keychain for later use by the request controller and also set the sharedRequestCredential property on the request controller.

If the request controller detects that the RequestCredential object is expired, or receives a 403 on a request it will call the method reAuthenticate(credential:completion:) to re-authenticate the user before then continuing to make the request (Or re-making) the request.

Examples

All of the examples shown below are shown with all optional parameters excluded, for example the request, download and upload functions have multiple parameters (For things such as header overrides and base url overrides) as outlined in the generated docs.

Initialization

guard let baseURL = URL(string: "https://httpbin.org/") else {
	fatalError("Unexpectedly failed to create URL")
}
let requestController = RequestController(baseURL: baseURL)

GET request

requestController.request("get", method: .GET) { (response, error) in
	// Do something with response
}

POST request

let body = [
	"name": "Thunder Request",
	"isAwesome": true
]
requestController.request("post", method: .POST, body: JSONRequestBody(body)) { (response, error) in
	// Do something with response
}

Request bodies

The body sent to the request function must conform to the RequestBody protocol. There are multiple extensions and structs built into the project that conform to this protocol for ease of use.

JSONRequestBody

Formats the request as JSON, and sets the request's Content-Type header to application/json.

let bodyJSON = [
    "name": "Thunder Request",
    "isAwesome": true
]
let body = JSONRequestBody(bodyJSON)

PropertyListRequestBody

Similar to JSONRequestBody but uses the "text/x-xml-plist" or "application/x-plist" Content-Type.

let bodyPlist = [
    "name": "Thunder Request",
    "isAwesome": true
]
let body = PropertyListRequestBody(bodyPlist, format: .xml)

MultipartFormRequestBody

Formats a dictionary of objects conforming to MultipartFormElement to the data required for the multipart/form-data; boundary= Content-Type.

let multipartElements = [
    "name": "Thunder Request",
    "avatar": MultipartFormFile(
    	image: image, 
    	format: .png, 
    	fileName: "image.png", 
    	name: "image"
    )!
]
let body = MultipartFormRequestBody(
	parts: multipartElements, 
	boundary: "----SomeBoundary"
)

FormURLEncodedRequestBody

Similar to JSONRequestBody except uses the "application/x-www-form-urlencoded" Content-Type and formats the payload to be correct for this type of request.

let bodyJSON = [
    "name": "Thunder Request",
    "isAwesome": true
]
let body = FormURLEncodedRequestBody(bodyJSON)

ImageRequestBody

Converts a UIImage to a request payload data and Content-Type based on the provided format.

let imageBody = ImageRequestBody(image: image, format: .png)

EncodableRequestBody

Converts an object which conforms to the Encodable (Or Codable) protocol to either JSON or Plist based on the format provided upon initialisation (Defaults to JSON).

let someEncodableObject: CodableStruct = CodableStruct(
	name: "Thunder Request", 
	isAwesome: true
)
let body = EncodableRequestBody(someEncodableObject)

Request Response

The request response callback sends both an Error? object and a RequestResponse? object. RequestResponse has helper methods for converting the response to various Swift types:

Decodable

If your object conforms to the Decodable (Or Codable) is can be decoded directly for you:

let codableArray: [CodableStruct]? = response.decoded()
let codableObject: CodableStruct? = response.decoded()

Dictionary

let dictionaryResponse = response.dictionary

Array

let arrayResponse = response.array

String

let stringResponse = response.string
let utf16Response = response.string(encoding: .utf16)

The RequestResponse object also includes the HTTP status as an enum, the raw Data from the request response, the original response (For when a request was re-directed), and the request headers (headers)

Downloading

Downloading from a url is as simple as making any a request using any other HTTP method

let requestBaseURL = URL(string: "https://via.placeholder.com/")!        
let requestController = RequestController(baseURL: requestBaseURL)
requestController.download("500", progress: nil) { (response, url, error) in
	// Do something with the filePath that the file was downloaded to
}

Uploading

Uploading is just as simple, and can be done using any of the RequestBody types listed above, as well as via a raw Data instance or from a file URL

requestController.uploadFile(fileURL, to: "post", progress: { (progress, totalBytes, uploadedBytes) in
    // Do something with progress
}) { (response, _, error) in
    // Do something with response/error
} 

Building Binaries for Carthage

Since Xcode 12 there has been issues with building Carthage binaries caused by the inclusion of a secondary arm64 slice in the generated binary needed for Apple Silicon on macOS. This means that rather than simply using carthage build --archive you need to use the ./carthage-build build --archive command which uses the script included with this repo. For more information, see the issue on Carthage's github here

We will be investigating moving over to use SPM as an agency soon, and will also look into migrating to use .xcframeworks as soon as Carthage have support for it.

Code level documentation

Documentation is available for the entire library in AppleDoc format. This is available in the framework itself or in the Hosted Version

License

See LICENSE.md

Comments
  • App Store Rejection

    App Store Rejection

    Your app uses or references the following non-public APIs:

    parentAnnotation, serviceIdentifier, setParentAnnotation:

    The use of non-public APIs is not permitted on the App Store because it can lead to a poor user experience should these APIs change.

    opened by MattCheetham 4
  • Custom threading

    Custom threading

    Request created on behalf of Simon to avoid orphaned branches.

    From what I can tell this moves the request controlled from using the main queue for callbacks to a custom queue.

    @simonmitchell can you explain the benefits of this?

    opened by MattCheetham 3
  • Fix/loading indicator

    Fix/loading indicator

    Makes the application loading indicator state more manageable across instances of TSCRequestController by creating a shared instance of a controller which manages a count of how many times it has been turned on/off

    opened by simonmitchell 3
  • Adds option to stop background download controller reading to disk

    Adds option to stop background download controller reading to disk

    Added this so we can (try and) avoid Background download daemon's 40mb memory limit!

    Description

    Added a property to background controller init method to stop it reading downloaded file to Data immediately.

    How Has This Been Tested?

    Has been tested with the implementation of background downloading storm delta bundles in ThunderCloud

    Types of changes

    • [ ] Bug fix (non-breaking change which fixes an issue)
    • [x] New feature (non-breaking change which adds functionality)
    • [ ] Breaking change (fix or feature that would cause existing functionality to change)

    Checklist:

    • [x] My code follows the code style of this project.
    • [x] My change requires a change to the documentation.
    • [x] I have updated the documentation accordingly.
    • [x] I have read the CONTRIBUTING document.
    • [ ] I have added tests to cover my changes.
    • [x] All new and existing tests passed.
    opened by simonmitchell 2
  • Make loading indicator available in status bar

    Make loading indicator available in status bar

    We used to have the loading indicator in the status bar spin whilst any requests were going on but we removed it when watchOS came out.

    We should add it back in and wrap it in an if statement and maybe even give it an info.plist option to enable/disable it.

    I think it's important and helps establish when things like delta publishes are finished.

    Interested on your thoughts @simonmitchell and @joeltrew

    enhancement 
    opened by MattCheetham 2
  • Release/v2.2.2

    Release/v2.2.2

    Post Notification when a URLError is returned in a URL task completion.

    Motivation and Context

    Useful for apps using this framework to respond to URLErrors

    Types of changes

    • [ ] Bug fix (non-breaking change which fixes an issue)
    • [x] New feature (non-breaking change which adds functionality)
    • [ ] Breaking change (fix or feature that would cause existing functionality to change)

    Checklist:

    • [x] My code follows the code style of this project.
    • [ ] My change requires a change to the documentation.
    • [ ] I have updated the documentation accordingly.
    • [x] I have read the CONTRIBUTING document.
    • [ ] I have added tests to cover my changes.
    • [ ] All new and existing tests passed.
    opened by BenShutt 1
  • #36 - ensured that ErrorRecoveryOption's properties can be accessed beyond the module.

    #36 - ensured that ErrorRecoveryOption's properties can be accessed beyond the module.

    Description

    ErrorRecoveryOption's properties are now marked as public, so they can be accessed outside of the module.

    Related Issue

    Resolves #36

    Motivation and Context

    One of our applications requires access to these.

    How Has This Been Tested?

    This has been tested within the context of the affected app.

    Screenshots (if appropriate):

    Types of changes

    • [x] Bug fix (non-breaking change which fixes an issue)
    • [ ] New feature (non-breaking change which adds functionality)
    • [ ] Breaking change (fix or feature that would cause existing functionality to change)

    Checklist:

    • [x] My code follows the code style of this project.
    • [ ] My change requires a change to the documentation.
    • [ ] I have updated the documentation accordingly.
    • [x] I have read the CONTRIBUTING document.
    • [ ] I have added tests to cover my changes.
    • [x] All new and existing tests passed.
    bug 
    opened by ryanbourneuk 1
  • get:withURLParamDictionary:contentType:completion: not found

    get:withURLParamDictionary:contentType:completion: not found

    Method definition 'get:withURLParamDictionary:contentType:completion:' not found

    Looks like the new contentType stuff that was merged resulted in the header being merged but the method implementation is missing.

    opened by MattCheetham 1
  • Content Types

    Content Types

    Creating this pull request on behalf of @simonmitchell. Previously discussed deleting but seems these changes are not in develop and are fairly minimal.

    Appears to just add some new types and a new method for making a request with a type. Happy to delete if it's not in use anywhere though or we don't want it.

    opened by MattCheetham 1
  • Fix `RequestCredential` issue resulting from insecure encoding/decoding

    Fix `RequestCredential` issue resulting from insecure encoding/decoding

    Description

    As RequestCredential conformed to NSCoding instead of NSSecureCoding unarchiving would log the following error:

    Error Domain=NSCocoaErrorDomain Code=4864 \"This decoder will only decode classes that adopt NSSecureCoding. Class \'TSCRequestCredential\' does not adopt it.\" UserInfo={NSDebugDescription=This decoder will only decode classes that adopt NSSecureCoding. Class \'TSCRequestCredential\' does not adopt it.}
    

    Moreover, when unarchiving, types should be declared as so:

    NSKeyedUnarchiver.unarchivedObject(
        ofClasses: [RequestCredential.self, NSString.self],
        from: keychainData
    ) as? RequestCredential
    

    otherwise, the following error will be logged

    [general] *** -[NSKeyedUnarchiver validateAllowedClass:forKey:] allowed unarchiving safe plist type ''NSString' (0x1da1637d0) [/System/Library/Frameworks/Foundation.framework]' for key 'password', even though it was not explicitly included in the client allowed classes set: '{(
        "'TSCRequestCredential' (0x102a856d8) [...]"
    )}'. This will be disallowed in the future.
    

    Related Issue

    https://3sidedcube.atlassian.net/browse/SP-771

    Motivation and Context

    Bug fix, breaking change from Apple around archiving/unarchiving.

    How Has This Been Tested?

    SAF (Hero Care)

    Screenshots (if appropriate):

    Not applicable

    Types of changes

    • [x] Bug fix (non-breaking change which fixes an issue)
    • [ ] New feature (non-breaking change which adds functionality)
    • [x] Breaking change (fix or feature that would cause existing functionality to change)

    Apps using the public interface here may still be able to use this change without any "breaking changes". But the credentials property of RequestCredential is now computed, and the archived/unarchived data will be different.

    Checklist:

    • [x] My code follows the code style of this project.
    • [ ] My change requires a change to the documentation.
    • [ ] I have updated the documentation accordingly.
    • [x] I have read the CONTRIBUTING document.
    • [ ] I have added tests to cover my changes.
    • [ ] All new and existing tests passed.
    opened by BenShutt 0
  • Release/v3.0.0

    Release/v3.0.0

    Warning

    Does not include the iOS 13 migration.

    Description

    • Bump version to v3.0.0
    • Make suggested Xcode 13 updates

    Breaking changes for iOS 12 and keychain.

    Motivation and Context

    OS Updates

    Types of changes

    • [ ] Bug fix (non-breaking change which fixes an issue)
    • [x] New feature (non-breaking change which adds functionality)
    • [x] Breaking change (fix or feature that would cause existing functionality to change)

    It is breaking in the sense that we have dropped pre-iOS12 support.

    Checklist:

    • [x] My code follows the code style of this project.
    • [x] My change requires a change to the documentation.
    • [x] I have updated the documentation accordingly.
    • [x] I have read the CONTRIBUTING document.
    • [ ] I have added tests to cover my changes.
    • [ ] All new and existing tests passed.
    opened by BenShutt 0
  • Write tests around `Request().construct()` method

    Write tests around `Request().construct()` method

    For some context, we recently discovered that if baseURL on Request was the exact url and included url parameters, they were removed by this method. Whilst this has been fixed, we should write test-cases around the construct method to make sure nothing like this happens in the future!

    enhancement 
    opened by simonmitchell 0
Releases(v2.3.1)
Owner
3 SIDED CUBE
We're an app development and digital product company that specialises in tech for good.
3 SIDED CUBE
A delightful networking framework for iOS, macOS, watchOS, and tvOS.

AFNetworking is a delightful networking library for iOS, macOS, watchOS, and tvOS. It's built on top of the Foundation URL Loading System, extending t

AFNetworking 33.3k Sep 22, 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
Lightweight Networking and Parsing framework made for iOS, Mac, WatchOS and tvOS.

NetworkKit A lightweight iOS, Mac and Watch OS framework that makes networking and parsing super simple. Uses the open-sourced JSONHelper with functio

Alex Telek 29 May 24, 2022
Bonjour networking for discovery and connection between iOS, macOS and tvOS devices.

Merhaba Bonjour networking for discovery and connection between iOS, macOS and tvOS devices. Features Creating Service Start & Stop Service Stop Brows

Abdullah Selek 66 Jun 20, 2022
ZeroMQ Swift Bindings for iOS, macOS, tvOS and watchOS

SwiftyZeroMQ - ZeroMQ Swift Bindings for iOS, macOS, tvOS and watchOS This library provides easy-to-use iOS, macOS, tvOS and watchOS Swift bindings fo

Ahmad M. Zawawi 60 Sep 15, 2022
SwiftSoup: Pure Swift HTML Parser, with best of DOM, CSS, and jquery (Supports Linux, iOS, Mac, tvOS, watchOS)

SwiftSoup is a pure Swift library, cross-platform (macOS, iOS, tvOS, watchOS and Linux!), for working with real-world HTML. It provides a very conveni

Nabil Chatbi 3.5k Sep 18, 2022
Asynchronous socket networking library for Mac and iOS

CocoaAsyncSocket CocoaAsyncSocket provides easy-to-use and powerful asynchronous socket libraries for macOS, iOS, and tvOS. The classes are described

Robbie Hanson 12.3k Sep 25, 2022
Swish is a networking library that is particularly meant for requesting and decoding JSON via Decodable

Swish Nothing but net(working). Swish is a networking library that is particularly meant for requesting and decoding JSON via Decodable. It is protoco

thoughtbot, inc. 370 Sep 9, 2022
foursquare iOS networking library

FSNetworking foursquare's iOS networking library FSN is a small library for HTTP networking on iOS. It comprises a single class, FSNConnection, and se

Foursquare 386 Sep 1, 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 846 Sep 9, 2022
Malibu is a networking library built on promises

Description Palm trees, coral reefs and breaking waves. Welcome to the surf club Malibu, a networking library built on promises. It's more than just a

Vadym Markov 409 Sep 9, 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
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 28 Jul 25, 2022
Malibu is a networking library built on promises

Description Palm trees, coral reefs and breaking waves. Welcome to the surf club Malibu, a networking library built on promises. It's more than just a

HyperRedink 10 Jan 29, 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 resource based, protocol oriented networking library designed for pure-SwiftUI applications.

Monarch ?? - WIP A resource based, protocol oriented networking library designed for pure-SwiftUI applications. Features: Async/Await Resource Based P

Emilio Pelaez Romero 3 Jun 30, 2022
Lightweight REST library for iOS and watchOS. Available on cococapods

RMHttp RMHttp is a Lightweight REST library for iOS and watchOS. Features Chainable Request URL / JSON Parameter Encoding HTTP Methods GET/POST/DELETE

Roger Molas 6 Mar 13, 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 Aug 4, 2022