SeaCat Tutorial - Chapter 3: Introduction to REST Integration (iOS)

Foreword

This article continues with practical demonstration of strength and capabilities of SeaCat (Mobile Secure Gateway) in our tutorial series.

In the previous article we created a simple host in Node.js where we were able to handle POST requests sent from a mobile application via SeaCat Gateway to our host.

The goal of this article is to extend the knowledge and develop an iOS application which is able to comunicate with REST interface provided by Node.js that we are going to create as well. A full integration with SeaCat is essential for information security of our example.

There are several points we would like to mention before we begin. The most important one is the switch from Objective-C to Apple new programming language so-called Swift [1], despite the fact the both languages are equally supported nowadays. The reason for this change is that we strongly believe that Swift is the future of iOS development and the sooner we start, the better.

For our convenience the Node.js part is now written in Express.js [2] framework. This lightweight Sinatra-like framework helps us to simplify the work with HTTP requests by wrapping the most common tasks into simple commands and get things done with less effort. For the same reason we decided to use AFNetworking [3] library on iOS side.

This application will be also extended and improved in future parts of this tutorial. We don't want you to be overwhelmed by new languages and frameworks and for this reason we decided to have data stored in-memory for this time. You can play with REST interface without any doubt until you decide to restart the Node.js host. This will change in the next tutorial where we use MongoDB for storing all our data.

Node.js host

The first step in our journey is to prepare Node.js host with REST interface. There are many ways how to do that: It can be written completely from scratch, however it is quite tedious job far out of scope of this article. To accelerate the way how we work with HTTP, we use Express.js. The following code is written in Node.js with Express.js and because of its length, the chunk of codes are split into several parts each with detailed explanation.

Installation of Express.js and Body-Parser libraries

To install both libraries is very straightforward. We assume you have already had Node.js installed and are familiar with concept of NPM modules. The only two things we need to do is run npm install express to install Express.js.

Express and Body parser installation

And for BodyParser installation just execute npm install body-parser.

Body parser installation

If you want to have these modules available globally, just add -g parameter (npm install -g express and npm install -g body-parser) but for the purpose of this tutorial this step is not necessary.

Script initialisation

Once we have Express.js and Body-Parser in place, we can start writing actual script. The first part is about initialisation.

// Include external modules - Express.js and BodyParser.
var express = require('express');
var bodyParser = require('body-parser');

// Initialise app by using Express framework.
var app = express();

// Use Body Parser (Helps to process incoming requests).
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());

// Set default port 1337 or custom if defined by user externally.
app.set('port', process.env.PORT || 1337);

In-memory objects

It has been already mentioned that we are not going use any persistent storage. All data will be stored in memory of Node.js process at this time. The API we are going to build is about movies. The objects which help us to handle data around that are mentioned below.

// Initialisation of movies array.  
var movies = [
    {
        id: 1,
        name: "Forrest Gump",
        director: "Robert Zemeckis",
        release: 1994
    },
    { 
        id: 2,
        name: "Donnie Darko",
        director: "Richard Kelly",
        release: 2001
    },
    {
        id: 3,
        name: "Inception",
        director: "Christopher Nolan",
        release: 2010
    }
];

// A simulation of creating new IDs. Basically get the last element and increase the value of an ID.

function getNewId(){
    return movies[movies.length -1].id + 1;
}

// Function findIndexOfElement helps to identify the array index according to specified key/value pair.

function findIndexOfElement(inputArray, key, value){
    for (var i = 0; i < inputArray.length; i++){
        if (inputArray[i][key] === value){
            return i;
        }
    }
return -1;
}

REST API interface

We are going to create interface which is able to work with following:

  • GET /api/movies - get a list of all movies stored in memory.
  • GET /api/movies/:id - get detail of particular movie using its id.
  • POST /api/movies - create a new movie entry.
  • PUT /api/movies/:id - update an existing movie entry.
  • DELETE /api/movies/:id - delete and existing movie entry.

The code which is able to handle this is covered below.

