[Swift] How to call REST API in iOS by using Swift code

9:29:00 PM 0 Comments

Hi,

I would like to share my little experiences on how to create a REST API request functions by using Swift.

Getting started

This is a function to post a request, you can notice that we have a completionHandler() as a parameter of sendPostRequest. The reason behind this is an asynchronous, all of HTTP request in swift runs as asynchronous request, just like Javascript or the other languages. 

All of the example here will use a completion handler function. The reason behind this is an asynchronous process, NSURLSession run the session in asynchronous mode (same as Javascript so it's not something new). 

Having a Callback function allows you to have more flexible over the bunch of request you have made. 

Create a new Project

Simply opening Xcode and create a new console project on MacOs.

Server configuration

In this tutorial, we will use a Mockable.io to build a test API server, I've found it a very simple website that allows you to build a mock API server. 

I'm using the basic authorisation because this functions come from my previous works, however, it doesn't matter with Mock server. So you can feel free to get rid of it, I simply put it here because I want the functions to have fully meaning :).

NSData to NSDictionary

I likes to seperate this step out of our HTTP request functions, because I usually handles error and do more stuff in this step. So if you don't like this, just convert the Request response directly and no need to make another function.

    // Convert NSData to Dictionary
    class func convertToDict(jsonStr: NSData) -> NSDictionary {
        do {
            if let convertedJsonIntoDict = try NSJSONSerialization.JSONObjectWithData(jsonStr, options: []) as? NSDictionary {
                
                return convertedJsonIntoDict
                
            }
        } catch let error as NSError {
            print(error.localizedDescription)
        }
        return NSDictionary()
    }

GET Request

    // GET Request
    func sendGetRequest(url: String, credential: [String], completionHandler: (NSData?, NSError?) -> ()) -> NSURLSessionTask {
        
        // NSURL Object
        let myNSURL = NSURL(string: url)
        
        // URL Request
        let myRequest = NSMutableURLRequest(URL: myNSURL!)
        myRequest.HTTPMethod = "GET"
        
        // Basic Authorization
        let username = credential[0]
        let password = credential[1]
        let loginString =  NSString(format: "%@:%@", username, password)
        let loginData: NSData = loginString.dataUsingEncoding(NSUTF8StringEncoding)!
        let base64LoginString = loginData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions())
        myRequest.setValue("Basic \(base64LoginString)", forHTTPHeaderField: "Authorization")
        
        // Excute HTTP Request
        let task = NSURLSession.sharedSession().dataTaskWithRequest(myRequest) { data, response, error in
            
            dispatch_async(dispatch_get_main_queue()) {
                if data != nil {
                    completionHandler(data, nil)
                }else {
                    completionHandler(nil, error)
                    return
                }
            }
            
        }
        
        task.resume();
        
        return task
    }

POST request

func sendPostRequest(url: String, credential: [String], json: Dictionary<String,String>, completionHandler: (NSData?, NSError?) -> ()) -> NSURLSessionTask {
        
        // NSURL Object
        let myNSURL = NSURL(string: url)
        
        // URL Request
        let myRequest = NSMutableURLRequest(URL: myNSURL!)
        myRequest.HTTPMethod = "POST"
        
        // Basic Authorization
        let username = credential[0]
        let password = credential[1]
        let loginString =  NSString(format: "%@:%@", username, password)
        let loginData: NSData = loginString.dataUsingEncoding(NSUTF8StringEncoding)!
        let base64LoginString = loginData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions())
        myRequest.setValue("Basic \(base64LoginString)", forHTTPHeaderField: "Authorization")
        
        // Append JSON to request body
        myRequest.HTTPBody = try! NSJSONSerialization.dataWithJSONObject(json, options: [])
        
        // Excute HTTP Request
        let task = NSURLSession.sharedSession().dataTaskWithRequest(myRequest) { data, response, error in
            
            dispatch_async(dispatch_get_main_queue( )) {
                if data != nil {
                    completionHandler(data, nil)
                }else {
                    completionHandler(nil, error)
                    return
                }
            }
            
        }
        
        task.resume();
        
        return task
    }

REST API class

So we will create a simple class to call our HTTPRequest functions. Let's have a look at below codes.

class HTTPRequest {
    
    // Convert NSData to Dictionary
    class func convertToDict(jsonStr: NSData) -> NSDictionary {
        do {
            if let convertedJsonIntoDict = try NSJSONSerialization.JSONObjectWithData(jsonStr, options: []) as? NSDictionary {
                
                return convertedJsonIntoDict
                
            }
        } catch let error as NSError {
            print(error.localizedDescription)
        }
        return NSDictionary()
    }
    
