Git Product home page Git Product logo

swifthttp's Introduction

SwiftHTTP

SwiftHTTP is a thin wrapper around NSURLSession in Swift to simplify HTTP requests.

Features

  • Convenient Closure APIs
  • NSOperationQueue Support
  • Parameter Encoding
  • Custom Response Serializer
  • Builtin JSON Response Serialization
  • Upload/Download with Progress Closure
  • Concise Codebase. Under 1000 LOC

Full article here: http://vluxe.io/swifthttp.html

First thing is to import the framework. See the Installation instructions on how to add the framework to your project.

import SwiftHTTP

Examples

GET

The most basic request. By default an NSData object will be returned for the response.

var request = HTTPTask()
request.GET("http://vluxe.io", parameters: nil, completionHandler: {(response: HTTPResponse) in
	if let err = response.error {
		println("error: \(err.localizedDescription)")
		return //also notify app of failure as needed
	}
	if let data = response.responseObject as? NSData {
	    let str = NSString(data: data, encoding: NSUTF8StringEncoding)
	    println("response: \(str)") //prints the HTML of the page
	}
})

We can also add parameters as with standard container objects and they will be properly serialized to their respective HTTP equivalent.

var request = HTTPTask()
request.GET("http://google.com", parameters: ["param": "param1", "array": ["first array element","second","third"], "num": 23], completionHandler: {(response: HTTPResponse) in
    if let err = response.error {
		println("error: \(err.localizedDescription)")
		return //also notify app of failure as needed
	}
	if let res: AnyObject = response.responseObject {
		println("response: \(res)")
	}
})

The HTTPResponse contains all the common HTTP response data, such as the responseObject of the data and the headers of the response.

POST

A POST request is just as easy as a GET.

var request = HTTPTask()
//we have to add the explicit type, else the wrong type is inferred. See the vluxe.io article for more info.
let params: Dictionary<String,AnyObject> = ["param": "param1", "array": ["first array element","second","third"], "num": 23, "dict": ["someKey": "someVal"]]
request.POST("http://domain.com/create", parameters: params, completionHandler: {(response: HTTPResponse) in
	//do things...
})

PUT

PUT works the same as post. The example also include a file upload to do a multi form request.

let fileUrl = NSURL.fileURLWithPath("/Users/dalton/Desktop/file")!
var request = HTTPTask()
request.PUT("http://domain.com/1", parameters:  ["param": "hi", "something": "else", "key": "value","file": HTTPUpload(fileUrl: fileUrl)], completionHandler: {(response: HTTPResponse) in
	//do stuff
})

The HTTPUpload object is use to represent files on disk or in memory file as data.

DELETE

DELETE works the same as the GET.

var request = HTTPTask()
request.DELETE("http://domain.com/1", parameters: nil, completionHandler: {(response: HTTPResponse) in
    if let err = response.error {
		println("error: \(err.localizedDescription)")
		return //also notify app of failure as needed
	}
	println("DELETE was successful!")
})

HEAD

HEAD works the same as the GET.

var request = HTTPTask()
request.HEAD("http://domain.com/image.png", parameters: nil, completionHandler: {(response: HTTPResponse) in
    if let err = response.error {
		println("error: \(err.localizedDescription)")
		return //also notify app of failure as needed
	}
	println("The file does exist!")
})

Download

The download method uses the background download functionality of NSURLSession. It also has a progress closure to report the progress of the download.

var request = HTTPTask()
let downloadTask = request.download("http://vluxe.io/assets/images/logo.png", parameters: nil, progress: {(complete: Double) in
    println("percent complete: \(complete)")
    }, completionHandler: {(response: HTTPResponse) in
    println("download finished!")
    if let err = response.error {
		println("error: \(err.localizedDescription)")
		return //also notify app of failure as needed
	}
    if let url = response.responseObject as? NSURL {
	    //we MUST copy the file from its temp location to a permanent location.
        if let path = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first as? String {
            if let fileName = response.suggestedFilename {
                if let newPath = NSURL(fileURLWithPath: "\(path)/\(fileName)") {
                    let fileManager = NSFileManager.defaultManager()
                    fileManager.removeItemAtURL(newPath, error: nil)
                    fileManager.moveItemAtURL(url, toURL: newPath, error:nil)
                }
            }
        }
    }

})

Cancel the download.

if let t = downloadTask {
    t.cancel()
}

Upload

File uploads can be done using the HTTPUpload object. All files to upload should be wrapped in a HTTPUpload object and added as a parameter.

let task = HTTPTask()
var fileUrl = NSURL(fileURLWithPath: "/Users/dalton/Desktop/testfile")!
task.upload("http://domain.com/upload", method: .POST, parameters: ["aParam": "aValue", "file": HTTPUpload(fileUrl: fileUrl)], progress: { (value: Double) in
    println("progress: \(value)")
}, completionHandler: { (response: HTTPResponse) in
    if let err = response.error {
        println("error: \(err.localizedDescription)")
        return //also notify app of failure as needed
    }
    if let data = response.responseObject as? NSData {
        let str = NSString(data: data, encoding: NSUTF8StringEncoding)
        println("response: \(str!)") //prints the response
    }
})