// GET - list of all records.
app.get('/api/movies', function(request, response){
    response.json(movies.map(function(movie){
        return {
            id: movie.id,
            name: movie.name,
            director: movie.director,
            release: movie.release
        }
    }));
});

// GET - list of a record with particular id. If not found, forward the request to 404 - not found. 
app.get('/api/movies/:id', function(request, response, next){  
    // Get an integer interpretation of URL parameter. 
    var urlIntParam = parseInt(request.params.id);
    // Check whether the element is a valid positive number.
    if (urlIntParam < 0 || isNaN(urlIntParam)){
        // Use following middleware - matched 404.
        next();
    }
    else {
        // Find array index in our movie array based on the input parameter (converted to integer).
        var elementIndex = findIndexOfElement(movies, 'id', urlIntParam);
        // If element exists, get the response, otherwise redirect to 404.
        if (elementIndex >= 0){
            // Get an object from movie array.
            var selectedMovie = movies[elementIndex];
            // Return JSON response with selected attributes.
            response.json({
                id: selectedMovie.id,
                name: selectedMovie.name,
                director: selectedMovie.director,
                release: selectedMovie.release
            });
        }
        else {
            // redirection to 404.
            next();      
        }
    }
});

// POST - create a new element.
app.post('/api/movies', function(request, response){
    // complete request body
    var requestBody = request.body;

    movies.push({
        id: getNewId(),
        name: requestBody.name,
        director: requestBody.director,
        release: requestBody.release
    });

    response.status(200).end();
});

// PUT - update existing element.
app.put('/api/movies/:id', function(request, response, next){
    // Get an integer interpretation of URL parameter.
    var urlIntParam = parseInt(request.params.id);
    // Check whether the element is a valid positive number.
    if (urlIntParam < 0 || isNaN(urlIntParam)){
        // Use following middleware - matched 404.
        next();
    }
    else {
        // Find array index in our movie array based on the input parameter (converted to integer).
        var elementIndex = findIndexOfElement(movies, 'id', urlIntParam);
        // If element exists, get the response, otherwise redirect to 404.
        if (elementIndex >= 0){
            // Update element accordingly.
            movies[elementIndex] = {
                id: urlIntParam,
                name: request.body.name,
                director: request.body.director,
                release: request.body.release
            };
            // Element successfuly updated.
            response.status(200).end();
        }
        else {
            // redirection to 404.
            next();
        }
    }
});

// DELETE - remove particular record from array.
app.delete('/api/movies/:id', function(request, response, next){
    // Get an integer interpretation of URL parameter. 
    var urlIntParam = parseInt(request.params.id);
    // Check whether the element exists or not. If not (following case, redirect the request to 404).
    if (urlIntParam < 0 || isNaN(urlIntParam)){
        // Use following middleware - matched 404.
        next();
    }
    else {
        // Find array index in our movie array based on the input parameter (converted to integer).
        var elementIndex = findIndexOfElement(movies, 'id', urlIntParam);
        // If element exists, get the response, otherwise redirect to 404.
        if (elementIndex >= 0){
            // Delete element according to index parameter.
            movies.splice(elementIndex, 1);
            // Element successfuly deleted.
            response.status(200).end();
        }
        else {
            // redirection to 404.
            next();
        }
    }
});

The error handling

The last part we are going to add is an error handling. Problems like non-existing resources (404) and server problems (500) are really simple to handle with Express.js and its middleware concept. It's quite complex topic, for now on just keep in mind we have to place following parts at the end of script (after all other routes from above).

// Use Express midleware to handle 404 and 500 error states.
app.use(function(request, response){
    // Set status 404 if none of above routes processed incoming request. 
    response.status(404); 
    // Generate the output.
    response.send('404 - not found');
});

// 500 error handling. This will be handled in case of any internal issue on the host side.
app.use(function(err, request, response){
    // Set response type to application/json.
    response.type('application/json');
    // Set response status to 500 (error code for internal server error).
    response.status(500);
    // Generate the output - an Internal server error message. 
    response.send('500 - internal server error');
});

Finalisation of the host script

The last piece of information we have to add is part for actual listening on the defined port.

// Start listening on defined port, this keep running the application until hit Ctrl + C key combination.

