Last active
June 7, 2016 12:37
-
-
Save Gujci/d639df15584f24eca38ff48d9eff6eb9 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
| // | |
| // API.swift | |
| // | |
| // Created by Gujgiczer Máté on 19/03/16. | |
| // | |
| import Foundation | |
| public enum APIError: Int, ErrorType { | |
| case Unknown | |
| case NotFound | |
| case Unouthorized | |
| case Forbidden | |
| case Timeout | |
| case MultipleChoice | |
| case BadRequest | |
| init?(withResponse response: NSURLResponse?) { | |
| if let statusCode = (response as? NSHTTPURLResponse)?.statusCode { | |
| switch statusCode { | |
| case 200: | |
| return nil | |
| case 300: | |
| self = .MultipleChoice | |
| case 400: | |
| self = .BadRequest | |
| case 401: | |
| self = .Unouthorized | |
| case 403: | |
| self = .Forbidden | |
| case 404: | |
| self = .NotFound | |
| case 500...599: | |
| self = .Timeout | |
| default: | |
| self = .Unknown | |
| } | |
| } | |
| else { | |
| return nil | |
| } | |
| } | |
| } | |
| enum ValidJSONObjectParseError: ErrorType { | |
| case JSONSerializeError | |
| } | |
| protocol ValidJSONObject { | |
| func JSONFormat() throws -> NSData | |
| } | |
| enum AuthenticationType { | |
| case None | |
| case HTTPHeader | |
| case URLParameter | |
| } | |
| class RequestAuthenticator { | |
| var type: AuthenticationType = .None | |
| var accessToken: String? | |
| var tokenKey: String? | |
| func authenticateURLRequest(req: NSMutableURLRequest) -> NSMutableURLRequest { | |
| switch self.type { | |
| case .HTTPHeader where accessToken != nil && tokenKey != nil: | |
| req.addValue(accessToken!,forHTTPHeaderField: tokenKey!) | |
| return req | |
| case .URLParameter where accessToken != nil && tokenKey != nil: | |
| req.URL = NSURL(url: req.URL!,query: [tokenKey!: accessToken!]) | |
| return req | |
| default: | |
| return req | |
| } | |
| } | |
| } | |
| typealias APICompletionHandler = ((JSON?) throws -> Void)? | |
| class API { | |
| var authentication: RequestAuthenticator | |
| var baseURL: String | |
| func post(endpoint: String, query: Dictionary<String, Queryable>? = nil, data: ValidJSONObject? = nil, | |
| completion: (error: APIError?, object: JSON?) -> ()) { | |
| dataTask(clientURLRequest(endpoint, query: query, params: data), method: "POST", completion: completion) | |
| } | |
| func put(endpoint: String, query: Dictionary<String, Queryable>? = nil, data: ValidJSONObject? = nil, | |
| completion: (error: APIError?, object: JSON?) -> ()) { | |
| dataTask(clientURLRequest(endpoint, query: query, params: data), method: "PUT", completion: completion) | |
| } | |
| func get(endpoint: String, query: Dictionary<String, Queryable>? = nil, data: ValidJSONObject? = nil, | |
| completion: (error: APIError?, object: JSON?) -> ()) { | |
| dataTask(clientURLRequest(endpoint, query: query, params: data), method: "GET", completion: completion) | |
| } | |
| func delete(endpoint: String, query: Dictionary<String, Queryable>? = nil, data: ValidJSONObject? = nil, | |
| completion: (error: APIError?, object: JSON?) -> ()) { | |
| dataTask(clientURLRequest(endpoint, query: query, params: data), method: "DELETE", completion: completion) | |
| } | |
| internal func dataTask(request: NSMutableURLRequest, method: String, completion: (error: APIError?, object: JSON?) -> ()) { | |
| request.HTTPMethod = method | |
| let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration()) | |
| session.dataTaskWithRequest(authentication.authenticateURLRequest(request)) { (data, response, error) -> Void in | |
| if let validData = data { | |
| completion(error: APIError(withResponse: response), object: JSON(data: validData)) | |
| } | |
| else { | |
| completion(error: APIError(withResponse: response), object: nil) | |
| } | |
| }.resume() | |
| } | |
| internal func clientURLRequest(path: String,query: Dictionary<String, Queryable>?, params: ValidJSONObject?) | |
| -> NSMutableURLRequest { | |
| let request = NSMutableURLRequest(URL: NSURL(string: baseURL + path, query: query)) | |
| if let params = params { | |
| let jsonData = try? params.JSONFormat() | |
| request.HTTPBody = jsonData | |
| } | |
| request.addValue("application/json",forHTTPHeaderField: "Content-Type") | |
| request.addValue("application/json",forHTTPHeaderField: "Accept") | |
| request.addValue(NSBundle.mainBundle().preferredLocalizations.first ?? "en",forHTTPHeaderField: "Accept-Language") | |
| return request | |
| } | |
| init(withBaseUrl baseUrl: String, authentication: RequestAuthenticator? = nil) { | |
| self.baseURL = baseUrl | |
| if let givenAuthentication = authentication { | |
| self.authentication = givenAuthentication | |
| } | |
| else { | |
| self.authentication = RequestAuthenticator() | |
| } | |
| } | |
| } | |
| protocol Queryable { | |
| func queryString(forKey key: String) -> [NSURLQueryItem] | |
| } | |
| extension Array: Queryable { | |
| func queryString(forKey key: String) -> [NSURLQueryItem] { | |
| return self.map() { item in | |
| return NSURLQueryItem(name: "\(key)[]", value: "\(item)") | |
| } | |
| } | |
| } | |
| extension String: Queryable { | |
| func queryString(forKey key: String) -> [NSURLQueryItem] { | |
| return [NSURLQueryItem(name: key, value: self)] | |
| } | |
| } | |
| extension NSURL { | |
| convenience init(string: String, query: Dictionary<String, Queryable>?) { | |
| if query == nil { | |
| self.init(string: string)! | |
| return | |
| } | |
| let components = NSURLComponents(string: string) | |
| var querryItems = components?.queryItems ?? Array<NSURLQueryItem>() | |
| query?.forEach() { | |
| querryItems.appendContentsOf($0.1.queryString(forKey: $0.0)) | |
| } | |
| components?.queryItems = querryItems | |
| self.init(string: "",relativeToURL: components!.URL)! | |
| } | |
| convenience init(url: NSURL, query: Dictionary<String, Queryable>?) { | |
| let components = NSURLComponents(URL: url, resolvingAgainstBaseURL: false) | |
| var querryItems = components?.queryItems ?? Array<NSURLQueryItem>() | |
| query?.forEach() { | |
| querryItems.appendContentsOf($0.1.queryString(forKey: $0.0)) | |
| } | |
| components?.queryItems = querryItems | |
| self.init(string: "",relativeToURL: components!.URL)! | |
| } | |
| } | |
| extension NSDate { | |
| static var timestamp: Double { | |
| get { | |
| return NSDate().timeIntervalSince1970 * 1000 | |
| } | |
| } | |
| } | |
| extension Dictionary: ValidJSONObject { | |
| func JSONFormat() throws -> NSData { | |
| if let serializableData = self as? AnyObject { | |
| return try NSJSONSerialization.dataWithJSONObject(serializableData, options: .PrettyPrinted) | |
| } | |
| else { | |
| throw ValidJSONObjectParseError.JSONSerializeError | |
| } | |
| } | |
| } | |
| extension Array: ValidJSONObject { | |
| func JSONFormat() throws -> NSData { | |
| if let serializableData = self as? AnyObject { | |
| return try NSJSONSerialization.dataWithJSONObject(serializableData, options: .PrettyPrinted) | |
| } | |
| else { | |
| throw ValidJSONObjectParseError.JSONSerializeError | |
| } | |
| } | |
| } | |
| func + <K, V>(left: Dictionary<K, V>, right: Dictionary<K, V>) -> Dictionary<K, V> { | |
| var map = Dictionary<K, V>() | |
| for (k, v) in left { | |
| map[k] = v | |
| } | |
| for (k, v) in right { | |
| map[k] = v | |
| } | |
| return map | |
| } | |
| func += <K, V> (inout left: Dictionary<K, V>, right: Dictionary<K, V>) -> Dictionary<K, V> { | |
| for (k, v) in right { | |
| left[k] = v | |
| } | |
| return left | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment