JSON data example

in Backend, Swift

Swift on servers 101 – Swift Express


As I said in one of my previous posts, Swift has come a long way since it was first introduced in June 2014. In this tutorial we’ll see how useful Swift is for developing web applications by trying to create a fully functional website with API calls, HTML structure, CSS style and JavaScript plugins. For this experiment I’ve chosen Swift Express, framework developed by crossroadlabs which already has a (growing) community and few beta releases on github.

By the end of this tutorial we will create a responsive 9gag clone which will have some funny images on the home page fetched by an async call using only Foundation framework from Swift and SwiftExpress.

Instaling Swift express
First step is to install Swift Express on your machine. This tutorial will focus on OS X platform but apart from installation process the actual code should run just fine on any recent Linux distribution. First thing that we need to install package manager for OS X called Brew. If you’ve done any development with iOS you should be familiar with Brew but just in case I’ll cover this step as well. Brew is installed very easily, simply copy the following code into your terminal:

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

This will allow you to install various packages, dependencies and gems. Next, copy the following two lines in your terminal to install Swift Express:

brew tap crossroadlabs/tap
brew install swift-express

With this you are ready to start developing web applications in Swift.

Creating application files
Again inside your terminal you have to type few commands which is a straightforward process like in any other framework.

swift-express init HelloWorldFromExpress
cd HelloWorldFromExpress
swift-express bootstrap

I am naming my application HelloWorldFromExpress but you can name yours any way you like. This will create all the files inside your root directory unless you specify the location. Final step is to build the application and run it. At the moment of writing this tutorial building application from Xcode will not work, so you have to do it manually through terminal.

swift-express build
swift-express run

Open your browser and type http://localhost:9999/. If everything is okay you should see a welcome message like on the image below:

Welcome to Swift Express screen

Welcome to Swift Express screen

One thing that you should take into consideration is that building and running Swift Express application after you’ve already built it on the same port will not trigger the update, because the port was in use. To solve this problem, you can chain terminal commands in the following order: kill all processes on the given port, build changes if any, run applicaiton on the same port. The terminal command will look like this:

sudo kill -kill `lsof -t -i tcp:9999`; swift-express build; swift-express run 

Note that you need sudo permissions to chain commands in terminal. My recommendation is to always use instead this approach, even though Swift Express documentation has not addressed this issue at all which I found a bit strange.

File structure and organization
Swift Express has a very basic structure similar to most web frameworks. There are three main folders: app, views and public, something which you might expect to find in any MVC based arhitecture. Inside the app folder you will find a file called main. This file handles all the routes, Stencil init and so on. By default you get a home route which presents index page. App folder is the folder where all your models and controllers should be put. Views folder will have all the HTML files. Swift express uses Stencil as a view rendering engine. Finally, folder public will contain all your CSS, JavaScript and static images.

HomeController
We could write all of our code inside the main class but for any serious development this would of course after few routes become quite hard to maintain, so let’s start by creating a new class called HomeController. Before that create two groups inside app folder and name them Models and Controllers so we get a nice code structure. Your application should now look something like this:

Initial application organization

Initial application organization

Now create a new class function called index and for now just copy everything from the default home route provided in the main file so we can test things out.

class func index() -> Action {
    return Action.render("index", context: ["hello": "Hello,", "swift": "Swift", "express": "Express!"])
}

Go back to your main.swift file and replace the default route code with the following:

app.get("/") { request in
    return HomeController.index()
}

As you can notice we created a nice simple routing system allowing us to structure the code into logical groups. Build and run your swift express application and refresh the browser, everything should stay the same.

Next, go to your Info.plist file, open it as source code and add the following at the bottom:

Info.plist modification allow the usage of HTTP API endpointa

Info.plist modification allow the usage of HTTP API endpointa

This will allow us to fetch data from API source which does not use HTTPS. For production application this is not recommended but it will save us some time of registering to a service, adding tokens, handling expiry of the token and so on. The API that we will use is InfiniGAG API (you can chacke the git repo here).

Fetching data
Next step is to actually fetch the data. For that we will use NSURLSession, but if you prefer, you can import Alamofire, or any other library available on Carthage. Inside our HomeController at the top create two variables:

let urlAsString = "http://infinigag.k3min.eu/trending"
let urlSession = NSURLSession.sharedSession()

First variable is the API url which contains trending photos from 9GAG, and the second is the reference to NSURLSession.

Next, create a new function called fetchData and add the following code:

let url = NSURL(string: urlAsString)!
        
let jsonQuery = urlSession.dataTaskWithURL(url, completionHandler: { data, response, error -> Void in
            
      do {
         let JSON = try NSJSONSerialization.JSONObjectWithData(data!, options:NSJSONReadingOptions(rawValue: 0))
                
          guard let JSONDictionary :NSDictionary = JSON as? NSDictionary else {
              print("Not a Dictionary")
              return
          }
                
          print("JSONDictionary! \(JSONDictionary)")
                
      } catch let JSONError as NSError {
         print("\(JSONError)")
      }
})
        
jsonQuery.resume()