app.listen(app.get('port'), function(){
    console.log("Host is running and listening on http://localhost:" + app.get('port') + '; press Ctrl-C to terminate.');  
});

Once all of above is in one file, the script is done and ready to go. Full version of the script is available in GitHub as NodeRESTHost.js.

Running Node.js host

For running our script we have to just type node NodeRESTHost.js. The result should look like following:

Node.js running

SeaCat Gateway configuration

Let's configure the SeaCat Gateway which will handle the secure communication between the client (iOS) and host (Node.js + Express.js).

Download SeaCat trial installation package and unpack the content of that package by typing tar xjvf SeaCat_Trial_OSX_iOS_14.12.tar.bz2 in working directory in terminal.

SeaCat unpacking output in terminal

As the next step you have to modify the file seacat-trial.conf in SeaCat_Trial_OSX_iOS/SeaCatGateway directory. Change the default settings:

[host:test]
uri=http://127.0.0.1/

To the configuration represented by Node.js host settings (our host listens on port 1337).

[host:nodejshost]
uri=http://127.0.0.1:1337

We can also download the updated version of seacat-trial.conf from GitHub.

Once the changes in seacat-trial.conf are saved, we run the SeaCat Gateway by typing ./seacatd-trial in terminal window (the same working directory as seacat-trial.conf). If the output is similar to following:

SeaCat Gateway host running

SeaCat Gateway is configured correctly. Congratulations! We have to keep both Node.js host and SeaCat Gateway running.

iOS Mobile Application (Swift)

Now it's time to develop the iOS mobile application which communicate with SeaCat Gateway. Before we begin, it's important to check whether the system contains the latest Xcode version (everything >= 6.0.0 is fine). If the version is below the 6.0.0, the code examples for Swift won't compile.

Creating empty project and changing the default settings

To start a new project is simple. Just open Xcode and create a new project. From the list of available templates select Single View Application and click on the Next button.

Xcode opening

As a product name type RESTClient and make sure Swift is selected as language option. What you fill into other text fields is completely up to you. We still run our examples in Simulator and from this perspective other settings here really don't matter.

Xcode new project

Once you click on the Next button and save the project on the disk, you will see following screen.

Xcode new project created

Before we start with development, we have to change some of the default settings. We need to: Hide status bar and Change the launch screen to Main.storyboard. Make sure the settings look like in the picture below.

Xcode changed default settings

Another step is to get rid of default LaunchScreen.xib file. Just make a right-click on the file and select Delete from the available options.

Xcode changed default settings

Once the confirmation screen will appear, click on Move to Trash button and ged rid of this default screen.

Xcode changed default settings confirmation

Another step is to click on Main.storyboard (1), Show document outline (2) if hidden, select View Controller (3), show The file inspector (4) and uncheck Use Size Classes (5).

Xcode changed default settings confirmation

Once we do that, we have to confirm our intention by clicking on Disable Size Classes. This help us to establish the correct settings in automatic layout.

Xcode changed default settings confirmation

Including SeaCat.framework and AFNetworking

To include Objective-C libraries is a bit different with the new version of Xcode and Swift environment. The key thing is to include special ProjectName-Bridging-Header.h which help us to connect these two worlds.

In this application we are going to incorporate following frameworks:

Open the particular folders and move the files into our Xcode workspace. In case of AFNetworking there are several folders. For the purpose of our development we are interested in AFNetworking one (not UIKit+AFNetworking). Take this folder and drag it into workspace.

Xcode copying AFNetworking

Once we release mouse button, another dialog will appear. We have to make sure the option Copy items if needed is checked.

Xcode copying AFNetworking

By clicking on the Finish button, AFNetworking is added in the project structure.

Xcode adding AFNetworking

The situation with the SeaCat libraries is similar. The only difference is that we are adding a framework at this time. Open the folder with the client and drag the framework file in project structure.

Xcode adding SeaCat

Release the mouse button and make sure the destination Copy items if needed is checked.

Xcode adding SeaCat

Once we click on Finish button, SeaCat library will be added in the project like is shown in following picture.

