Archive for August, 2016

Building a Simple RESTful Web Service and Consuming it with an iOS app

28/08/2016

Most of the projects that I work on contain two separate parts. The first one is the Java back-end. This gets the requests from the front-end and generates the outputs either in JSON, XML, PDF or XLS format. The second part is the front-end, which interacts with the user. It gets the input, presents the menus and actions and shows the output to the user. This flow is great since the two parts do not depend on each other. That way, we can swap the server side whenever and however we wish, provided that the contract between it and the UI side is preserved. That is also true for the front-end. If, somehow, the technology we preferred is not supported any more, we have the freedom to replace it possibly without changing a single line of server code.
In theory, there is no difference between practice and theory but in practice, there is. The previous paragraph seems all good in theory. But I would like to test if this is also true in practice. Nowadays, I am exploring iOS development and trying to learn Swift. Hence, my current aim is to convert one of our simple JavaScript interfaces to an iOS app. Working on a toy example will be my first step. So I started with building a very small RESTful web service. and moved on to consuming it with an iOS app.
That was a little bit strange though. I prefer using Eclipse with Maven and walked through the web service generation example accordingly and the things flew as I hoped for. However, while creating the iOS app, I hit a few problems and in this post, I would like to share my setup and solutions.

Producer: RESTful Web Service

The RESTful web service creating is in fact quite strait-forward. I have only downloaded the full code from Spring github repository. There contains three phases of the same gs-rest-service project. We will use the complete one. As always, my preference was to use Eclipse with Maven so I selected only the src/ folder and pom.xml file to copy into my workspace.

Here is the complete project

The selected code to be included

After selecting the necessary components, we need to create a project inside the workspace. Frankly, we only import the codes and Eclipse do the rest to make a project out of them. We first copy the selected codes to a project folder in the workspace. We can also put the whole downloaded Spring code and remove the folders that we do not need. Whatever way you choose, eventually your workspace will have your project folder, which only contains the src/ folder and the pom.xml file we have selected previously. Now we are ready to import them as our project.

Starting to import

We will use the wizard “Projects from Folder or Archive”. It will understand that it is a Maven project so the whole process will take too little time to complete.

Project import wizard that we will use

Maven Project

So we have our project ready to be update. Since it is a Maven project, it will be really convenient to update the project and download the jar files that the projects depends on. At the end, the whole content of the project should look like below:

The internals of the project

The code is compatible with Java 1.8 so we do not need to change anything. Up from the start, it is ready to run. First, we will run it inside Eclipse. The main() method resides in Application.java class.

Running the service from Eclipse

It has an embedded Tomcat server so we do not need to define an explicit server and deploy the project onto it. As you can see, we can simply run the main() method. This also make us to just make a jar out of it and run on different computers (having a JVM of course) by copying. To do that, we can follow my one of my previous posts and add a new running configuration.

Running mvn command implicitly

The mvn clean package command

Once you run that configuration successfully, a jar file that can be run directly by double clicking should be created under the target/ folder of your project.

The executable

Either from Eclipse or by double clicking the jar, the service starts and does nothing that can be perceived. We must somehow make a request to it and get its response. That is how RESTful services work. To test it, we only need a browser. This service only accepts one type of request and we will provide it by a URL. That principle will be the same while building our iOS app in the next steps or any other app that wants to use this service. This all means that our RESTful service made the all any other services using it independent of its internal dynamics. That is a good thing to achieve.

Testing the service

That is it. We have our RESTful server app that can even run as a standalone executable. What we see is that a JSON object. It can be thought to be a some kind of a dictionary, which will turn out to be true. When we want to get “id” information, it tells us that it is the integer 3. When we want to get the “content” information, it tells us that it is the String “Hello World!”. Any other query will yield to a nil, because there is no other key-value pair.

Now the easy and essential step is just behind, we can turn our attention to construct a way to consume it as an iOS app.

Consumer: iOS App

While coding the iOS app, I am using the Xcode 8.0 beta 6 (8S201h) build and Swift 3.0. The coding process is fundamentally the same with this tutorial. However, it is written with Objective-C and more importantly, before iOS 9 came out. Hence, we will see differences because of the language we use and also tackle with an important problem.

Single View Application

Details to be filled

We will build a very basic Single View Application. The Xcode provides us a nice wizard to create a template. You can fill in the Product Name and Organization Identifier however you see fit. At the end, we will have the following structure. We will only modify the Main.storyboard and ViewController.swift files. The others stay the same as in their creations.

The internals of iOS app

The Storyboard