HTTPUpload comes in both a on disk fileUrl version and a NSData version.

Custom Headers

Custom HTTP headers can be add to a request via the requestSerializer.

var request = HTTPTask()
request.requestSerializer = HTTPRequestSerializer()
request.requestSerializer.headers["someKey"] = "SomeValue" //example of adding a header value

SSL Pinning

SSL Pinning is also supported in SwiftHTTP.

let task = HTTPTask()
let data = ... //load your certificate from disk
task.security = HTTPSecurity(certs: [HTTPSSLCert(data: data)], usePublicKeys: true)
//task.security = HTTPSecurity() //uses the .cer files in your app's bundle
request.GET("http://yourdomain.com", parameters: nil, completionHandler: {(response: HTTPResponse) in
	//handle response
})

You load either a NSData blob of your certificate or you can use a SecKeyRef if you have a public key you want to use. The usePublicKeys bool is whether to use the certificates for validation or the public keys. The public keys will be extracted from the certificates automatically if usePublicKeys is choosen.

Authentication

SwiftHTTP supports authentication through NSURLCredential. Currently only Basic Auth and Digest Auth have been tested.

var request = HTTPTask()
//the auth closures will continually be called until a successful auth or rejection
var attempted = false
request.auth = {(challenge: NSURLAuthenticationChallenge) in
    if !attempted {
        attempted = true
        return NSURLCredential(user: "user", password: "passwd", persistence: .ForSession)
    }
    return nil //auth failed, nil causes the request to be properly cancelled.
}
request.GET("http://httpbin.org/basic-auth/user/passwd", parameters: nil, completionHandler: {(response: HTTPResponse) in
    if let err = response.error {
		println("error: \(err.localizedDescription)")
		return //also notify app of failure as needed
	}
	 println("winning!")
})

Allow all certificates example:

var request = HTTPTask()
var attempted = false
request.auth = {(challenge: NSURLAuthenticationChallenge) in
    if !attempted {
        attempted = true
        return NSURLCredential(forTrust: challenge.protectionSpace.serverTrust)
    }
    return nil
}
request.GET("https://somedomain.com", parameters: nil, completionHandler: {(response: HTTPResponse) in
    if let err = response.error {
		println("error: \(err.localizedDescription)")
		return //also notify app of failure as needed
	}
    println("winning!")
})

BaseURL

SwiftHTTP also supports use a request object with a baseURL. This is super handy for RESTFul API interaction.

var request = HTTPTask()
request.baseURL = "http://api.someserver.com/1"
request.GET("/users", parameters: ["key": "value"], completionHandler: {(response: HTTPResponse) in
    if let err = response.error {
		println("error: \(err.localizedDescription)")
		return //also notify app of failure as needed
	}
    println("Got data from http://api.someserver.com/1/users")
})

request.POST("/users", parameters: ["key": "updatedVale"], completionHandler: {(response: HTTPResponse) in
    if let err = response.error {
		println("error: \(err.localizedDescription)")
		return //also notify app of failure as needed
	}
    println("Got data from http://api.someserver.com/1/users")
})

request.GET("/resources", parameters: ["key": "value"], completionHandler: {(response: HTTPResponse) in
    if let err = response.error {
		println("error: \(err.localizedDescription)")
		return //also notify app of failure as needed
	}
    println("Got data from http://api.someserver.com/1/resources")
})

Operation Queue

Operation queues are also supported in SwiftHTTP.

let operationQueue = NSOperationQueue()
operationQueue.maxConcurrentOperationCount = 2
var request = HTTPTask()
var opt = request.create("http://vluxe.io", method: .GET, parameters: nil, completionHandler: {(response: HTTPResponse) in
    if let err = response.error {
		println("error: \(err.localizedDescription)")
		return //also notify app of failure as needed
	}
    if let data = response.responseObject as? NSData {
        let str = NSString(data: data, encoding: NSUTF8StringEncoding)
        println("response: \(str)") //prints the HTML of the page
    }
 })
if let o = opt {
    operationQueue.addOperation(o)
}

Cancel

Let's say you want to cancel this request a little later, simple use the operationQueue cancel.

if let o = opt {
    o.cancel()
}

Serializers

Request parameters and request responses can also be serialized as needed. By default request are serialized using standard HTTP form encoding. A JSON request and response serializer are provided as well. It is also very simple to create custom serializer by subclass a request or response serializer