Xcode adding SeaCat

The last step we have to do in this section is to create RESTClient-Bridging-Header.h file and include header files for both libraries. In the project group make a double-click and select a New File option.

Xcode adding a new header file

Selection of Header File is our choice in following screen. Confirm it by clicking on the Next button.

Xcode adding a new header file

Before you finally save the file, make sure the name is written as RESTClient-Bridging-Header and RESTClient checkbox is checked.

Xcode final creation of the file

Click on the Create button and the result will appear immediately.

Xcode final adding the file

The empty RESTClient-Bridging-Header file looks like:

#ifndef RESTClient_RESTClient_Bridging_Header_h
#define RESTClient_RESTClient_Bridging_Header_h


#endif

We have to update the file like:

#ifndef RESTClient_RESTClient_Bridging_Header_h
#define RESTClient_RESTClient_Bridging_Header_h

#import <SeaCatClientTrial/SeaCat.h>
#import "AFNetworking.h"

#endif

The last step in the configuration is to customise compiler settings. Basically what we have to do is to find Objective-C Bridging Header settings under Swift Compiler - Code Generation section. Click on the RESTClient group (1), select Build settings (2), extend the view to All (3) and find Objective-C Bridging Header option.

Changing the complier settings

Edit settings and add our header file as RESTClient-Bridging-Header.

Changing the complier settings

Now we are all set and we can start with the development itself. Quick compilation of the project by typing CMD + B helps to ensure that all libraries were added correctly. In case of any failure please check previous steps with your current settings.

Adding components to storyboard

Now it's time to add some actual components to storyboard. Let's start with the Labels. From the Object library find UILabel and place it to View Controller object.

First label

In the attribute inspector change the title to id: and confirm it.

First label

From the Object library find another UILabel and place it to View Controller object again.

Second label

In the attribute inspector change the title to name: and confirm it.

Second label

From the Object library find another UILabel and place it to View Controller object again.

Third label

In the attribute inspector change the title to director: and confirm it.

Third label

From the Object library find another UILabel and place it to View Controller object again.

Fourth label

In the attribute inspector change the title to release: and confirm it.

Fourth label

From the Object library find another UILabel and place it to View Controller object again.

Fifth label

In the attribute inspector change the title to response: and confirm it.

Fifth label

Not it's time to focus on UITextField objects. From the Object library choose one and place it to View Controller object.

First TextField

From the Object library select the second one and place it to View Controller object again.

Second TextField

From the Object library select the third one and place it to View Controller object again.

Third TextField

From the Object library select the fourth one and place it to View Controller object again.

Fourth TextField

From the Object library select the fifth (last) one and place it to View Controller object again.

Fifth TextField

Before any further development, we should make better alignment of our components.

Changing layout first part

Our result should look like the picture below.

Changing layout second part

Select the first Text Field and focus on Font and Placeholder text.

TextField1

Set the font size to 12 and Placeholder text to specify numeric ID.

TextField1

Select the second Text Field and focus on Font and Placeholder text again.

TextField2

Set the font size to 12 and Placeholder text to specify a movie name.

TextField2

Select the third Text Field and focus on Font and Placeholder text again.

TextField3

Set the font size to 12 and Placeholder text to specify a movie director.

TextField3

Select the fourth Text Field and focus on Font and Placeholder text again.

TextField4

Set the font size to 12 and Placeholder text to specify a year of release.

TextField4

Select the fifth Text Field and focus on Font and Enabled checkbox.

TextField5

Set the font size to 12 and uncheck Enabled option.

TextField5

To make the UX more interactive, select UISegmentedControl from Object library and place it to View Controller object.

Segmented Control

There are 2 parts to focus on. Segments and Segment Title.

Segmented Control1

Change Segments number to 4 and title to GET.

Segmented Control1

Select the second segment from the list.

Segmented Control2

Change the default title to POST.

Segmented Control2

Select the third segment from the list.

Segmented Control3

Change the default title to PUT.

Segmented Control3

Select the fourth segment from the list.

Segmented Control4

Change the default title to DELETE and make the size a little bit wider.