The given code will fetch the data from the provided URL, serialize it as a NSDictionary and print it out to the console. In case of an error appropriate message will be displayed. Call this function from the index method and build the application. You should see something like this:

JSON data example

JSON data example

This means our fetch method works, and we retrieved the data successfully. Next thing we have to do, is to pass this data to our view. For this tutorial we are only going to use image url but feel free to experiment.

Navigate back to fetchData method and create posts array inside the method, and also delete print(“JSONDictionary! \(JSONDictionary)”). This will be replaced with the mapping code which should look like the following:

for (key, value) in JSONDictionary {
    if(key as! String == "data") {
        for data in value as! NSArray {
           posts.append(data["images"]!!["large"] as! String)        
        }
    }
}

Final thing that we have to add is completion handles since this is async task. We could use notifications but because of async nature of Swift Express making a callback is going to simplify things a lot. Inside your HomeController first implement a new method called futurify which we will use to refresh our view when we get the response. This method accepts futures as result of the handlers and is based on BrightFutures, framework providing a powerful alternative to completion blocks and support typesafe error handling in asynchronous code.

func futurify(fun:((Payload)->Void)->Void) -> Future<Payload, AnyError> {
    let p = Promise<Payload, AnyError>()
    
    fun { payload in
        p.success(payload)
    }
    
    return p.future
}

Do not forget to include BrightFutures at the top of HomeController. Final change that we have to implement in our fetchData method is to add completion handler and make it static. Hence, the changed code should now look like this:

static func fetchData(completionHandler: (posts: [String]) -> ()) {
    
    // Define URL and posts array
    let urlSession = NSURLSession.sharedSession()
    let url = NSURL(string: "http://infinigag.k3min.eu/trending")!
    
    var posts = [String]()
    
    // Make a request
    let request = urlSession.dataTaskWithURL(url, completionHandler: { data, response, error -> Void in
        
        // Try-catch block
        do {
            let JSON = try NSJSONSerialization.JSONObjectWithData(data!, options:NSJSONReadingOptions(rawValue: 0))
            
            guard let JSONDictionary :NSDictionary = JSON as? NSDictionary else {
                print("Not a Dictionary")
                return
            }
            
            // Map the JSON response to array
            for (key, value) in JSONDictionary {
                
                if(key as! String == "data") {
                    
                    for data in value as! NSArray {
                        
                        posts.append(data["images"]!!["large"] as! String)
                        
                    }
                }
            }
            // Call completion handler
            completionHandler(posts: posts)
            
            return
            
            
        } catch let JSONError as NSError {
            print("\(JSONError)")
        }
    })
    
    request.resume()
}

Note that we moved url and url session declaration from class inside the function.

The API has a lot more properties and feel free to experiment with the response and error handling. At the moment if we try to compile the code we will get an error because our fetchData method has been updated with a completion block.

Navigate back to main.swift file and update the route code with the following:

app.get("/") { (request:Request) -> Future<Action, AnyError> in
    
    return HomeController().futurify(HomeController.fetchData).map { posts in
        Action.render("index", context: ["posts": posts])
    }
}

We call futurify function from HomeController instance, pass fetchData as parameter and once we receive the response render the view.

Now navigate to index.stencil and delete all the code from body and replace it with the following:

{% for post in posts %}
    <img src={{ post }} />
    <br>
{% endfor %}

This is a stencil implementation of for loop which will finally render our images. If we build and run the application, some (funny) images should popup on our localhost.

Response example

Response example

Our view now very basic style. We can easily improve it by importing Bootstrap through CDN and adding a few classes. Here is one example but of course you can organize your HTML as you wish.
I also deleted default style that came with style.css

<html>
    <head>
        <title>{{hello}} {{swift}} {{express}}</title>
        <link href='https://fonts.googleapis.com/css?family=Source+Sans+Pro:700italic,700' rel='stylesheet' type='text/css'>
        <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
        <link href='/assets/css/main.css' rel='stylesheet' type='text/css'>

    </head>
    <body>

    <div class="container">
        <div class="jumbotron">
            <h1>Hello world from SwiftExpress!</h1>
            <p>This is a demo application showing how to build website using Swift. Backend is powered by SwiftExpress framework. Tutorial by nermin.tech. </p>
        </div>
        {% for post in posts %}
            <div class="row">
                <div class="col-sm-offset-2 col-sm-8">
                    <img src="{{post}}" class="img-responsive center-block">
                </div>
            </div>
            <br>
            <div class="row">
                <div class="col-sm-offset-2 col-sm-8">
                    <hr>
                </div>
            </div>
        {% endfor %}
    </div>

    </body>
</html>
Final layout

Final layout

And that would be it. We successfully created web application using Swift. Some of the interesting parts were setup of SwiftExpress framework, API calls, and async calls. I have to admit, writing HTML inside XCode felt a bit wired but overall impression is that even at this early stage Swift can be used to create a fully functional website. Entire project from this tutorial can be downloaded from my GitHub account here. Any questions that you may have regarding this tutorial write in the comments bellow or contact me on Twitter.