How to make REST API calls and Parse Json with Swift

How to make REST API calls and Parse Json with Swift

  • 2016-08-16
  • 5879

How to parse JSON with Swift we think about dictionaries and ugly code getting to the values of a REST API response. This processs can be made a lot cleaner and structured using a simple library and a REST response wrapper class.

Some time ago I had the post How to Make REST API Calls and Parse JSON with Swift, which was for an older Swift version and also using an older SwiftyJSON implementation. Today I will show you how to parse JSON with Swift 2.2 using SwiftyJSON through cocoapods and the Randomuser API for a dummy JSON response.

Setup the app and cocoapods

We start with a clean App so start Xcode, go ahead and Create a new Project and select the Single View Application. Insert your credentials and whatever name you like and finish the process.

As said before, this time we will use cocoapods which is a dependency manager for iOS libraries to install a pod called SwiftyJSON. This library helps us to parse JSON with Swift a lot easier.

To install cocoapods, follow the instruction on the official cocoapods website. Afterwards, create a Podfile at the rot of your blank project and insert:

Podfile to install SwiftyJSON

platform :ios, '8.0'
use_frameworks!
 
target 'devdactic-rest' do
  pod 'SwiftyJSON', :git => 'https://github.com/SwiftyJSON/SwiftyJSON.git'
end

This is a very simple Podfile, we just specify the target name (which was in my case devdacti-rest) and the Pod we want to install plus the git source. Save this file and run pod install from your command line.

If this finishes successful, please use the *.workspace file from now on as this includes your original target and the Pods target.

Note: We have to specify use_frameworks! in our Podfile because SwiftyJSON is a Swift Pod.

If you want all of the code of this tutorial, grab your complete package below!

The final app with some dummy data will look like this:

enter image description here

Creating our REST Connection Manager

I love having all of my REST calls in one place, so inside your project create a new Swift file called RestApiManager.

In this class we will talk to the Randomuser API and see how to perform a simple GET and POST request with Swift. Open your created file and insert:

Our REST API Manager singleton

import SwiftyJSON
 
typealias ServiceResponse = (JSON, NSError?) -> Void
 
class RestApiManager: NSObject {
    static let sharedInstance = RestApiManager()
 
    let baseURL = "http://api.randomuser.me/"
 
    func getRandomUser(onCompletion: (JSON) -> Void) {
        let route = baseURL
        makeHTTPGetRequest(route, onCompletion: { json, err in
            onCompletion(json as JSON)
        })
    }
 
    // MARK: Perform a GET Request
    private func makeHTTPGetRequest(path: String, onCompletion: ServiceResponse) {
        let request = NSMutableURLRequest(URL: NSURL(string: path)!)
 
        let session = NSURLSession.sharedSession()
 
        let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
            if let jsonData = data {
                let json:JSON = JSON(data: jsonData)
                onCompletion(json, error)
            } else {
                onCompletion(nil, error)
            }
        })
        task.resume()
    }
 
    // MARK: Perform a POST Request
    private func makeHTTPPostRequest(path: String, body: [String: AnyObject], onCompletion: ServiceResponse) {
        let request = NSMutableURLRequest(URL: NSURL(string: path)!)
 
        // Set the method to POST
        request.HTTPMethod = "POST"
 
        do {
            // Set the POST body for the request
            let jsonBody = try NSJSONSerialization.dataWithJSONObject(body, options: .PrettyPrinted)
            request.HTTPBody = jsonBody
            let session = NSURLSession.sharedSession()
 
            let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
                if let jsonData = data {
                    let json:JSON = JSON(data: jsonData)
                    onCompletion(json, nil)
                } else {
                    onCompletion(nil, error)
                }
            })
            task.resume()
        } catch {
            // Create your personal error
            onCompletion(nil, nil)
        }
    }
}

As we only want to expose the functions we need, we make our GET and POST request methods private.

We also define a typealias for all of our responses, which will always consist of the JSON object and an optional NSError.

There is nothing really special in here, we just make plain HTTP calls and can pass the data object directly into the initializer of SwiftyJSON.

If you have any questions to the implementation of the REST Manager, please leave a comment below!

Parse JSON with Swift

Now that we got the backbone of our app, we take care of the View. But before we actually craft the final view, we create a wrapper for our REST response. To parse JSON with Swift we could only rely on SwiftyJSON, which makes life already a lot easier.