Segmented Control4

From the Object library select the UIButton and place it to View Controller object.

Button

Change the title to Send Request.

Button

The view should look like following:

Layout general overview

Select every object (command key + a).

Selection all objects

Once objects selected, go to Editor -> Embed in and click on View.

Embeded in

This will collect every object into 1 group which helps with the layout settings.

Merge objects

Click on Pin button and add width and height constraints as following.

Adding constrains

Click on align button and add two more constraints - horizontal and vertical center in container.

Adding two more constrains

Click on View Controller and in Simulated Metrics in Attribute Inspector set the status bar to None.

Disabling status bar

The final layout result will look like following:

Final layout result

Connect objects in storyboard with code in ViewController.swift

The part we are going to focus on right now is the connection between Main.storyboard and ViewController.swift. Open the ViewController.swift.

Open view controller code

And add following code:

@IBOutlet weak var idTextField: UITextField!
@IBOutlet weak var nameTextField: UITextField!
@IBOutlet weak var directorTextField: UITextField!
@IBOutlet weak var releaseTextField: UITextField!
@IBOutlet weak var verbInSegmentedControl: UISegmentedControl!
@IBOutlet weak var responseTextField: UITextField!

We can see the small empty circles. This is indicator of a need for connection.

Adding IBOutlets

Click on yellow icon (View Controller specific one), push control button and drag the mouse into id text field.

Connection IBOutlets

From the submenu select idTextField.

Connection IBOutlets

Click on yellow icon (View Controller specific one), push control button and drag the mouse into name text field.

Connection IBOutlets

From the submenu select nameTextField.

Connection IBOutlets

Click on yellow icon (View Controller specific one), push control button and drag the mouse into director text field.

Connection IBOutlets

From the submenu select directorTextField.

Connection IBOutlets

Click on yellow icon (View Controller specific one), push control button and drag the mouse into release text field.

Connection IBOutlets

From the submenu select releaseTextField.

Connection IBOutlets

Click on yellow icon (View Controller specific one), push control button and drag the mouse into connecting response text field.

Connection IBOutlets

From the submenu select responseTextField.

Connection IBOutlets

Click on yellow icon (View Controller specific one), push control button and drag the mouse into connecting segmented control.

Connection IBOutlets

From the submenu select verbInSegmentedControl.

Connection IBOutlets

After all important objects are connected, we will see the circles filled.

IBOutlets connected

Finishing the application

We need to complete our application by adding some code. Let's start with creating an instance of AFHTTPRequestOperationManager class.

import UIKit