Our app will have a button, which makes a request and fetches the response. After getting the response, it will identify the “id” and “content” information and put them into their respective label fields. This way, we will be sure that a network traffic has occurred, the service returned the result of our query and the app printed it successfully.

So the storyboard will contain 5 labels. The two of them will be filled by the app but the remaining 3 are fixed. The fixed ones are just placeholders to identify the fields we will be updating. The board will also include an action button.

View Controller

It is not the best practice to make network calls inside a view controller but to keep things as simple as possible and focus on our main objective, I will follow the same steps as in the Spring tutorial.
The outline of the controller code is:
– Generate the query URL
– Asynchronously (that is critical) send the query to the RESTful service.
– When a response comes from the service, check it if it is successful.
– If so, parse it with a JSON parser
– If not, write the error to the console
Writing to console is meaningless to the users of the app since they will not have the opportunity to see any of that. Logging it to a file or presenting it as a message to the user should be the way to go. Here we will only print it to our console for again simplicity.
The input/output (i/o) operations of any app requires special consideration. The fluidity of interfaces, especially in iOS apps and Apple products, is may be the biggest indicator about the quality of the app or platform. Not to hinder that butter smooth interaction, the apps should handle the background i/o tasks as least obtrusive as possible. Especially network interactions depend on many parameters that can easily fail or take too much time to succeed. It is nearly impossible to run them on the same thread which also takes care of the GUI.
The solution is using asynchronous i/o. What goes on is that, the app sends whatever information it wants to send in another thread and waits for the answer while user interaction still goes on the main thread. That way, the user is not required to wait for the answer indefinitely. Rather, she can continue to use the other features of the app, interact with it device and when the response is ready, the waiting thread can process it or asks any other thread (even to the main one) to process it.
For this purpose, we will be using session.dataTask() method. There are two thing that we must know about it.
– First, it always starts in a suspended state. So, only making a declaration and initialization is insufficient. We must explicitly tell it to start. That is where dataTask.resume()method comes in
– Second, since the timing and control of the response of the asynchronous request is out of our hands, we must provide a handler / listener type of code to the request sender. Then, it will know for sure what to do when the response comes in. For our case, a Swift closure provided as thecompletionHandler“` parameter exactly fills this very specific role.
Below is the first version of the code, which makes the request-response traffic and inspects what response has. It does not update the storyboard.

Traffic code

There are a few things to talk about before moving forward. The closures in Swift are part of codes that are self contained and can be run whenever are provided to a method. Here, the closure that we use has three parameters. error informs us if there is something going wrong. If that is ok, we got a response. This does not mean that everything is ok. We must be sure about the status of the response. There are different HTTP response codes. We can check each of them in our code for robustness. The ones with code 200 indicate the response is a success. At that time can we be sure about the data part. We simply get a dictionary version of the JSON data by means of the JSONSerialization class. So we can get the values in it by querying with the keys. This helps us in extracting the necessary information to fill in the storyboard. The whole picture after this step is below.

The code-storyboard connection

When I run this, I expected to see the id and content inside the labels in storyboard but I hit an important problem.

Uppss ATS

Actually it is not a problem but a precaution taken by Apple.App Transport Security is a security measure which defaults to blocking non-HTTPS network traffic. By the time the Spring iOS consumer tutorial was written, I think that this was not functional. But we need to deal with that now. I got the help from this post What we are to do is add exceptions inside the info.plist file. When the project is first created by the wizard, the content of the info.plist file is like this:

Default info.plist file

Step by step we will add 3 dictionaries one under another and set two parameters to TRUE. I am using localhost as my server but if you use another, feel free to change it accordingly. Here is the eventual state:

info.plist with exceptions

So we are now ready to go. Our network traffic is given permission and we can send our request and get the successful response. But there is something amiss, isn’t it?

Where is the ID?

Here, the problem is that, we ID field as a String but it is an Int in reality. Just change the code to cast it into Int as follows:

Casting to Int

Now it is an Int. Running the app again and the picture is… What?

Optional?

Swift has an interesting feature. It is called Optionals. It protects the developer not to deal with unknown or nil data. In our case, since the dictionary returns totally optional objects, the Int we got is actually an Optional Int. We clearly, and unintentionally, see that in our little label. While casting it into Int, we must state that, that object is always different than nil. We guarantee it with the Exclamation Mark symbol. Here is the very small but important change in the code.

Little mark does what we want

At last here is our thought to be simple but turned out to be a valuable example app in all its glory.

The final

I just learnt a lot both in the server Java application and in the iOS app. I will definitely try to implement more on these. Hope you also had fun.

Advertisements