To get to a stage of even better understandable code I recommend to create wrappers for your responses. By doing this you only have to access values by their name once in the init of the object. This means, if anything changes from the backend side, you only have to change it in one location in your app.

This can save a big amount of time in big projects, plus using the objects from then on is a lot friendly for everyone reading and working with your code.

So enough words, create a UserObject Swift file and insert:

UserObject class to wrap the REST response

import SwiftyJSON
 
class UserObject {
    var pictureURL: String!
    var username: String!
    
    required init(json: JSON) {
        pictureURL = json["picture"]["medium"].stringValue
        username = json["email"].stringValue
    }
}

The values we access can be seen in the response of the Randomuser API, for now we just use the name and an image. Let’s see how to create our user objects from our controller.

UPDATE: We need to use the “email” field now as the “name” field seems to be empty.

Inside your project you should already have a quite empty ViewController, so we can use that one for our tableView.

We want to display all the users we receive from the API inside a simple UITableView. Additionaly we want to have a little button to reload more users into our list. A POST request would have no effect on the Randomuser API side, so we just focus on get and creating our objects now.

Open your ViewController and replace everything inside with:

The TableViewController of our app

import UIKit
import SwiftyJSON
 
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
 
    var tableView: UITableView!
    var items = [UserObject]()
 
    override func viewWillAppear(animated: Bool) {
        let frame:CGRect = CGRect(x: 0, y: 100, width: self.view.frame.width, height: self.view.frame.height-100)
        self.tableView = UITableView(frame: frame)
        self.tableView.dataSource = self
        self.tableView.delegate = self
        self.view.addSubview(self.tableView)
 
        let btn = UIButton(frame: CGRect(x: 0, y: 25, width: self.view.frame.width, height: 50))
        btn.backgroundColor = UIColor.cyanColor()
        btn.setTitle("Add new Dummy", forState: UIControlState.Normal)
        btn.addTarget(self, action: "addDummyData", forControlEvents: UIControlEvents.TouchUpInside)
        self.view.addSubview(btn)
    }
 
    func addDummyData() {
        RestApiManager.sharedInstance.getRandomUser { (json: JSON) in
            if let results = json["results"].array {
                for entry in results {
                    self.items.append(UserObject(json: entry))
                }
                dispatch_async(dispatch_get_main_queue(),{
                    self.tableView.reloadData()
                })
            }
        }
    }
 
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.items.count;
    }
 
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var cell = tableView.dequeueReusableCellWithIdentifier("CELL")
 
        if cell == nil {
            cell = UITableViewCell(style: UITableViewCellStyle.Value1, reuseIdentifier: "CELL")
        }
        let user = self.items[indexPath.row]
 
        if let url = NSURL(string: user.pictureURL) {
            if let data = NSData(contentsOfURL: url) {
                cell?.imageView?.image = UIImage(data: data)
            }
        }
        cell!.textLabel?.text = user.username
        return cell!
    }
}

As you can see, a very straight forward UITableView with an items array for our users and a UIButton to call addDummyData.

Inside this function we call the singleton instance of our RestApiManager an use the JSON result as an array from which we create a new UserObject for each entry.

In only a few lines we have added a lot of logic and parsing and can now use the Object in the standard Swift way!

That’s what I really like about doing it this way. If you look at the cellForRowAtIndexPath function, you see how easy we can access the name and image of a user now, plus some if let logic to only load data into an image that really exists.

Now go ahead an run your app!

UPDATE: If you encounter “Transport Security Has Blocked a cleartext http….” which you will for sure, you should edit your .plist file and add App Transport Security Settings and under App Transport Security Settings set Allow Arbitrary Loads to Yes.

See how in this Stackoverflow post.

Thanks again to Jasper for reporting this!

Conclusion

JSON parsing with Swift can be quite easy using the right approach. In general you don’t want to access the variables inside the JSON often by using the string names, that’s why it’s a good approach to seperate this logic into wrapper classes or structs you can use after creating the initial object from JSON!

Suggest

Swift 3 and iOS 10 Tutorial Learn to Code like a Pro

The Complete iOS 10 Developer Course Build 21 Apps

iOS 10 & Swift 3: From Beginner to Paid Professional

Swift 3 Tutorials - Learn to Code Like a Pro

Make a Chat App! (Firebase : Swift in Xcode)