class ViewController: UIViewController {
    let manager = AFHTTPRequestOperationManager()
    .
    .
    .

Another step is to update viewDidLoad() by adding some method calls (we haven't added these methods yet).

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    // Manage Accesibility for UITextFields just after the initialisation.
    manageAccessibilityForUITextFields(verbInSegmentedControl.selectedSegmentIndex)
    dataCleaningForUITextFields()
}

We are also going to add our own method manageAccessibilityForUITextFields(verb: Int). This will help us to lock/unlock our UITextField elements based on selected HTTP method (GET/PUT/POST/DELETE).

func manageAccessibilityForUITextFields(verb: Int) {
    switch verb {
        // We are going to handle UITextFields based on GET (index 0).
    case 0:
        idTextField.enabled = true
        nameTextField.enabled = false
        directorTextField.enabled = false
        releaseTextField.enabled = false
        // We are going to handle UITextFields based on POST (index 1).
    case 1:
        idTextField.enabled = false
        nameTextField.enabled = true
        directorTextField.enabled = true
        releaseTextField.enabled = true
    case 2:
        // We are going to handle UITextFields based on PUT (index 2).
        idTextField.enabled = true
        nameTextField.enabled = true
        directorTextField.enabled = true
        releaseTextField.enabled = true
        // We are going to handle UITextFields based on DELETE (index 3).
    case 3:
        idTextField.enabled = true
        nameTextField.enabled = false
        directorTextField.enabled = false
        releaseTextField.enabled = false
        // Enabled all fields in Default.
    default:
        idTextField.enabled = true
        nameTextField.enabled = true
        directorTextField.enabled = true
        releaseTextField.enabled = true
    }
}

Another method helps us to clean UITextFields once any action is done.

func dataCleaningForUITextFields() {
    // Clean all fields in every situation.

    idTextField.text = String()
    nameTextField.text = String()
    directorTextField.text = String()
    releaseTextField.text = String()
    responseTextField.text = String()
}

Method populateTextFields(responseObject: AnyObject!) reads the response and populate the text fields with the content.

func populateTextFields(responseObject: AnyObject!) {
    let jsonResult = responseObject as Dictionary<String, AnyObject>
    nameTextField.text = String(jsonResult["name"] as AnyObject! as String)
    directorTextField.text = String(jsonResult["director"] as AnyObject! as String)
    releaseTextField.text = String(jsonResult["release"] as AnyObject! as Int)
}

We call func displaySuccessMessage(message: String) and func displayErrorMessage(message: String) methods basically whenever we need to send some message to response text field.

func displaySuccessMessage(message: String) {
    self.responseTextField.textColor = UIColor.darkGrayColor()
    self.responseTextField.text = message
}

func displayErrorMessage(message: String) {
    self.responseTextField.textColor = UIColor.redColor()
    self.responseTextField.text = message
}

Method getRequest() basically process a GET request. Read defined ENDPOINT based on specified parameter.

func getRequest() {
    var id: String = idTextField.text
    if countElements(id) == 0 {
        displayErrorMessage("ID element is empty")
    }
    else
    {
        manager.GET("https://nodejshost.seacat/api/movies/\(id)",
            parameters: nil,
            success: {(operation: AFHTTPRequestOperation!, responseObject: AnyObject!) in
                let message = "Data received successfully!"
                self.populateTextFields(responseObject)
                self.displaySuccessMessage(message)
            },
            failure: {(operation: AFHTTPRequestOperation!, error: NSError!) in
                self.dataCleaningForUITextFields()
                let message = error.localizedDescription
                self.responseTextField.textColor = UIColor.redColor()
                self.responseTextField.text = message
        })
    }
}

Method postRequest() basically do a POST request. Send data to defined ENDPOINT.

func postRequest() {
    var name = nameTextField.text
    var director = directorTextField.text
    var release = releaseTextField.text
    var parameters = ["name": name, "director": director, "release": release]

    manager.POST("https://nodejshost.seacat/api/movies",
        parameters: parameters,
        success: {(operation: AFHTTPRequestOperation!, responseObject: AnyObject!) in
            let message = "Data successfully sent!"
            self.displaySuccessMessage(message)
        },
        failure: {(operation: AFHTTPRequestOperation!, error: NSError!) in
            self.dataCleaningForUITextFields()
            let message = error.localizedDescription
            self.responseTextField.textColor = UIColor.redColor()
            self.responseTextField.text = message
    })
}

Method putRequest() basically do a PUT request. Send updated data to defined ENDPOINT based on specified id element.

func putRequest() {
    var id = idTextField.text
    var name = nameTextField.text
    var director = directorTextField.text
    var release = releaseTextField.text
    var parameters = ["name": name, "director": director, "release": release]

    if countElements(id) == 0 {
        displayErrorMessage("ID element is empty")
    }
    else {
        manager.PUT("https://nodejshost.seacat/api/movies/\(id)",
            parameters: parameters,
            success: {(operation: AFHTTPRequestOperation!, responseObject: AnyObject!) in
                let message = "Data successfully sent!"
                self.displaySuccessMessage(message)
            },
            failure: {(operation: AFHTTPRequestOperation!, error: NSError!) in
                self.dataCleaningForUITextFields()
                let message = error.localizedDescription
                self.responseTextField.textColor = UIColor.redColor()
                self.responseTextField.text = message
        })
    }
}

Method deleteRequest() basically do a DELETE request. Delete data in defined ENDPOINT based on specified id element.

func deleteRequest() {
    var id = idTextField.text
    if countElements(id) == 0 {
        displayErrorMessage("ID element is empty")
    }
    else {
        manager.DELETE("https://nodejshost.seacat/api/movies/\(id)",
            parameters: nil,
            success: {(operation: AFHTTPRequestOperation!, responseObject: AnyObject!) in
                let message = "Object successfully deleted!"
                self.displaySuccessMessage(message)
            },
            failure: {(operation: AFHTTPRequestOperation!, error: NSError!) in
                self.dataCleaningForUITextFields()
                let message = error.localizedDescription
                self.responseTextField.textColor = UIColor.redColor()
                self.responseTextField.text = message
        })
    }
}

There are two more methods we need to implement. Adding these methods help us to manage the actions and we can simply check the state of segmented control or button.

@IBAction func selectVerbInSegmentedControl(sender: AnyObject) {
    manageAccessibilityForUITextFields(sender.selectedSegmentIndex)
    dataCleaningForUITextFields()
}

@IBAction func sendRequest(sender: AnyObject) {
    switch (verbInSegmentedControl.selectedSegmentIndex)
    {
        case 0:
            self.getRequest()
        case 1:
            self.postRequest()
        case 2:
            self.putRequest()
        case 3:
            self.deleteRequest()
        default:
            println("Undefined request")
    }
}

We have to return back to Main.storyboard and click on the UISegmentedControl. Then Push control key and drag mouse into View Controller icon.

Action connection #1

From the context menu we have to choose selectVerbInSegmentedControl: option.

Action connection #2

One of the last thing is clicking on the UIButton Send Request. Then we have to push control key and drag mouse into View Controller icon again.

Action connection #3

From the context menu we have to choose sendRequest: option.

Action connection #4

Open AppDelegate.swift in Xcode and focus on following method:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    // Override point for customization after application launch.