    // GET Request
    class func sendGetRequest(url: String, credential: [String], completionHandler: (NSData?, NSError?) -> ()) -> NSURLSessionTask {
        
        // NSURL Object
        let myNSURL = NSURL(string: url)
        
        // URL Request
        let myRequest = NSMutableURLRequest(URL: myNSURL!)
        myRequest.HTTPMethod = "GET"
        
        // Basic Authorization
        let username = credential[0]
        let password = credential[1]
        let loginString =  NSString(format: "%@:%@", username, password)
        let loginData: NSData = loginString.dataUsingEncoding(NSUTF8StringEncoding)!
        let base64LoginString = loginData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions())
        myRequest.setValue("Basic \(base64LoginString)", forHTTPHeaderField: "Authorization")
        
        // Excute HTTP Request
        let task = NSURLSession.sharedSession().dataTaskWithRequest(myRequest) { data, response, error in
            
            dispatch_async(dispatch_get_main_queue()) {
                if data != nil {
                    completionHandler(data, nil)
                }else {
                    completionHandler(nil, error)
                    return
                }
            }
            
        }
        
        task.resume();
        
        return task
    }
    
    // POST
    class func sendPostRequest(url: String, credential: [String], json: Dictionary<String,String>, completionHandler: (NSData?, NSError?) -> ()) -> NSURLSessionTask {
        
        // NSURL Object
        let myNSURL = NSURL(string: url)
        
        // URL Request
        let myRequest = NSMutableURLRequest(URL: myNSURL!)
        myRequest.HTTPMethod = "POST"
        
        // Basic Authorization
        let username = credential[0]
        let password = credential[1]
        let loginString =  NSString(format: "%@:%@", username, password)
        let loginData: NSData = loginString.dataUsingEncoding(NSUTF8StringEncoding)!
        let base64LoginString = loginData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions())
        myRequest.setValue("Basic \(base64LoginString)", forHTTPHeaderField: "Authorization")
        
        // Append JSON to request body
        myRequest.HTTPBody = try! NSJSONSerialization.dataWithJSONObject(json, options: [])
        
        // Excute HTTP Request
        let task = NSURLSession.sharedSession().dataTaskWithRequest(myRequest) { data, response, error in
            
            dispatch_async(dispatch_get_main_queue( )) {
                if data != nil {
                    completionHandler(data, nil)
                }else {
                    completionHandler(nil, error)
                    return
                }
            }
            
        }
        
        task.resume();
        
        return task
    }

The class keyword before every function allows methods to be associated with class, so it can be called directly, for example, HTTPRequest.sendPostRequest.

The DELETE and PUT request are just the same as POST and GET so we just replicate the same code but change HTTPMethod to appropriate one.

Run it 

It's time to see some movement here. Opening the main.swift and add the following line of code, then run it to see what is going to happen.

// Declare a username and password
let credential = ["test", "1234"]

// Declare a GET URL
let getUrl = "https://demo9196980.mockable.io/getmymock"

// Declare a POST URL
let postUrl = "https://demo9196980.mockable.io/postmymock"

// Declare a POST data
let postData = ["username" : credential[0], "password" : credential[1]]

// Get it
HTTPRequest.sendGetRequest(getUrl, credential: credential) { response, error in
    if (response != nil) {
        let json =  HTTPRequest.convertToDict(response!)
        print("GET response \(json)")
        // Do something else you want here
        
    } else {
        print(error)
        // Handle error here
        
    }
}

// Post it
HTTPRequest.sendPostRequest(postUrl, credential: credential, json: postData) { response, error in
    if (response != nil) {
        let json =  HTTPRequest.convertToDict(response!)
        print("POST response \(json)")
        // Do something else you want here
        
    } else {
        print(error)
        // Handle error here
        
    }
}

NSRunLoop.mainRunLoop().run()

NSRunLoop.mainRunLoop().run() will stop the console from exit, so that the program will run forever to wait the async response.



In case you missed anything, try to have a look in this source code.

Don't hesitate to point out any mistakes in this tutorial. I'm not a super expert so I will try to fix it as soon as possible. So we can learn from each other :).

Feel free to share it if you find it useful.

Thanks


Unknown

Some say he’s half man half fish, others say he’s more of a seventy/thirty split. Either way he’s a fishy bastard. Google

0 comments: