Escolar Documentos
Profissional Documentos
Cultura Documentos
m
pl
im
en
ts
Extending
of
Swift Value(s)
to the Server
Editors: Nan Barber and Susan Conant Interior Designer: David Futato
Production Editor: Shiny Kalapurakkel Cover Designer: Karen Montgomery
Copyeditor: Christina Edwards Illustrator: Rebecca Panzer
Proofreader: Eliahu Sussman
The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. Extending Swift
Value(s) to the Server, the cover image, and related trade dress are trademarks of
O’Reilly Media, Inc.
While the publisher and the authors have used good faith efforts to ensure that the
information and instructions contained in this work are accurate, the publisher and
the authors disclaim all responsibility for errors or omissions, including without
limitation responsibility for damages resulting from the use of or reliance on this
work. Use of the information and instructions contained in this work is at your own
risk. If any code samples or other technology this work contains or describes is sub‐
ject to open source licenses or the intellectual property rights of others, it is your
responsibility to ensure that your use thereof complies with such licenses and/or
rights.
978-1-491-97646-3
[LSI]
Table of Contents
1. A Swift Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Types and Type Inference 2
Syntax 2
Simple Enumerations 3
Tuples 3
Custom Operators 5
Closures 6
Object Orientation 7
Protocols Define Interfaces 7
Extending Classes, Structures, and Enumerations 9
v
Importing a Library in Your Project 47
Developing in Xcode 50
Creating Your Own Library 51
Producing More Complex Projects 54
Using C Dynamic Libraries 55
Conclusions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
vi | Table of Contents
Preface: Swift for the Rest of
Your Application
vii
(including Raspberry Pi), and zOS architectures, as well as
Linux, macOS, tvOS, watchOS, and iOS operating systems. So, it is
now possible to write a whole end-to-end mobile application—
front-end, middle, back, and even toaster—all in Swift. That’s why
we wrote this book; we wanted to help you, the developer, who is
most likely writing in Java or JavaScript, to consider a switch to
Swift.
Why adopt Swift?
• The Swift language may well be better than what you are cur‐
rently using.
• You can develop and debug in a consistent environment. Inte‐
grated development environments (IDEs) offer a tremendous
amount of functionality such as text editing, static analysis, code
completion, debugging, profiling, and even source-control inte‐
gration. Switching back and forth between say, Eclipse and
Xcode is a bit like switching between French horn and electric
guitar: neither easy nor productive.
• You can reuse code. When each bit of functionality is expressed
exactly once, there is less work, more understanding, and fewer
bugs.
• You can leverage Swift’s features—such as optional types, value
types, and functional programming facilities—to detect many
bugs at compile time that would otherwise be hard to find.
• Since Swift uses the LLVM compiler toolchain for producing
native-code binaries, your applications have the potential for
competitive performance in terms of speed, startup time, and
memory usage. However, examination of performance is out‐
side the scope of this book.
• You will find an active and approachable community of Swift
developers who are creating web posts, books, and videos. In
2016, Swift was cited as the second “Most Loved” language in a
StackOverflow survey, and the third most upward trending
technology.
This book will introduce you to the Swift language, illustrate some
of its most interesting features, and show you how to create and
deploy a simple web service. Let’s get started!
Acknowledgments
This book would not have been possible without the support,
encouragement, and guidance of the IBM Cloud and Swift@IBM
leadership team, including Pat Bohrer, Eli Cleary, Jason Gart‐
ner, Sandeep Gopisetty, Heiko Ludwig, Giovanni Pacifici, John
Ponzo, and Karl Weinmeister. In addition, we want to extend our
thanks to the many IBM Swift engineers and Swift community
members working to bring Swift to the server—including Chris Bai‐
ley, Hubertus Franke, David Grove, David Jones, and Shmuel Kall‐
ner—for sharing their collective technical insights and creating the
tools and libraries described herein. The Swift community’s embrace
of Swift on the server reassured us that our contribution would be
valued. The growing number of their instructive blog posts, videos,
conference talks, and books have been of great help. We would like
to thank our technical reviewers: Chris Devers, Shun Jiang, and
Andrew Black. Nan Barber and the O’Reilly team had the daunting
task of editing our lengthy technical drafts and producing this book.
We owe a huge debt of gratitude to the Apple Core Swift Team for
their courage, intelligence, talent, wisdom, and generosity for bring‐
ing a new language and ecosystem into existence and moving it to
open source. Language design involves many difficult and complex
tradeoffs, and bringing a new language to the world requires a tre‐
1
Types and Type Inference
Swift combines strong and static typing with powerful type inference
to keep code relatively concise. Swift’s type system and compile-time
guarantees help improve the reliability of nontrivial code.
Syntax
Swift’s syntax borrows enough from other languages to be easily
readable. Here’s a trivial example:
let aHost = "someMachine.com"
aHost = "anotherMachine.com" // ILLEGAL: can't change a constant
Tuples
As in some other languages, a Swift tuple simply groups multiple
values together. For example, here’s a function that returns both a
name and serial number:
func lookup(user: String) -> (String, Int) {
// compute n and sn
return (n, sn)
}
Simple Enumerations | 3
Tuple members can be accessed by index:
let userInfo = lookup(user: "Washington")
print( "name:", userInfo.0, "serialNumber:", userInfo.1 )
or can be unpacked simultaneously:
let (name, serialNumber) = lookup(user: "Adams")
print( "name:", name, "serialNumber:", serialNumber )
Members can be named in the tuple type declaration:
func lookup(user: String)
-> (name: String, serialNumber: Int)
{
// compute n and sn
return (n, sn)
}
and then accessed by name:
let userInfo = lookup(user: "Washington")
print("name:", userInfo.name,
"serialNumber:", userInfo.serialNumber)
Custom Operators
As in some other statically-typed languages, Swift allows you to
define your own operators based on static types.
One custom operator we’ll be using in our examples later is apply,
which we’ll denote as |>. Like a Unix pipe, it feeds a result on the left
into a function on the right:
9.0 |> sqrt // returns 3
This lets us read code from left to right, in the order of execution.
For example:
send(compress(getImage()))
can be rewritten as:
getImage() |> compress |> send
To define this custom operator, you first tell Swift about the syntax:
Custom Operators | 5
precedencegroup LeftFunctionalApply {
associativity: left
higherThan: AssignmentPrecedence
lowerThan: TernaryPrecedence
}
infix operator |> : LeftFunctionalApply
then provide a (generic) implementation:
func |> <In, Out> ( lhs: In, rhs: (In) throws -> Out )
rethrows -> Out {
return try rhs(lhs)
}
Judiciously used, custom operators can help make code clear and
concise.
Closures
Swift includes closures: anonymous functions defined inline, which
can read and write to their enclosing lexical scope.1 A closure is a
first-class entity, a reference type which can be assigned to constants
and variables, passed as arguments, and returned as results. Func‐
tions and methods are just special cases of closures with a slightly
different syntax for their definition. Closures support functional pro‐
gramming, which can be particularly helpful in dealing with asyn‐
chrony (Chapter 3).
1 Unlike Smalltalk, Swift closures cannot return from the home method’s scope (a.k.a.,
nonlocal return), so they cannot be used to extend the built-in control structures.
Object Orientation
Swift includes full support for class-based object-oriented program‐
ming, including classes, instances, constructors (called “initializ‐
ers”), instance variables, static variables, computed virtual getters
and setters, inheritance, and final attributes. When one method
overrides another, it must be annotated in the code. This require‐
ment prevents some errors. Experienced Swift programmers tend to
reserve objects for things requiring shared access to a mutable state.
(See Chapter 2.)
Object Orientation | 7
{
var requestString: String { return "GET" }
}
class Post_HTTP_Request:
Abstract_HTTP_Request, HTTP_Request_Protocol
{
var requestString: String { return "POST" }
var data: String
init( url: URL, data: String ) {
self.data = data
super.init(url: url)
}
}
When declaring a variable to hold a request, instead of using the
type Abstract_HTTP_Request, use the type HTTP_Request_Proto
col:
let aRequest: HTTP_Request_Protocol
= Get_HTTP_Request(url: … /* some URL */)
aRequest.requestString // returns "GET"
In the following, you’ll see an example of a generic protocol, which
could not be used as a type. As in other languages, protocols help to
prevent errors as well as remove dependencies on the representa‐
tion.
Generic Protocols
Generic entities allow the same basic code to apply to different
types. In addition to concrete types, Swift also allows protocols to be
generalized to different types, although the mechanism differs.
For example, suppose you have two responses, a TemperatureRes
ponse and a FavoriteFoodResponse:
struct TemperatureResponse {
let city: String
let answer: Int
}
struct FavoriteFoodResponse {
let city: String
let answer: String
}
Even though each answer is a different type, they can share the same
description by adopting a common protocol:
13
let contentType = headerFields["Content-Type"]
and Swift will infer a type for contentType. But that type is
not “String”! It is “String?” with a question mark, because String
represents a value that can never be nil, whereas String? represents
a value that be either a String or nil. The latter is called an optional
type. The dictionary lookup returns an optional type because the
dictionary might not contain a key for “Content-Type.” The type
String? is not the same type as String and Swift won’t let you use
the value of an optional type without an explicit check:
if contentType.hasPrefix("text") // ILLEGAL
There are many convenient ways to perform this check. For exam‐
ple, the if-let form checks if the value is nonnil. If so, it assigns
the value to a new variable that is local to the then-part. If the value
is nil, it executes the else-part, if any.
let contentType: String
if let ct = headerFields["Content-Type"] {
contentType = ct
}
else {
contentType = "no contentType"
}
init(city: String) {
self.city = city
}
}
After creating a request object:
let request = TemperatureRequestClass(city: "Paris")
1 Unless it is passed in-out, in which case the caller must mark it with an ampersand.
init(city: String) {
self.city = city
}
}
2 Swift does include a way to pass in a structure so that the callee can mutate it—in-out
parameters. But the call site looks different when passing such a parameter, so that you
need only inspect the local part of the code to see that there might be a possibility of
mutation.
Mutating Methods
Unlike any other value type, a structure can include methods that
mutate the contents of var fields in the structure. As a helpful signal
to the programmer, such methods must be annotated with mutat
ing. This requirement highlights the places where side effects could
occur:
struct TemperatureRequestStruct {
…
var startTime: Date? = nil
mutating func clearStartTime() { startTime = nil }
}
func send(
completionHandler:
@escaping (Data?, URLResponse?, Error?) -> Void
) {
let s = URLSession()
let r = URLRequest(url: someURL)
Choosing an Aggregate
Tuples, classes, structures, protocols, enumerations: Swift offers
many different aggregates. Which to use in any given situation?
Figure 2-3 and the following subsections provide a simplified guide.
It neglects two aspects: some constructs may run faster than others,
and classes offer more implicitly dynamic dispatch of methods than
do other aggregates.
Choosing an Aggregate | 25
class User {
let name: String // the User’s name can not change
var location: String // the User’s location can change
If you are currently using a language with little support for optional
types or value types, your code will benefit from moving to Swift
and using them wherever you can. The assurances they provide
about freedom from nil values, mutation, and coupling will help you
write cleaner code. This code will be easier to reason about, main‐
tain, and debug.
Choosing an Aggregate | 27
CHAPTER 3
Swift Promises to Tame
Asynchrony
29
1. Synchronous operations are linked together in a chain, each
operation depending on the previous one, and each potentially
throwing an exception. By using the Result enumeration, the
divergent control flow that results from handling exceptions
gets restructured into a simpler linear data flow that is easier to
follow.
2. The nested callbacks needed to chain asynchronous operations
are hard to read and maintain. This section shows how to trans‐
form the nest into a straightforward chain of BasicPromises.
3. Steps 1 and 2 converge, combining Result and BasicPro
mise into Promise. This synthesis simplifies and clarifies the
construction of chains of asynchronous operations that cope
with errors at any stage.
Each of these steps takes advantage of Swift’s extensibility and static
checking to create more concise and robust code.
PromiseKit Conventions
Faced with many different names for the concepts in
this chapter, we chose the terminology used in Promis‐
eKit because it is one of the most popular libraries in
this domain. It is a third-party, open-source library
written by Max Howell and available at promiseKit.org
or at https://github.com/mxcl/PromiseKit. For
instance, we use the terms fulfill and reject instead
of the terms success, fail, or map, etc.
1 If you know other functional languages, you might recognize the enumeration by
names such as “maybe” or “either.”
2 Throughout this chapter, in the interest of brevity, we omit public on what would nor‐
mally be exported library declarations. We also omit the @discardableResult func‐
tion attribute, which silences warnings when a function is invoked without consuming
its return value.
The last argument to the initializer for Result is a closure, which the
initializer invokes. If the closure returns normally, the initializer cre‐
ates a fulfilled Result that includes the closure’s return value. If
the closure throws an exception, the initializer creates a rejected
Result that includes the error:
extension Result {
init( of body: () throws -> FulfilledValue ) {
do { self = try .fulfilled( body() ) }
catch { self = .rejected ( error ) }
}
}
Now that you have a Result<City>, use it to get the temperature for
a city. Although you could write a switch statement for this particu‐
lar chain:
func getTemperatureFromCity( aResult: Result<City> )
-> Result<Int>
{
switch aResult {
case let .fulfilled(city):
return Result<Int> { try getTemperature(in: city) }
case let .rejected(err):
return Result<Int>.rejected(err)
}
}
You can do better by encapsulating the switch statement inside a
reusable member function of Result:
So far, this book has dealt with only synchronous operations, but
server-side programming often relies on asynchronous operations
Replacing Callbacks
In order to get rid of nested callbacks, an asynchronous operation
must return some thing that can be fed to the next operation. That
thing must be something that can be created and returned before the
first asynchronous operation completes. That way, it can be passed
on to the next operation without being nested inside the first opera‐
tion. This thing is commonly called a future or a promise. It works
like a Unix pipe between two threads: the first thread creates the
pipe and immediately returns it. Then, the second thread receives
the pipe and waits for some data. Later, the first thread computes its
data and sends it down the pipe. The pipe wakes up the second
thread and presents it with the data from the first thread.
For now, defer error-handling considerations to “Step 3: Coping
with Asynchronous Errors” on page 40, so define a BasicPromise,
which does not account for errors. Recall that Result is generic
because the value for success can be any type, but that type can be
determined statically. BasicPromise is also generic for the same rea‐
son. Call the type of the value for (eventual) success Out
come. Because a shared BasicPromise communicates the readiness
of a result, it must be a class: classBasicPromise<Outcome>.
Specifying a DispatchQueue
Since then runs its body asynchronously, you
might want the body to run on a specific
DispatchQueue. Methods such as then take an
optional argument to allow you to specify a Dis
patchQueue. In PromiseKit, the DispatchQueue
defaults to .main, which can often result in a
deadlock. We suggest .userInitiated instead.
The Promise methods named “then” only run their bodies if the
computation has succeeded, and the Promise method named
“catch”5 only runs its body if the computation has failed. Unlike a
BasicPromise, a Promise only gets fulfilled if the computation
succeeds, and it gets rejected if the computation fails. In addition
to explicitly calling reject, a body can also signal failure by throw‐
ing an exception.
Here is a requestCity function that returns a Promise. It creates the
Promise with pending, a static function that returns a new Promise,
together with its fulfill and reject functions. It simulates the
asynchrony that would occur with a real web request with an asyn‐
chronous invocation of the switch statement:
func requestCity(of user: String) -> Promise<City> {
// obtain a new Promise & fulfill & reject functions
let (promise, fulfill, reject) = Promise<City>.pending()
DispatchQueue.global(qos: .userInitiated).async {
switch user {
case "Rob": fulfill(.Austin)
case "David": fulfill(.Mountain_View)
case "John": fulfill(.Podunk)
default: reject(Errors.unknownUser)
}
}
return promise
}
5 “Catch” here is just another method name, a sort of pun on the catch keyword in Swift.
The first requestCity sends out a request. If the request later fails,
each of the then blocks will bypass its body, and only the catch will
run its body. If the request instead succeeds, the first invocation of
the then method will run its body, requesting the temperature of the
city that was returned from the city request. Then, if the tempera‐
ture request succeeds, the temperature will be printed. Otherwise,
the body of the catch will run.
Although the code above is asynchronous, it is as clear as the syn‐
chronous version:
Result { try getCity(of: user) }
.then { try getTemperature(in: $0) }
.then { print("temperature:", $0) }
.catch { print("error:", $0) }
Space precludes a thorough tour through the implementation here;
see MiniPromiseKit.
Asynchrony and errors have been abstracted away! Swift’s support of
functional programming and type-based overloading have raised
the level of discourse so that the code focuses on what is happening,
not when or what-if failure.
Reinventing the wheel is a great way to waste your time and effort.
When another developer has already created a solid library that per‐
forms a function needed by your application, you can save weeks of
time if you are able to reuse it. The Swift ecosystem is growing very
quickly, and often there are many similar libraries that solve the
same problem. If you adopt Swift for your project, you will find
hundreds of Swift packages on GitHub or listed in the IBM Swift
Package Catalog, which can be easily incorporated with the aid of
the Swift Package Manager (SwiftPM). Whether you are looking to
store your data in a database, parse JSON, or use reactive program‐
ming, chances are that there is a Swift package out there that can do
what you need it to.
As a developer, you might want to add one of these libraries to your
project. This is where the SwiftPM comes into play. If you already
use a package manager such as Rust’s Cargo, NodeJS’s npm, Java’s
Maven, or Ruby’s Gem, you will feel right at home using the
SwiftPM. It helps to resolve dependencies by automatically down‐
loading the sources that match the version you want, and arranges
the build process so that you have the executable or Swift library
that you need. Because the SwiftPM works on many platforms, you
can kick off builds, test, or fetch dependencies with shell commands.
In addition, you can use it to generate an Xcode project, as
described in “Developing in Xcode” on page 50.
43
Semantic Versioning
When SwiftPM fetches a required package, it must fetch an appro‐
priate version that will work with your project. So, each package
uses a three-level version number, consisting of major, minor, and
patch numbers:
Creating an Application
This section steps you through the process of using the SwiftPM to
create a new project from scratch, find a package to include, import
that package, and build your project.
Creating an Application | 45
swift modules. Finally, it links the .swiftmodule files to produce
your executable, which is left in the .build/debug/ directory. Run
your program now:
$ ./build/debug/MyProject
Hello, world!
The Package.swift file describes the project and how to build it.
Builds are not described by a special language like Gradle or a
Makefile—it’s native Swift code! You don’t have to learn another lan‐
guage to control the build process. You can write if statements that
will select the correct library to use based on whether you are run‐
ning on Darwin or Linux:
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
import Darwin
#elseif os(Linux)
import Glibc
#endif
The system’s environment variables can also influence the build pro‐
cess. For example, you can check for the existence of an environ‐
ment variable before executing a code block:
let env = ProcessInfo.processInfo.environment
if env["MY_SYSTEM_ENV"] == "true" { ... }
Figure 4-1. Searching for a package in the IBM Swift Package Catalog
Select the Pipes package to view the details about the project shown
in Figure 4-2. These include the last tagged version number, dis‐
played at the top of the right column:
Click on “Include project in your code,” which will copy the neces‐
sary dependency link to your clipboard so you can paste it into Pack
age.swift.
Go back to your Package.swift file and insert that dependency in
your Package constructor:
import PackageDescription
Although you have the flexibility to use a large version range (such
as only specifying the major version), we recommend locking down
both the major and minor versions. Although, in theory, minor ver‐
sion changes should not break a build, they often do so at early ver‐
sion numbers.
You can now write code that uses Pipes. Open main.swift and
import the Pipes module, and write some basic code:
import Pipes
Hello, Alice!
Developing in Xcode
While you can easily develop entirely on the command line using
your favorite text editor, many macOS users will want to use Xcode
for their server-side Swift development. You can use Xcode to edit
and compile the code, run tests, and profile your Swift code just like
you can with iOS and macOS projects. But first, in order to use
Xcode, a project must be created from your Package.swift. The fol‐
lowing command will create your project:
$ swift package generate-xcodeproj
Running this command line fetches the necessary dependencies
before creating the Xcode project. When you build with Xcode, it
does not use SwiftPM to build your project, but instead will use
Xcode’s native build system.
In the future, we expect to see tighter integration of SwiftPM and
Xcode.
You can open the project in Xcode, and once in Xcode, tools such as
the debugger, instruments, code coverage, and testing will work as
expected. If you want to run an executable, make sure you change
your active scheme in Xcode to the executable before you use the
Run (<Cmd>-r) command.
swift init generates files for a library, just as it does for an exe‐
cutable. But instead of generating a main.swift file, it generates a
file named after the module. Instead of nothing in Tests, it creates a
very basic test suite.
Next, open Sources/Pipes.swift, erase what’s there, and add an
implementation of the Pipe operator that will be used for your
library:
precedencegroup LeftFunctionalApply {
associativity: left
higherThan: AssignmentPrecedence
lowerThan: TernaryPrecedence
}
@discardableResult
public func |> <A, B> (
x: A,
f: (A) throws -> B
) rethrows -> B
{
return try f(x)
}
extension PipesTests {
static var allTests : [
( String, (PipesTests) -> () throws -> Void )
]
{
return [
("testDouble", testDouble)
]
}
}
The allTests array is not needed to run your tests in Xcode, but it
is important for the SwiftPM to run the tests with the swift test
command.
Now, compile and test your library by running swift build, then
swift test:
Pipes$ swift build
Compile Swift Module 'Pipes' (1 sources)
Pipes $ swift test
Compile Swift Module 'PipesTestSuite' (1 sources)
Linking .build/debug/PipesTests.xctest/Contents/MacOS/PipesTests
Test Suite 'All tests' started ...
Test Suite 'PipesTests.xctest' ...
Test Suite 'PipesTests' started ...
Test Case '-[PipesTestSuite.PipesTests testDouble]'
started.
Test Case '-[PipesTestSuite.PipesTests testDouble]'
passed (0.001 seconds).
Test Suite 'PipesTests' passed at ...
Executed 1 test, with 0 failures (0 unexpected) in 0.001
(0.001) seconds
Test Suite 'PipesTests.xctest' passed at 2016-07-22 13:59:39.629.
57
let router = Router()
Before an incoming request can get to the router, an HTTP server
must be listening on a TCP port. Create the server, register it to your
Router, and have it listen on port 8090:
Kitura.addHTTPServer(onPort: 8090, with: router)
Kitura.run()
Multiple Servers
The Kitura runtime supports creating multiple HTTP
servers. These servers can be listening on different
ports, and you can also create different routers for
each. While some users may use a separate TLS/SSL
proxy for their secure transport, it is also possible to
create an HTTPS server in Kitura.
What is @escaping?
Swift requires the callNextHandler argument to be
marked @escaping because it is a closure that might
outlive the callee. More information can be found in
the Swift documentation.
When a client requests the addition of a new to-do item to the list,
the request is fulfilled by a RouterHandler that is registered to a
POST request type. A POST request will typically contain a message
body in it, but in order to extract the JSON in this body, Kitura must
first parse the body before passing it to the handler.
Kitura has a piece of middleware called BodyParser that will parse
the body of the request before sending it to the handler. BodyParser
reads the Content-Type of a message, and fills in the body field of
the RouterRequest with a ParsedBody enumeration. The enumera‐
tion includes cases for json, text, raw, and other values. But for the
BodyParser to work, you must register it on routes that need this
payload information, namely, the POST on"/v1/task". In order to
have it be used on all routes, you can use "/*":
router.all("/*", middleware: BodyParser())
In Kitura, unlike NodeJS, multiple handlers run concurrently on dif‐
ferent threads. To avoid data loss and potential heap corrup‐
tion, serialize mutations to the itemStrings array with a statically-
allocated semaphore:
let itemStringsLock = DispatchSemaphore(value: 1)
itemStringsLock.wait()
itemStrings.append(item)
itemStringsLock.signal()
response.send("Added '\(item)'\n")
callNextHandler()
}
After creating the router, register each handler:
router.get ("/v1/string/item", handler: handleGetStringItems)
router.post("/v1/string/item", handler: handleAddStringItem)
If you compile and run the project now, you will have a working to-
do list! The server will run and accept incoming connections, so test
if the server is working properly by using cURL.
$ curl -H "Content-Type: application/json" \
-X POST \
-d '{"item":"Reticulate Splines"}' \
localhost:8090/v1/string/item
Added 'Reticulate Splines'
$ curl localhost:8090/v1/string/item
["Reticulate Splines"]
If you are not on a Mac, or wish to use the command line, you must
first create some files to prepare your project for deployment.
Because Bluemix is a CloudFoundry-based hosting platform, it uses
buildpacks for deploying your code. These buildpacks are scripts
that are used to build your project in the cloud. When you push
your application to Bluemix, your code is bundled and uploaded to
a build server. The code is compiled based on the Swift buildpack.
Next, Bluemix uploads copies of the binary onto the number of vir‐
tual machine instances that you provisioned. When the application
is launched, and a load balancer distributes network traffic to all of
your instances running your server.
To describe your deployment, your application must have a
manifest.yml in the root path. This manifest file declares the appli‐
cation’s memory requirement, the number of instances, hostname,
and the address to the buildpack.
else {
response.status(.badRequest)
callNextHandler()
return
}
itemDictionariesLock.wait()
itemDictionaries.append( [ "id": UUID().uuidString,
"title": title ] )
itemDictionariesLock.signal()
response.send("Added '\(title)'\n")
$ curl localhost:8090/v1/dictionary/item
[
{
"id" : "2A6BF4C7-2773-4FC9-884C-957F205F940A",
"title" : "Reticulate Splines"
}
]
Move to a Structure
Now, represent an item with a structure. This change will allow the
item to be expressed in Swift more naturally, and has the benefit of
guaranteeing type safety on the properties:
struct Item {
let id: UUID
let title: String
}
var itemStructs = [Item]()
let itemStructsLock = DispatchSemaphore(value: 1)
func handleAddItemStruct(
request: RouterRequest,
response: RouterResponse,
callNextHandler: @escaping () -> Void
) {
guard case let .json(jsonBody)? = request.body
else {
response.status(.badRequest)
callNextHandler()
return
}
do {
let item = try Item(json: jsonBody)
itemStructsLock.wait()
itemStructs.append(item)
itemStructsLock.signal()
response.send("Added '\(item)'\n")
callNextHandler()
}
catch {
response.status(.badRequest)
let err = error.localizedDescription
response.send(err)
callNextHandler()
}
}
Register the handlers:
router.get ("/v1/struct/item", handler: handleGetItemStructs)
router.post("/v1/struct/item", handler: handleAddItemStruct)
$ curl localhost:8090/v1/struct/item
[
{
"id" : "054879B8-B798-4462-AF0B-79B20F9617F4",
"title" : Finish book!
}
]
Adding Authentication
You may not want to allow a user to add a task to someone else’s list.
In order to prevent that from happening, you must first add a layer
of authentication. User identity will be assured by the client securely
sending a token that uniquely identifies the user. This token is
obtained by a third-party service the user already has an account on,
such as Facebook, Google, GitHub, or LinkedIn. This method is
convenient and more secure because your application’s database will
not need to store each user’s login name and password. The database
can just link each user’s login name to that user’s to do list items.
Kitura has a middleware library called Kitura Credentials that
makes it easy to add authentication to your application. There are
several plug-ins that currently support Facebook, Github, and Goo‐
gle OAuth token validation. In addition, there are plug-ins for
HTTP basic and digest authentication. The middleware intercepts
each RouterRequest, and then ensures that the token in the header
correctly authenticates the user. The RouterRequest will only pro‐
ceed to execute the handler if the authentication succeeds.
The example below shows how to use the Facebook plug-in. After
credentials middleware is created, the Facebook plug-in is registered
with the middleware. Next, the routes matching the item resource
are protected with the authentication layer. This is useful, since there
might be other routes that you might not want to protect; for
instance, the welcome page. The following sets up the authentica‐
tion:
$ curl localhost:8090/v1/couch/item
[
{
"id" : "054879B8-B798-4462-AF0B-79B20F9617F4",
"title" : Finish book!
}
]
You have learned how to create a fully working to-do list application
in Swift that uses a database and can be deployed to a server. Scratch
that off your bucket list.
Conclusions | 75
About the Authors
David Ungar holds a Ph.D. in Computer Science from U.C. Berke‐
ley, taught at Stanford, and enjoys a research position at IBM in the
Ubiquitous Platforms group in Cloud and Mobile Enterprise
Research. He loves programming and has enjoyed APL, C, C++,
Smalltalk, Self (which he codesigned), Java, JavaScript, Objective-C,
and Swift. His interests have included UNIX system programming,
microprocessors, object-oriented language design and implementa‐
tion, cartoon animation techniques for user interfaces, reflection
APIs, IDEs, emergence for massive parallelism, and contextual pro‐
gramming. Now he builds iOS and macOS applications.
Four of his papers have been honored by the Association for Com‐
puting Machinery for lasting impact. In 2009, he was awarded the
Dahl-Nygaard prize for outstanding career contributions to object-
oriented language technology by the Association Internationale
pour les Technologies Objets.
He blogs at http://blog.davidungar.net and tweets at @senderPath.
Robert F. Dickerson is a software engineer in the Swift@IBM engi‐
neering group. Having written many end-to-end applications in
Java, JavaScript, and Swift (on iOS), he loves being able to write his
server-side code in Swift! He was one of the original developers who
made Kitura, a web-service middleware framework for Swift. He
leads a team that builds applications and libraries that use Kitura.
He is active in the open-source Swift community, where he has
given talks about server-side Swift at AltConf 2016, Try! Swift NYC
2016, and the Server-side Swift Year-Long Conference 2016. Before
joining IBM as a developer, he was on the faculty in the computer
science departments at the College of William and Mary and then at
the University of Texas at Austin. He holds a Ph.D. in Computer Sci‐
ence from the University of Virginia.
He blogs at https://developer.ibm.com/swift/ and tweets at @rfdicker‐
son.