var request = HTTPTask()
//The parameters will be encoding as JSON data and sent.
request.requestSerializer = JSONRequestSerializer()
//The expected response will be JSON and be converted to an object return by NSJSONSerialization instead of a NSData.
request.responseSerializer = JSONResponseSerializer()
request.GET("http://vluxe.io", parameters: nil, completionHandler: {(response: HTTPResponse) in
    if let err = response.error {
		println("error: \(err.localizedDescription)")
		return //also notify app of failure as needed
	}
    if let dict = response.responseObject as? Dictionary<String,AnyObject> {
    		let value = dict["key"]!
		println("example of the JSON key: \(value)")
		println("print the whole response: \(response)")
    }
 })

UI Changes

All completionHandler closures return on a background thread. This allows any data parsing to be done without blocking the UI. To make update the UI, call dispatch_async(dispatch_get_main_queue(),{...}.

var request = HTTPTask()
request.GET("http://vluxe.io", parameters: nil, completionHandler: {(response: HTTPResponse) in
    if let err = response.error {
		println("error: \(err.localizedDescription)")
		return //also notify app of failure as needed
	}
	if let data = response.responseObject as? NSData {
        let str = NSString(data: data, encoding: NSUTF8StringEncoding)
        println("response: \(str)") //prints the HTML of the page
		dispatch_async(dispatch_get_main_queue(),{
			self.label.text = str //update the label's text with the HTML content
		})
    }
})

Client/Server Example

This is a full example swiftHTTP in action. First here is a quick web server in Go.

package main

import (
	"fmt"
	"log"
	"net/http"
)

func main() {
	http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
		log.Println("got a web request")
		fmt.Println("header: ", r.Header.Get("someKey"))
		w.Write([]byte("{\"status\": \"ok\"}"))
	})

	log.Fatal(http.ListenAndServe(":8080", nil))
}

Now for the request:

//The object that will represent our response. More Info in the JSON Parsing section below.
struct Status : JSONJoy {
    var status: String?
    init() {

    }
    init(_ decoder: JSONDecoder) {
        status = decoder["status"].string
    }
}
//The request
var request = HTTPTask()
request.requestSerializer = HTTPRequestSerializer()
request.requestSerializer.headers["someKey"] = "SomeValue" //example of adding a header value
request.responseSerializer = JSONResponseSerializer()
request.GET("http://localhost:8080/bar", parameters: nil, completionHandler: {(response: HTTPResponse) in
    if let err = response.error {
		println("error: \(err.localizedDescription)")
		return //also notify app of failure as needed
	}
    if let obj: AnyObject = response.responseObject {
		let resp = Status(JSONDecoder(obj))
        println("status is: \(resp.status)")
    }
})

JSON Parsing

Swift has a lot of great JSON parsing libraries, but I made one specifically designed for JSON to object serialization.

JSONJoy-Swift

Requirements

SwiftHTTP works with iOS 7/OSX 10.9 or above. It is recommended to use iOS 8/10.10 or above for Cocoapods/framework support.

Installation

Cocoapods

Check out Get Started tab on cocoapods.org.

To use SwiftHTTP in your project add the following 'Podfile' to your project

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!

pod 'SwiftHTTP', '~> 0.9.4'

Then run:

pod install

Carthage

Check out the Carthage docs on how to add a install. The SwiftHTTP framework is already setup with shared schemes.

Carthage Install

Rogue

First see the installation docs for how to install Rogue.

To install SwiftLog run the command below in the directory you created the rogue file.

rogue add https://github.com/daltoniam/SwiftHTTP

Next open the libs folder and add the SwiftHTTP.xcodeproj to your Xcode project. Once that is complete, in your "Build Phases" add the SwiftHTTP.framework to your "Link Binary with Libraries" phase. Make sure to add the libs folder to your .gitignore file.

Other

Simply grab the framework (either via git submodule or another package manager).

Add the SwiftHTTP.xcodeproj to your Xcode project. Once that is complete, in your "Build Phases" add the SwiftHTTP.framework to your "Link Binary with Libraries" phase.

Add Copy Frameworks Phase

If you are running this in an OSX app or on a physical iOS device you will need to make sure you add the SwiftHTTP.framework included in your app bundle. To do this, in Xcode, navigate to the target configuration window by clicking on the blue project icon, and selecting the application target under the "Targets" heading in the sidebar. In the tab bar at the top of that window, open the "Build Phases" panel. Expand the "Link Binary with Libraries" group, and add SwiftHTTP.framework. Click on the + button at the top left of the panel and select "New Copy Files Phase". Rename this new phase to "Copy Frameworks", set the "Destination" to "Frameworks", and add SwiftHTTP.framework.

TODOs

  • Add more unit tests

License

SwiftHTTP is licensed under the Apache v2 License.

Contact

Dalton Cherry

swifthttp's People

Contributors

daltoniam avatar acmacalister avatar robertmryan avatar rajeev avatar mogadget avatar pizthewiz avatar keith avatar theadam avatar nemesis avatar jrschifa avatar randomite avatar neichen avatar samlbest avatar rere61 avatar

Watchers

 avatar James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.