Skip to content

Instantly share code, notes, and snippets.

@robertBojor
Last active September 21, 2015 19:43
Show Gist options
  • Select an option

  • Save robertBojor/40b4b5e3fe93a11bda24 to your computer and use it in GitHub Desktop.

Select an option

Save robertBojor/40b4b5e3fe93a11bda24 to your computer and use it in GitHub Desktop.

Revisions

  1. robertBojor revised this gist Sep 21, 2015. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions APIManager.swift
    Original file line number Diff line number Diff line change
    @@ -18,6 +18,7 @@ public class ApiManager: NSObject {
    let apiBaseURL = "https://api.yourdomain.com/"
    let apiVersionStub = "v1/"

    /* Endpoint format: METHOD~URL_STUB with possible parameters expressed as ? */
    let kEndpointAuth = "POST~auth"
    let kEndpointUserAdd = "POST~users"
    let kEndpointUserGetDetails = "GET~users/?"
  2. robertBojor revised this gist Sep 21, 2015. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion APIManager.swift
    Original file line number Diff line number Diff line change
    @@ -6,7 +6,6 @@
    //

    import Foundation
    import SystemConfiguration

    public class ApiManager: NSObject {

  3. robertBojor revised this gist Sep 21, 2015. 1 changed file with 1 addition and 2 deletions.
    3 changes: 1 addition & 2 deletions APIManager.swift
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,5 @@
    //
    // ConnectionManager.swift
    // BiConnect
    // APIManager.swift
    //
    // Created by Robert Bojor on 21/09/15.
    // Copyright (c) 2015 Robert Bojor. All rights reserved.
  4. robertBojor created this gist Sep 21, 2015.
    342 changes: 342 additions & 0 deletions APIManager.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,342 @@
    //
    // ConnectionManager.swift
    // BiConnect
    //
    // Created by Robert Bojor on 21/09/15.
    // Copyright (c) 2015 Robert Bojor. All rights reserved.
    //

    import Foundation
    import SystemConfiguration

    public class ApiManager: NSObject {

    let localStore = NSUserDefaults.standardUserDefaults()

    var errorDomain:String = "com.yourdomain.api"
    var authHeaderName = "X-Authorization"
    var authFieldInLocalStorage = "authToken"

    let apiBaseURL = "https://api.yourdomain.com/"
    let apiVersionStub = "v1/"

    let kEndpointAuth = "POST~auth"
    let kEndpointUserAdd = "POST~users"
    let kEndpointUserGetDetails = "GET~users/?"
    let kEndpointUserUpdateDetails = "POST~users/?"

    public enum ErrorCodes:Int {
    case AuthFailed = 0,
    AuthMissing = 1,
    UnknownErrorOnServer = 2,
    ServerISEError = 3
    }

    public enum ErrorMessages:String {
    case
    EmptyAPIURL = "API URL cannot be empty",
    EmptyAPIVersion = "API version cannot be empty",
    CheckingForNetwork = "Checking if connected to network",
    NotConnected = "Not connected to the internet",
    ConnectedToInternet = "Connected to internet",
    EmptyCredentials = "Authentication credentials cannot be empty",
    AuthTokenNotFound = "authToken was not found",
    AuthTokenFound = "authToken found and saved"
    }

    public enum MimeTypes:String {
    case ApplicationAtomXML = "application/atom+xml",
    ApplicationVnd = "application/vnd.dart",
    ApplicationECMAScript = "application/ecmascript",
    ApplicationEDIX12 = "application/EDI-X12",
    ApplicationEDIFACT = "application/EDIFACT",
    ApplicationJSON = "application/json",
    ApplicationJavaScript = "application/javascript",
    ApplicationOctetStream = "application/octet-stream",
    ApplicationOGG = "application/ogg",
    ApplicationDashXML = "application/dash+xml",
    ApplicationPDF = "application/pdf",
    ApplicationPostScript = "application/postscript",
    ApplicationRDF = "application/rdf+xml",
    ApplicationRSS = "application/rss+xml",
    ApplicationSOAP = "application/soap+xml",
    ApplicationWOFF = "application/font-woff",
    ApplicationXHTML = "application/xhtml+xml",
    ApplicationXML = "application/xml",
    ApplicationDTD = "application/xml-dtd",
    ApplicationXOP = "application/xop+xml",
    ApplicationZIP = "application/zip",
    ApplicationGzip = "application/gzip",
    ApplicationNACL = "application/x-nacl",
    ApplicationPNACL = "application/x-pnacl",
    ApplicationSMIL = "application/smil+xml",
    AudioBasic = "audio/basic",
    AudioL24 = "audio/L24",
    AudioMP4 = "audio/mp4",
    AudioMPEG = "audio/mpeg",
    AudioOGG = "audio/ogg",
    AudioFlac = "audio/flac",
    AudioOpus = "audio/opus",
    AudioVorbis = "audio/vorbis",
    AudioRealAudio = "audio/vnd.rn-realaudio",
    AudioWAV = "audio/vnd.wave",
    AudioWebM = "audio/webm",
    ImageGIF = "image/gif",
    ImageJPEG = "image/jpeg",
    ImagePJPEG = "image/pjpeg",
    ImagePNG = "image/png",
    ImageSVG = "image/svg+xml",
    ImageTiff = "image/tiff",
    ImageDjVu = "image/vnd.djvu",
    MessageHTTP = "message/http",
    MessageIMDN = "message/imdn+xml",
    MessagePartial = "message/partial",
    MessageRFC822 = "message/rfc822",
    ModelIGS = "model/iges",
    ModelMesh = "model/mesh",
    ModelVRML = "model/vrml",
    ModelX3DISO = "model/x3d+binary",
    ModelX3DFastInfoSet = "model/x3d+fastinfoset",
    ModelX3DVRML = "model/x3d-vrml",
    ModelX3DXML = "model/x3d+xml",
    MultipartMixed = "multipart/mixed",
    MultipartAlternative = "multipart/alternative",
    MultipartRelated = "multipart/related",
    MultipartFormData = "multipart/form-data",
    MultipartSigned = "multipart/signed",
    MultipartEncrypted = "multipart/encrypted",
    TextCMD = "text/cmd",
    TextCSS = "text/css",
    TextCSV = "text/csv",
    TextHTML = "text/html",
    TextPlain = "text/plain",
    TextRTF = "text/rtf",
    TextvCard = "text/vcard",
    TextALanguage = "text/vnd.a",
    TextABCNotation = "text/vnd.abc",
    TextXML = "text/xml",
    VideoAVI = "video/avi",
    VideoMPEG = "video/mpeg",
    VideoMP4 = "video/mp4",
    VideoOGG = "video/ogg",
    VideoQuicktime = "video/quicktime",
    VideoWebM = "video/webm",
    VideoMatroska = "video/x-matroska",
    VideoWMV = "video/x-ms-wmv",
    VideoFLV = "video/x-flv"
    }

    func NSURLByAppendingQueryParameters(URL : NSURL!, queryParameters : Dictionary<String, String>) -> NSURL {
    let URLString : NSString = NSString(format: "%@?%@", URL.absoluteString, self.stringFromQueryParameters(queryParameters))
    return NSURL(string: URLString as String)!
    }

    func stringFromQueryParameters(queryParameters : Dictionary<String, String>) -> String {
    var parts:[String] = []
    for (name, value) in queryParameters {
    let part = name.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLFragmentAllowedCharacterSet())! + "=" + value.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLFragmentAllowedCharacterSet())!
    parts.append(part)
    }
    return parts.joinWithSeparator("&")
    }

    func dataToJSONObject(data:NSData) -> NSDictionary {
    var jsonObject = NSDictionary()
    do {
    jsonObject = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments) as! NSDictionary
    } catch {
    jsonObject = ["payload":NSString(data: data, encoding: NSUTF8StringEncoding) as! String]
    }
    return jsonObject
    }

    public func sendRequest(toEndpoint:String, withURLParams:Array<String>?, withAuthentication:Bool, withHeaders:Dictionary<String,String>?, withParameters:Dictionary<String,String>?, withSuccess:(responsePayload:NSDictionary!, statusCode:Int!) -> Void, withFailure:(responsePayload:NSDictionary!, statusCode:Int, andError:NSError!)->Void) -> Void
    {
    let sessionConfig = NSURLSessionConfiguration.defaultSessionConfiguration()
    let session = NSURLSession(configuration: sessionConfig, delegate: nil, delegateQueue: nil)

    let urlParts = toEndpoint.componentsSeparatedByString("~")
    let requestMethod = urlParts[0]
    var endpointURL = urlParts[1]

    if (withURLParams != nil && withURLParams!.count > 0) {
    for(_, val) in withURLParams!.enumerate() {
    let occurence = endpointURL.rangeOfString("?")
    if (occurence != nil) {
    endpointURL = endpointURL.stringByReplacingCharactersInRange(occurence!, withString: "\(val)")
    }
    }
    }

    endpointURL = self.apiBaseURL + self.apiVersionStub + endpointURL
    var URL = NSURL(string: endpointURL)

    if requestMethod == "GET" && withParameters != nil && withParameters!.count > 0 {
    URL = self.NSURLByAppendingQueryParameters(URL, queryParameters: withParameters!)
    }

    let request = NSMutableURLRequest(URL: URL!)
    request.HTTPMethod = requestMethod
    request.addValue("application/json", forHTTPHeaderField: "Accept")

    if requestMethod == "POST" {
    request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
    }

    if (withHeaders != nil && withHeaders!.count > 0) {
    for(key, val) in withHeaders!.enumerate() {
    request.addValue("\(val)", forHTTPHeaderField: "\(key)")
    }
    }

    if (withAuthentication) {
    let authToken:String = localStore.objectForKey(self.authFieldInLocalStorage) as! String
    if authToken == "" {
    let errorCode = ErrorCodes.AuthMissing.rawValue
    let userInfoError = ["description":"Authentication has not been performed"]
    let authError = NSError(domain: errorDomain, code: errorCode, userInfo: userInfoError)
    withFailure(responsePayload: nil, statusCode: 0, andError: authError)
    }
    request.addValue(authToken, forHTTPHeaderField: self.authHeaderName)
    }

    if requestMethod == "POST" && withParameters != nil && withParameters!.count > 0 {
    let queryParameters = stringFromQueryParameters(withParameters!)
    request.HTTPBody = queryParameters.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
    }

    let task = session.dataTaskWithRequest(request, completionHandler: { (data : NSData?, response : NSURLResponse?, error : NSError?) -> Void in
    let responseStatusCode = (response as! NSHTTPURLResponse).statusCode
    if (error == nil) {
    switch (responseStatusCode) {
    // Everything ok
    case 200:
    withSuccess(responsePayload: self.dataToJSONObject(data!), statusCode: responseStatusCode)
    break
    // Bad request, Unauthorised request, Internal Server Error
    case 400, 403, 500:
    withFailure(responsePayload: self.dataToJSONObject(data!), statusCode: responseStatusCode, andError: error!)
    break
    case 500:
    let errorCode = ErrorCodes.ServerISEError.rawValue
    let userInfoError = ["description":"Internal Server Error - Data attached, if any"]
    let serverError = NSError(domain: self.errorDomain, code: errorCode, userInfo: userInfoError)
    withFailure(responsePayload: self.dataToJSONObject(data!), statusCode: 500, andError: serverError)
    break
    // None of the above
    default:
    let errorCode = ErrorCodes.UnknownErrorOnServer.rawValue
    let userInfoError = ["description":"Unknown Server Error - Data attached, if any"]
    let serverError = NSError(domain: self.errorDomain, code: errorCode, userInfo: userInfoError)
    withFailure(responsePayload: self.dataToJSONObject(data!), statusCode: 0, andError: serverError)
    break
    }
    } else {
    withFailure(responsePayload: self.dataToJSONObject(data!), statusCode: responseStatusCode, andError: error!)
    }
    })
    task.resume()
    }

    public func sendUploadRequest(toEndpoint toEndpoint:String, withURLParams:Array<String>?, withAuthentication:Bool, withHeaders:Dictionary<String,String>?, withParameters:Dictionary<String,String>?,
    withFilePath:String?, withFileName:String?, withFileContentType:MimeTypes?, withSuccess:(responsePayload:NSDictionary!, statusCode:Int!) -> Void, withFailure:(responsePayload:NSDictionary!, statusCode:Int, andError:NSError!)->Void) -> Void
    {
    let boundary = "__RB_HELPER_BOUNDARY__"
    var bodyString = ""
    var separator = ""
    var bodyData = NSMutableData()

    let sessionConfig = NSURLSessionConfiguration.defaultSessionConfiguration()
    let session = NSURLSession(configuration: sessionConfig, delegate: nil, delegateQueue: nil)

    let urlParts = toEndpoint.componentsSeparatedByString("~")
    let requestMethod = urlParts[0]
    var endpointURL = urlParts[1]

    if (withURLParams != nil && withURLParams!.count > 0) {
    for(_, val) in withURLParams!.enumerate() {
    let occurence = endpointURL.rangeOfString("?")
    if (occurence != nil) {
    endpointURL = endpointURL.stringByReplacingCharactersInRange(occurence!, withString: "\(val)")
    }
    }
    }

    endpointURL = self.apiBaseURL + self.apiVersionStub + endpointURL
    let URL = NSURL(string: endpointURL)
    let request = NSMutableURLRequest(URL: URL!)
    request.HTTPMethod = requestMethod

    if (withHeaders != nil && withHeaders!.count > 0) {
    for(key, val) in withHeaders!.enumerate() {
    request.addValue("\(val)", forHTTPHeaderField: "\(key)")
    }
    }

    if (withAuthentication) {
    let authToken:String = localStore.objectForKey(self.authFieldInLocalStorage) as! String
    if authToken == "" {
    let errorCode = ErrorCodes.AuthMissing.rawValue
    let userInfoError = ["description":"Authentication has not been performed"]
    let authError = NSError(domain: errorDomain, code: errorCode, userInfo: userInfoError)
    withFailure(responsePayload: nil, statusCode: 0, andError: authError)
    }
    request.addValue(authToken, forHTTPHeaderField: self.authHeaderName)
    }

    if (withParameters != nil && withParameters!.count > 0) {
    for(paramKey, paramVal) in withParameters!.enumerate() {
    bodyString = "\(separator)--\(boundary)\r\nContent-Disposition: form-data; name=\"\(paramKey)\"\r\n\r\n\(paramVal)"
    separator = "\r\n"
    bodyData.appendData(bodyString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!)
    }
    }

    if (withFilePath != nil) {
    let fileData = NSData(contentsOfFile: withFilePath!)
    if ((fileData) != nil) {
    bodyString = "\(separator)--\(boundary)\r\nContent-Disposition: form-data; name=\"payload\"; filename=\"\(withFileName)\"\r\nContent-Type: \(withFileContentType!.rawValue)\r\n\r\n"
    separator = "\r\n"
    bodyData.appendData(bodyString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!)
    bodyData.appendData(fileData!)
    bodyData.appendData(separator.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!)
    }
    }

    bodyString = "--\(boundary)--\r\n"
    bodyData.appendData(bodyString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!)

    request.HTTPBody = bodyData
    let task = session.dataTaskWithRequest(request, completionHandler: { (data : NSData?, response : NSURLResponse?, error : NSError?) -> Void in
    let responseStatusCode = (response as! NSHTTPURLResponse).statusCode
    if (error == nil) {
    switch (responseStatusCode) {
    // Everything ok
    case 200:
    withSuccess(responsePayload: self.dataToJSONObject(data!), statusCode: responseStatusCode)
    break
    // Bad request, Unauthorised request, Internal Server Error
    case 400, 403, 500:
    withFailure(responsePayload: self.dataToJSONObject(data!), statusCode: responseStatusCode, andError: error!)
    break
    case 500:
    let errorCode = ErrorCodes.ServerISEError.rawValue
    let userInfoError = ["description":"Internal Server Error - Data attached, if any"]
    let serverError = NSError(domain: self.errorDomain, code: errorCode, userInfo: userInfoError)
    withFailure(responsePayload: self.dataToJSONObject(data!), statusCode: 500, andError: serverError)
    break
    // None of the above
    default:
    let errorCode = ErrorCodes.UnknownErrorOnServer.rawValue
    let userInfoError = ["description":"Unknown Server Error - Data attached, if any"]
    let serverError = NSError(domain: self.errorDomain, code: errorCode, userInfo: userInfoError)
    withFailure(responsePayload: self.dataToJSONObject(data!), statusCode: 0, andError: serverError)
    break
    }
    } else {
    withFailure(responsePayload: self.dataToJSONObject(data!), statusCode: responseStatusCode, andError: error!)
    }
    })
    task.resume()
    }
    }