    return true
}

Update it as following

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    // Override point for customization after application launch.
    SeaCatClient.configure()

    return true
}

Running the application

We are done from the implementation point of view. Now it's time to play with our application. After run in the simulator we can see following result:

Simulator #1

Once we specify a certain id, we will get desired result.

Simulator #2

We can try to delete an element with certain id as well.

Simulator #3

If we try to select that deleted record, the element won't be available any more.

Simulator #4

And so on! Pretty cool, isn't it? You can download the whole application from GitHub.

Conclusion

We basically built a really simple application using a REST interface. There is still some missing pieces like advance error handling. In following tutorials we will improve the application step by step and get more advance features. Enjoy!

Reference:

  1. https://developer.apple.com/swift
  2. http://expressjs.com
  3. http://afnetworking.com

SeaCat iOS tutorials in this series:

  1. Chapter 1: Hello World
  2. Chapter 2: Simple Post
  3. Chapter 3: Introduction to REST Integration
  4. Chapter 4: Using MongoDB with REST Integration
  5. Chapter 5: Using Parse.com with REST Integration

About the Author

Ales Teska

TeskaLabs’ founder and CEO, Ales Teska, is a driven innovator who proactively builds things and comes up with solutions to solve practical IT problems.




You Might Be Interested in Reading These Articles

Entangled ways of product development in the area of cybersecurity #1 - Asynchronous or parallel?

I started working at TeskaLabs at the beginning of autumn 2017 as a student at the Faculty of Information Technology of CTU. In the job advertisement, I was particularly interested in the fact that it is a small, product-based company that does not focus on just one technology or one programming language.

Continue reading ...

development tech premek

Published on November 15, 2022

And the winner is...Go!

What compiled language for a backend development is the right one to move our technological stack to the next level? We've started to look around for a compiled computer language that will enable us to build microservices with higher performance. Now, don't get me wrong, we don't depart from Python at all. It is the extension of the portfolio.

Continue reading ...

development tech

Published on November 15, 2021

Entangled ways of product development in the area of cybersecurity #3 - LogMan.io

At that time I lived in Prague for a short time, which is not a very friendly place to live, but it allowed me to go to the office almost every day. A bigger surprise awaited Vlaďka and Aleš when I told them that I was going to move to a house almost eighty kilometres from the office and that I would need to be mainly at the home office.

Continue reading ...

development tech premek

Published on January 15, 2023