Created
June 4, 2014 08:18
-
-
Save Nub/94e6a76e48e9fdbde11c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // NSURL_Networking.swift | |
| // swiftTools | |
| // | |
| // Created by Zachry Thayer on 6/3/14. | |
| // Copyright (c) 2014 Zachry Thayer. All rights reserved. | |
| // | |
| import Foundation | |
| #if os(iOS) | |
| import UIKit | |
| #elseif os(OSX) | |
| import AppKit | |
| #endif | |
| extension NSURL { | |
| //MARK: Networking | |
| struct Networking { | |
| static let operationQueue = NSOperationQueue.mainQueue() | |
| enum REST: String { | |
| case GET = "GET" | |
| case POST = "POST" | |
| case PUT = "PUT" | |
| case DELETE = "DELETE" | |
| } | |
| enum ErrorCode: Int { | |
| case ImageProcessingFailure = -1 | |
| case JsonProcessingFailure = -2 | |
| } | |
| static let ErrorDomain = "NSURL_Networking" | |
| static let ResponseKey = "response" | |
| #if os(iOS) | |
| static let imageType = UIImage.self | |
| #elseif os(OSX) | |
| static let imageType = NSImage.self | |
| #endif | |
| } | |
| typealias StringDict = Dictionary<String,String> | |
| func request() -> NSMutableURLRequest { | |
| let request = NSMutableURLRequest(URL: self) | |
| return request | |
| } | |
| func GET(body: (NSData, StringDict!)?=nil, completion: ((NSHTTPURLResponse, AnyObject) -> Void)) { | |
| fetch(Networking.REST.GET, body: body, completion: completion) | |
| } | |
| func POST(body: (NSData, StringDict!), completion: ((NSHTTPURLResponse, AnyObject) -> Void)) { | |
| fetch(Networking.REST.POST, body: body, completion: completion) | |
| } | |
| func PUT(body: (NSData, StringDict!), completion: ((NSHTTPURLResponse, AnyObject) -> Void)) { | |
| fetch(Networking.REST.PUT, body: body, completion: completion) | |
| } | |
| func DELETE(body: (NSData, StringDict!)?=nil, completion: ((NSHTTPURLResponse, AnyObject) -> Void)) { | |
| fetch(Networking.REST.DELETE, body: body, completion: completion) | |
| } | |
| func fetch(method: Networking.REST, body: (NSData, StringDict!)!, completion: ((NSHTTPURLResponse, AnyObject) -> Void)) { | |
| let request = self.request() | |
| request.HTTPMethod = method.toRaw() | |
| if body != nil { | |
| let data = body.0 | |
| let headerFieldValues = body.1 | |
| request.HTTPBody = data; | |
| for key: String in headerFieldValues.keys { | |
| let value = headerFieldValues[key] | |
| request.setValue(value, forHTTPHeaderField: key) | |
| } | |
| } | |
| NSURLConnection.sendAsynchronousRequest(request, queue: Networking.operationQueue){(response: NSURLResponse!, data: NSData!, error: NSError!) in | |
| let httpResponse = response as NSHTTPURLResponse | |
| if error == nil { | |
| completion(httpResponse, data) | |
| } else { | |
| completion(httpResponse, error) | |
| } | |
| } | |
| } | |
| func processResponse(response: NSHTTPURLResponse, data: NSData) -> AnyObject { | |
| let mime: String = response.MIMEType | |
| var responseData: AnyObject! | |
| var error: NSErrorPointer! = UnsafePointer<NSError?>() | |
| switch mime { | |
| case "application/json": | |
| responseData = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: error) | |
| case let image where image.hasPrefix("image"): | |
| responseData = Networking.imageType(data: data as NSData) | |
| if response == nil { | |
| let userInfo = NSDictionary(object: response, forKey: Networking.ResponseKey) | |
| error.memory = NSError(domain: Networking.ErrorDomain, code: Networking.ErrorCode.ImageProcessingFailure.toRaw(), userInfo: userInfo) | |
| } | |
| default: | |
| responseData = data | |
| } | |
| if error != nil { | |
| println("Response:\(response)\nError:\(error)") | |
| responseData = nil | |
| } | |
| return response | |
| } | |
| //MARK: URL Building | |
| /** | |
| * Builds urls based off of a template and a set of values | |
| * @arg template - URL template format: Keys are defined as {key}, where key is a value from a dictionary | |
| **/ | |
| class func URLWithTemplate(template: String, values: Dictionary<String,String>) -> NSURL { | |
| var urlString = template | |
| for key: String in values.keys { | |
| let keyTemplate = "{\(key)}" | |
| let value = NSURL.escapeQueryString(values[key]!) | |
| urlString = urlString.stringByReplacingOccurrencesOfString(keyTemplate, withString: value) | |
| } | |
| return NSURL.URLWithString(urlString) | |
| } | |
| /** | |
| * Converts a dictionary into a GET query and appends it to a URL | |
| **/ | |
| func URLByAppendingQuery(query: Dictionary<String, AnyObject>) -> NSURL { | |
| let queryString = NSURL.queryStringFromDictionary(query, baseName:nil) | |
| return NSURL(string: queryString) | |
| } | |
| //MARK: Private URL Building | |
| class func queryStringFromDictionary(dictionary: Dictionary<String, AnyObject>, baseName: String!) -> String { | |
| let escapedBasename = NSURL.escapeQueryString(baseName) | |
| var queryString = escapedBasename + "=" | |
| var firstItem: Bool = (baseName != nil) | |
| for key: String in dictionary.keys { | |
| var escapedKey = NSURL.escapeQueryString(key) | |
| var value: AnyObject = dictionary[key] as AnyObject | |
| var newBaseName: String | |
| if firstItem { | |
| newBaseName = escapedKey | |
| } else { | |
| queryString += "&" | |
| newBaseName = "\(escapedBasename)[\(escapedKey)]" | |
| } | |
| if value is Dictionary<String, AnyObject> { | |
| let dictionaryQueryString = NSURL.queryStringFromDictionary(value as Dictionary<String, AnyObject>, baseName: newBaseName) | |
| queryString += dictionaryQueryString | |
| continue | |
| } else if value is Array<String> { | |
| let dictionaryQueryString = NSURL.queryStringFromDictionary(value as Dictionary<String, AnyObject>, baseName: newBaseName) | |
| queryString += dictionaryQueryString | |
| continue | |
| } else { | |
| let escapedValue = NSURL.escapeQueryString("\(value)") | |
| if baseName != nil { | |
| queryString += "\(escapedBasename)[\(escapedKey)]=\(escapedValue)" | |
| } else { | |
| queryString += "\(escapedKey)=\(escapedValue)" | |
| } | |
| } | |
| firstItem = false | |
| } | |
| return queryString | |
| } | |
| class func queryStringFromArray(array: Array<String>, baseName: String) -> String { | |
| let escapedKey = NSURL.escapeQueryString(baseName) | |
| var queryString = escapedKey + "=" | |
| for value: String in array { | |
| let escapedValue = NSURL.escapeQueryString(value) | |
| queryString += escapedValue | |
| if value != array[array.endIndex] { | |
| queryString += "," | |
| } | |
| } | |
| return queryString | |
| } | |
| class func escapeQueryString(queryString: String) -> String { | |
| let allowedCharacters = NSCharacterSet(charactersInString: ":/?#[]@!$&’()*+,;=") | |
| return queryString.stringByAddingPercentEncodingWithAllowedCharacters(allowedCharacters) | |
| } | |
| } | |
| //MARK: Operator overloading | |
| @infix func + (left: NSURL, right: Dictionary<String, AnyObject>) -> NSURL { | |
| return left.URLByAppendingQuery(right) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment