Developing software in the Real World

Getting Started with Kitura

Kitura is a new web framework for Swift 3 by IBM. As Swift is a compiled language, your Kitura application compiles to a binary that can either act as its own webserver (by default, on port 8090) or as a FastGCI server for use with Nginx or Apache.

By the end of this tutorial, we will have built a simple HTTP API that uses CouchDB for persistence.

Note that this tutorial doesn’t teach you Swift. I recommend The Swift Programming Language as a great place to start learning the language. Start with the tour.

Setting up Swift

To start with, we need a working Swift 3 compiler. Since September 2016, Swift 3.0 has been released, so we will use that. Note that for macOS you need Xcode installed and for Linux, you’ll need clang (sudo apt-get install clang)

To control which version of Kitura is used in any given project, we can use swiftenv which manages multiple Swift installations and selects the right one for our specific project. Follow the installation instructions to install.

For this project, we’re going to use Swift 3.0 final, so install it using:

(Note, that on OS X, you will need Xcode 8)

Create the project directory

Let’s create our project directory now:

This will create a .swift-version file in our directory and if you then run swift --version, you should see:

(on Linux – something similar on macOS)

Use version control

Everything is better with version control, so let’s get that going now:

Swift’s package manager creates and manages a directory called Packages and the build system uses a directory called .build, so we can add both of these to .gitignore as we don’t want git to manage them. Let’s do that now:

For the rest of the tutorial, I’ll assume that you will commit as and when you think that it’s wise to!

Hello world

We’re going to use the Swift Package Manager to manage our dependencies and control the building of our application. This uses a file called Package.swift in our root directory, so let’s create it:

Package.swift:

Throughout this tutorial, I’ll present code that I want you to write in blocks like this with the filename to use above it. So go ahead and create the file if it doesn’t yet exist and then add the new lines of code.

All we’ve done so far is name our application as BookshelfAPI. We’ll add dependencies shortly, but first we want to check we can compile and run a simple application.

SwiftPM expects our source code to be in the Sources sub-directory and the entry point to a SwiftPM application is a file called main.swift. This can be in the Sources directory or in a sub-directory of Sources. The first level of subdirectories in Sources are special as they represent compilable units such as executables or libraries.

We’ll create Sources/BookshelfAPI to hold our source code. SwiftPM will then name our binary BookshelfAPI for us.

We can now create our first Swift source file:

Sources/BookshelfAPI/main.swift

We can now compile our application and see if it worked:

This command will compile our code and put the resulting binary in the .build/debug directory. The command’s output is:

We can then run it like this:

And you should see the output:

We have successfully built our first Swift application.

Our first Kitura application

To write our first Kitura application, we need to bring in some dependencies. We need Kitura itself and we’ll also bring in HeliumLogger as logging makes it much easier to see what’s going on.

We do this by adding the GitHub project URLs to Package.swift along with specifying version constraints. Update Package.swift so that it looks like this:

Package.swift:

We’ve added the dependencies array with two Package elements, one for each dependency. For the particular version of the Swift compiler, we need version 0.25.x of Kitura and 0.14.x of HeliumLogger. While Swift 3 is still in active development, we need to match the swift compiler to the Kitura version as documented in the Kitura Readme.

If we now run swift build, the Swift Package Manager will download the Kitura and HeliumLogger packages along with any dependencies and compile them for us. In this case, we would pick up the Kitura-net, Kitura-sys, LoggerAPI, BlueSocket, CCurl, CHTTPParser, SwiftyJSON, and Kitura-TemplateEngine dependencies.

Let’s write some code! Our main.swift file becomes more of a real application now. Replace the contents of main.swift with this code:

Sources/BookshelfAPI/main.swift

Now, let’s look at this code stage by stage:

Firstly we import all the modules we want to use. Pretty much all Swift files have a set of imports at the top, so I won’t comment on them very often.

The LoggerAPI package implements the Log class which does nothing unless you attach an instance of a logger to it. Hence we attach a new instance of HeliumLogger so that the calls to the log within the rest of Kitura will now work. By default, HeliumLogger will output logs to stdout, so we use setbuf to disable buffering on stdout so that we can see the log output immediately.

Kitura is inspired by ExpressJS, so we set up the paths that the web application responds to in a similar way. The router instance has a set of methods for each HTTP verb that you want to respond to. In this case, we want to respond to the GET HTTP method, so we use router.get(). The first parameter is the URL path to match: “/” in this case. We’ll look at more complex paths as we build out the app. The other parameter to get() is a closure that is called when the path is matched. As the closure is the last argument to the method, we can use the trailing closure syntax.

The signature for the closure is:

That is, we are passed in an instance of RouterRequest, an instance of RouterResponse and a method called next. We use request to find out information that the client sent us and perform the relevant operations. We then populate the response with the status code, headers and data that we want to send to the client and then call next(). The system is implemented as a pipeline of handlers known as middleware; calling next() means that we want the next handler in the pipeline to be called.

In this case, we set the status to .OK (i.e. an HTTP 200 response) and then use send(json:) to fill in the response’ body with some JSON. The JSON library used is SwiftyJSON which is quite a nice way to convert between JSON and Swift dictionaries. Kitura implements a final handler that will send the contents of the response back to the client, so we call next() in order to continue the pipeline execution.

Finally, we tell Kitura that we want to run an HTTP server on port 8090 and pass it our configured router so that it can match routes. Then we run() the application.

Note, that, if you’re into Docker, then you can add this docker-compose.yml file if you want to target Linux from a Mac:

docker-compose.yml

You can then use docker-compose up to build and run the Swift application within a Linux environment.

Using a Makefile

We also need different command line switches for swift build depending on whether we’re using Linux or OS X, so we will abstract this all away via a Makefile which the Kitura team have already written for us! The Package-Builder library has what we need, so we add it as a submodule to our project:

This adds the Package-Builder directory to our project and we now add our own Makefile that includes the Package-Builder one. Create a Makefile file with this in it:

Makefile

Build & run our first Kitura app

We can now build the application:

This will invoke swift build with any required flags. The build will download the libraries specified in Package.swift and the dependencies that they have. It will then compile each library and finally compile our application. The Makefile includes informational messages in the output that are prefixed by ---.

A typical clean build looks like this (assuming the packages are already downloaded):

We can then run our app:

The app outputs its logs directly, so we can see them:

Test using curl

We’re writing an API, so we test with curl!

As you can see, using send(json:) has resulted in a valid JSON body and also the Content-Type header is set to application/json as it should be.

Done

We now have a working Kitura application which works on both Linux and OS X. It doesn’t do much, but we’ve set the stage for the next instalment!

Tutorial navigation

GitHub repository: kitura_bookshelfapi