Extending Swift Value(s) to the Server David Ungar and Robert Dickerson Extending Swift Value(s) to the Server by David Ungar and Robert Dickerson Copyright © 2017 IBM Corporation All rights reserved Printed in the United States of America Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472 O’Reilly books may be purchased for educational, business, or sales promotional use Online editions are also available for most titles (http://safaribooksonline.com) For more information, contact our corporate/institutional sales department: 800-998-9938 or corporate@oreilly.com Editors: Nan Barber and Susan Conant Production Editor: Shiny Kalapurakkel Copyeditor: Christina Edwards Proofreader: Eliahu Sussman Interior Designer: David Futato Cover Designer: Karen Montgomery Illustrator: Rebecca Panzer January 2017: First Edition Revision History for the First Edition 2017-01-25: First Release 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 subject 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-97196-3 [LSI] Preface: Swift for the Rest of Your Application Q: Why did the human put on his boxing gloves? A: He had to punch some cards Today’s applications not run on a single platform Rather, some parts run on resource-limited devices, and other parts run on a vast and mysterious cloud of servers This separation has led to a schism in how we build these applications because different platforms have different requirements: the mobile portions must conserve battery power, while the server portions must handle a large number of requests simultaneously Consequently, programmers use different languages for different parts of applications—for instance, JavaScript for the browser, and Java for the server However, constructing an application out of multiple languages is fraught with drawbacks: different teams in the same organization speak different languages—literally—and must master different developer ecosystems Precious time must be spent translating concepts across language barriers and a few developers must know all of the languages in order to be effective Test cases and data models must be replicated in different languages, introducing bugs and incurring future maintenance efforts Because third-party libraries cannot be shared across groups, each team must learn different APIs to obtain merely the same functionality Swift was introduced by Apple in 2014 and replaced Objective-C as the recommended language for all new applications running on Apple devices Later, when Swift became open source in 2015, it spread to new platforms Currently, Swift is available on x86, ARM (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 currently using You can develop and debug in a consistent environment Integrated development environments (IDEs) offer a tremendous amount of functionality such as text editing, static analysis, code completion, debugging, profiling, and even source-control integration 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 outside 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! CODING STYLE & IMPLEMENTATIONS In the examples, the space constraints of this medium have led us to indent, break lines, and place brackets differently than we would in actual code In addition, space has precluded the inclusion of full implementations and blocks of code in this edition contain inconsistencies in color and font If the inconsistencies confuse you, please consult the repositories in Table P-1 Table P-1 Where to find code examples Repository name Referenced in Book snippets Code snippets from the book MiniPromiseKit Created in Chapter 3; used in Chapter Pipes Used in Chapter Kitura To-Do List Created in Chapter 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 Gartner, 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 Bailey, Hubertus Franke, David Grove, David Jones, and Shmuel Kallner—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 bringing 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 tremendous amount of work The rapid acceptance of Swift by developers is powerful testimony to the quality of the language Words fall short in plumbing the depths of our gratitude for the support and love of our sweethearts, Barbara Hurd and Valerie Magolan Chapter A Swift Introduction Swift supports several different programming paradigms This chapter provides a brief overview of the parts of the Swift language that will be familiar to a Java or JavaScript programmer Swift is not a small language, and this chapter omits many of its conveniences, including argument labels, shorthand syntax for closures, string interpolation, array and dictionary literals, ranges, and scoping attributes Swift’s breadth lets you try Swift without changing your programming style while you master its basics Later, when ready, you can exploit the additional paradigms it offers A beginning Swift developer may initially be overwhelmed by the cornucopia of features in the Swift language, since it gives you many ways to solve the same problem But taking the time to choose the right approach can often catch bugs, shorten, and clarify your code For instance, value types help prevent unintended mutation of values Paradigms borrowed from functional programming such as generics, closures, and protocols provide ways to factor out not only common code, but also variations on common themes As a result, the underlying themes can be written once, used in varying contexts, and still be statically checked Your programs will be much easier to maintain and debug, especially as they grow larger As you read this chapter, you may want to refer to the documentation, The Swift Programming Language (Swift Edition) 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 DECIPHERING TYPE ERRORS IN LONG STATEMENTS If your program won’t compile, you can often clarify a type error by breaking up an assignment statement into smaller ones with explicit type declarations for each intermediate result 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 aHost is inferred by Swift to be of type String It is a constant, and Swift will not compile any code that changes a constant after it has been initialized (Throughout this book, ILLEGAL means “will not compile.”) This constant is initialized at its declaration, but Swift requires only that a constant be initialized before being used var aPath = "something" aPath = "myDatabase" // OK aPath is also a String, but is a mutable variable Swift functions use keywords to prevent mixing up arguments at a call site For example, here is a function: func combine(host: String, withPath path: String) -> String { return host + "/" + path } and here is a call to it: // returns "someMachine.com/myDatabase" combine(host: aHost, withPath: aPath) Swift’s syntax combines ease of learning, convenience of use, and prevention of mistakes Simple Enumerations In Swift, as in other languages, an enumeration represents some fixed, closed set of alternatives that might be assigned to some variable Unlike enumerations in other languages, Swift’s come in three flavors, each suited for a particular use The flavor of an enumeration depends on how much information its values are specified to include An enumeration may be specified by 1) only a set of cases, 2) a set of cases, each with a fixed value, or 3) a set of cases, each with a set of assignable values (The last flavor is covered in Chapter 2.) The simplest flavor merely associates a unique identifier with each case For example: enum Validity { case valid, invalid } The second flavor of enumeration provides for each case to be associated with a value that is always the same for that case Such a value must be expressed as a literal value, such as 17 or "abc" For example: enum StatusCode: Int { case ok = 200 case created = 201 … // more cases go here case badRequest = 400 case unauthorized = 401 } The value of this enumeration can be accessed via the rawValue attribute: func printRealValue(of e: StatusCode) { print ("real value is", e.rawValue) } 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) } 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) When an identifier is declared with let, every element of the tuple behaves as if it were declared with a let: let second = lookup(user: "Adams") second.name = "Gomez Adams" // ILLEGAL: u is a let var anotherSecond = lookup(user: "Adams") anotherSecond.name = "Gomez Adams" // Legal: x is a var print(anotherSecond.name) // prints Gomez Adams When you assign a tuple to a new variable, it gets a fresh copy: var first = lookup(user: "Washington") var anotherFirst = first first.name // returns "George Washington" anotherFirst.name // returns "George Washington" as expected first.name = "George Jefferson" first.name // was changed, so returns "George Jefferson" anotherFirst.name // returns "George Washington" because // anotherFirst is an unchanged copy first and anotherFirst are decoupled; changes to one not affect the other This isolation enables you to reason about your program one small chunk at a time Swift has other constructs with this tidy property; they are all lumped into the category of value types (See Chapter 2.) The opposite of a value type is a reference type The only reference types are instances-of-classes and closures Consequently, these are the only types that allow shared access to mutable state Tuples combine nicely with other language features: the standard built-in method for iterating through a dictionary uses key-value tuples Also, Swift’s switch statements become very concise and descriptive by switching on a tuple: enum PegShape { case roundPeg, squarePeg } enum HoleShape { case roundHole, squareHole, triangularHole } func howDoes( _ peg: PegShape, fitInto hole: HoleShape ) -> String { switch (peg, hole) { // switches on a tuple case (.roundPeg, roundHole): return "fits any orientation" case (.squarePeg, squareHole): return "fits four ways" default: return "does not fit" } } Tuples are a convenient way to aggregate a few constant fields that have no meaningful type apart from the types of the fields 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 var itemStrings = [String]() and also two handlers: one for getting all of the to-do items and the other for adding a to-do item (We omit showing an example of removing and modifying items for this tutorial.) Getting a list of items is easier than adding a new one, so start there The code needs to serialize the array of strings to JSON before sending to the client To make JSON serialization easier than using Foundation’s JSONSerialization class directly, you can use the SwiftyJSON library This library is able to serialize Swift primitive types such as String, Int, and Double, as well as collections containing these primitives such as Array and Dictionary The handler sends the serialized array to the client via the RouterResponse.send(json:) method, which automatically sets the Content-type of the response as application/json so that the client knows how to interpret the result: import SwiftyJSON func handleGetStringItems( request: RouterRequest, response: RouterResponse, callNextHandler: @escaping () -> Void ) throws { response.send( json: JSON(itemStrings) ) callNextHandler() } 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 enumeration 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 different threads To avoid data loss and potential heap corruption, serialize mutations to the itemStrings array with a statically-allocated semaphore: let itemStringsLock = DispatchSemaphore(value: 1) Define the second handler: func handleAddStringItem( request: RouterRequest, response: RouterResponse, callNextHandler: @escaping () -> Void ){ // If there is a body that holds JSON, get it guard case let json(jsonBody)? = request.body else { response.status(.badRequest) callNextHandler() return } let item = jsonBody["item"].stringValue 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"] Deploying Your Application to Bluemix There are many options for deploying a Kitura web application If you use a Docker-based platform, there is a Swift Dockerfile and image at DockerHub If you use a CloudFoundry environment, you can use a Swift buildpack for deploying your application Swift applications are compiled to native binary, which means that the binary must match the platform that will be running the application This ahead-of-time compilation might be different from what you are used to if you use NodeJS, where the code is just-in-time compiled, or Java, where the compiled byte-code runs in a virtual environment The IBM Bluemix cloud application platform supports Swift as a first-class language along with JavaScript (NodeJS) and Java (Liberty) If you choose to deploy your application with IBM Bluemix, you may consider using the IBM Cloud Tools for Swift The tool can be used to generate new starter applications, such as a TodoList service or an image-sharing service It can help you deploy any Swift application to Bluemix You can monitor a deployed application as shown in Figure 5-1 It will also help you configure your iOS application to direct network requests to the URL of the deployed web service once it’s on Bluemix Figure 5-1 IBM Cloud Tools for Swift helps users create new Kitura applications or start with sample applications and deploy them to Bluemix 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 virtual 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 application’s memory requirement, the number of instances, hostname, and the address to the buildpack applications: - name: todolist memory: 256M instances: random-route: true buildpack: https://github.com/IBM-Swift/swift-buildpack.git Next, you must include a Procfile It specifies the executable to run once the instance has been provisioned and ready for running Assuming the executable name is “Server,” the Procfile would be: web: Server When the application runs on Bluemix, it will be automatically assigned a port that it must listen on This port number can be retrieved with the Swift-cfenv library and used in a new HTTP server as follows: import CloudFoundryEnv { let appEnv = try CloudFoundryEnv.getAppEnv() let port: Int = appEnv.port Kitura.addHTTPServer(onPort: port, with: router) } catch CloudFoundryEnvError.InvalidValue { print("Oops, something went wrong Server did not start!") } You might consider adding the preceding code to all of the applications you intend to deploy to Bluemix, because when the application is running on Bluemix, the port will match what Bluemix gives your application However, if these cannot be found in the environment variables, the application is assumed to be running in a development environment, and therefore localhost:8090 will be used instead When you’re ready to deploy your application, you can install and use the Bluemix CLI tools Once installed, you can use the cf utility to push the code to the server: $ cf push This step will take roughly four to five minutes After your application has been deployed, you will see the assigned hostname Navigate your browser or use cURL to test your app: $ curl https://.bluemix.net/v1/string/item More Elaborate To-Do Items You might want a to-do item to have more properties than just a String, for example, ID, completion status, and due date For now, you’ll extend the code so that each item includes an ID and a title Start with a Dictionary Before moving straight to using a structure for this purpose, you will use a dictionary to store these fields Such a Dictionary is denoted by [String: Any], and an array of them by [[String: Any]] Define the array of items and the semaphore: var itemDictionaries = [[String: Any]]() let itemDictionariesLock = DispatchSemaphore(value: 1) This simple, untyped model corresponds so closely to JSON that only small changes are needed to the handlers func handleGetItemDictionaries( request: RouterRequest, response: RouterResponse, callNextHandler: @escaping () -> Void ) throws { response.send(json: JSON(itemDictionaries)) callNextHandler() } func handleAddItemDictionary( request: RouterRequest, response: RouterResponse, callNextHandler: @escaping () -> Void ){ guard case let json(jsonBody)? = request.body, let title = jsonBody["title"].string else { response.status(.badRequest) callNextHandler() return } itemDictionariesLock.wait() itemDictionaries.append( [ "id": UUID().uuidString, "title": title ] ) itemDictionariesLock.signal() response.send("Added '\(title)'\n") callNextHandler() } Register the handlers: router.get ("/v1/dictionary/item", handler: handleGetItemDictionaries) router.post("/v1/dictionary/item", handler: handleAddItemDictionary) Test: $ curl -H "Content-Type: application/json" \ -X POST \ -d '{"title":"Reticulate Splines"}' Added 'Reticulate Splines' $ 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) The transition from a dictionary to a struct requires you to write some code to convert Items to and from JSON Create the conversion routines for Item: enum ItemError: String, Error { case malformedJSON } extension Item { init ( json: JSON ) throws { guard let d = json.dictionary, let title = d["title"]?.string else { throw ItemError.malformedJSON } id = UUID() title = title } var dictionary: [String: Any] { return ["id": id.uuidString as Any, "title": title as Any] } } Write the new handlers: func handleGetItemStructs( request: RouterRequest, response: RouterResponse, callNextHandler: @escaping () -> Void ) throws { response.send( json: JSON(itemStructs.dictionary) ) callNextHandler() } func handleAddItemStruct( request: RouterRequest, response: RouterResponse, callNextHandler: @escaping () -> Void ){ guard case let json(jsonBody)? = request.body else { response.status(.badRequest) callNextHandler() return } { 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) Test: $ curl -H "Content-Type: application/json" \ -X POST \ -d '{"title":"Finish book!"}' localhost:8090/v1/struct/item Added 'Item(id: 054879B8-B798-4462-AF0B-79B20F9617F4, title: "Herd llamas")' $ 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 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 Google 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 proceed 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 authentication: let credentials = Credentials() let facebookCredentialsPlugin = CredentialsFacebookToken() credentials.register(facebookCredentialsPlugin) router.all("/v1/*/item", middleware: credentials) The login flow works as follows: The client must first obtain a Facebook OAuth token using the Facebook login web service If you are developing an iOS application, this is done through the Facebook SDK for iOS If you are developing a web application, you will use the Facebook SDK for JavaScript When the user imports the Facebook iOS SDK, it will allow you to present a Facebook login panel to the user requesting a username and password If the user has already signed into Facebook (and a cache exists with the token), the login screen is bypassed The username and password are sent to the Facebook server through HTTPS and, assuming the username and password checks out, an OAuth token is returned to the client The client then must include that token in the header of future requests to add or get items For Kitura Facebook Credentials to use this token, the client must bundle the token in the access_token header field, and “FacebookToken” in the X-tokentype field for all HTTP requests The user’s Facebook profile information can be read using the userProfile attribute of the RouterRequest The code can obtain the user’s unique user ID from request.userProfile.id For brevity, we did not show how to relate a user ID to the to-do items, but this would be an easy modification to make to the above examples Setting up the Database There are many different databases to choose from if you are building a to-do list in Swift You can see some examples by cloning our example Kitura TodoList applications, which will show you how to interface with some of the most popular databases You will see, for instance, MongoDB, PostgreSQL, Redis, and more There are many different database drivers for Swift in the Swift Package Catalog Some were written using C bindings to existing database drivers written in C, so you may need to install some development headers and libraries before you can use them Others have been developed from the ground up with pure Swift and therefore will not require the installation of any additional libraries In this section, we explain how to use CouchDB with your to-do list We chose this database since it will demonstrate how to make outbound network calls from your server CouchDB uses a simple REST API that receives and accepts JSON payloads CouchDB is supported well on Bluemix as an offering called Cloudant Everything in CouchDB is a document In order to query the database, you must write a special kind of document called a design document that contains some logic that should be run in the database When that logic is run, it prepares a “view” that is returned to the user The map function is run on every document in the database Usually some condition is checked, and if it passes, a new document is emitted containing the values of that document Another kind of logic is the reduce function It is useful for collapsing the documents down to a single document For instance, if you wanted to get the count or the sum of many documents To create a design, open a new file named todolist_design.json, and add the following to it: { "_id": "_design/tododesign", "_views" : { "all_todos" : { "map" : "function(doc) { emit(doc._id, [doc._id, doc.title]); }" } } } Since CouchDB uses a REST API, you can make new designs, add documents, and query for documents all using basic HTTP calls Before showing how to write the Swift code for these network calls, it is helpful to see what the cURL commands would be for each of these operations For instance, to create a new database called todolist: $ curl -X PUT http://127.0.0.1:5984/todolist To upload the todolist_design.json document to the newly created database: $ curl -X PUT http://127.0.0.1:5984/todolist/_design/tododesign \ data-dinary @todolist_design.json Then, in order to get back all the to-dos, you could make a request to: $ curl http://127.0.0.1:5984/todolist/_design/tododesign \ /_views/all_todos To add a new item to the database, you make the call to the database with a UUID for the document ID: $ curl http://127.0.0.1:5984/todolist/ \ -d '{ "title": "Reticulate Splines" }' Now we can show how to make outbound network connections with Swift Connecting to the Database Because outbound network requests introduce a fair amount of complexity to your application, we recommend using a promise library You can add the promise library created in Chapter by adding the following dependency to Package.swift: Package(url: "https://github.com/davidungar/miniPromiseKit", majorVersion: 4, minor: 1) Now, you can extend URLSession to use a promise instead of using a callback: extension URLSession { func dataTaskPromise(with url: URL) -> Promise { return Promise { fulfill, reject in let dataTask = URLSession(configuration: default).dataTask( with: url) { data, response, error in if let d = data { fulfill(d) } else { reject(error!) } } dataTask.resume() } } } By default, the miniPromiseKit and PromiseKit libraries will use the main queue for dispatching the then, catch, and always blocks, so it is important to create a new concurrent queue and use it as the context for executing these blocks: let queue = DispatchQueue(label: "com.todolist.controller", qos: userInitiated, attributes: concurrent) The body of the firstly call returns a promise for the array of items In the examples below, url is the URL for the all_todos view Once the data is returned, we convert it to an array of items In the interest of space, we have omitted the dataToItems method, which does the JSON parsing Refer to it in the example code This method can throw an error if the data could not be parsed properly, and that error can percolate through the promise chain func getAllItems() -> Promise { return firstly { URLSession().dataTaskPromise(with: url) } then(on: queue) { dataResult in return try dataToItems(data: dataResult) } } You can add a task by sending a URLRequest with a PUT method Assume for the sake of this example that URL is the path to the database and the UUID of the item you want to insert—for example, "127.0.0.1:5984/todolist/E71233AD-01D2-430B-8708-F7E2496AEFB2": func addItem(item: Item) -> Promise { return Promise { fulfill, reject in let session = URLSession(configuration: default) var request = URLRequest(url: url) request.httpMethod = "PUT" request.httpBody = try JSONSerialization.data( withJSONObject: item.dictionary, options: []) let dataTask = session.dataTask(with: request) { data, response, error in if let error = error { reject(error) } fulfill(item) } dataTask.resume() } } Next, you can write the handlers Promises help to improve the flow when responding to these error cases They help you write your error handling logic in a linear way The errors “short circuit” to the end of the handler where the code can serialize that error to the client Getting back a list of items takes the following steps: first, all of the items are retrieved from the database as a promise Once that promise is fulfilled, the items can be sent back to the client But if there was an error with servicing the request, the error can be serialized back to the user In all cases, we want the next handler in the chain to be invoked: func handleGetCouchDBItems( request: RouterRequest, response: RouterResponse, callNextHandler: @escaping () -> Void ) throws { firstly { getAllItems() } then(on: queue) { response.send(json: JSON(items.dictionary)) } catch(on: queue) { response.status(.badRequest) response.send(error.localizedDescription) } always(on: queue) { callNextHandler() } } The add item handler also benefits from using promises A new item is parsed from the body, and the item is sent to the database to be persisted If there was an error either with the parsing or with the network connectivity, that error is handled and sent to the client: func handleAddCouchDBItem( request: RouterRequest, response: RouterResponse, callNextHandler: @escaping () -> Void ){ firstly { () -> Promise in guard case let json(jsonBody)? = request.body else { throw ItemError.malformedJSON } let item = try Item(json: jsonBody) return addItem(item: item) } then(on: queue) { item in response.send("Added \(item.title)") } catch(on: queue) { error in response.status(.badRequest) response.send(error.localizedDescription) } always(on: queue) { callNextHandler() } } Register the handlers: router.get ( "/v1/couch/item", handler: handleGetCouchDBItems ) router.post( "/v1/couch/item", handler: handleAddCouchDBItem ) You can now test your application using the same aforementioned cURL statements $ curl -H "Content-Type: application/json" \ -X POST \ -d '{"title":"Finish book!"}' localhost:8090/v1/couch/item Added 'Item(id: 054879B8-B798-4462-AF0B-79B20F9617F4, title: "Finish book!")' $ 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 Swift is a powerful programming language that supports both object-oriented and functional programming Its static type checking, type inferencing, optional types, value types, and closures allow you to write code that is clear, concise, and robust It catches more bugs at compile-time—such as accesses to nil values—than many other popular languages Swift’s facilities ease the implementation of constructs such as promises (a.k.a., futures) that greatly simplify asynchronous programming Its ahead-of-time compilation provides predictable performance and plays nicely with libraries written in other languages such as C Swift is well suited for real applications If you choose to implement your server-side code in Swift, you’ll find the necessary tools to help you The Swift Package Manager aids in importing other libraries into your project and building your application correctly The Kitura library helps get you started quickly building web apps by handling incoming web requests and routing them to your application code Bluemix and the IBM Cloud Tools for Swift provide for easy deployment We hope you consider writing the entire stack of your next application in Swift, from client to sensor to server About the Authors David Ungar holds a Ph.D in Computer Science from U.C Berkeley, 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 implementation, cartoon animation techniques for user interfaces, reflection APIs, IDEs, emergence for massive parallelism, and contextual programming Now he builds iOS and macOS applications Four of his papers have been honored by the Association for Computing Machinery for lasting impact In 2009, he was awarded the Dahl-Nygaard prize for outstanding career contributions to objectoriented 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 engineering 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 webservice 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 serverside 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 Science from the University of Virginia He blogs at https://developer.ibm.com/swift/ and tweets at @rfdickerson ... state, are implemented by the adopter of the protocol Then the protocol extension adds the new cityAndState property to all objects that conform to the Request protocol protocol Request { var city:... and these requests are usually asynchronous; the application does not stop to wait for the result to return These requests may succeed or fail, and often the result contains the input to the. .. can find the temperature at the user’s home The application makes a request to a database to discover where the user lives, then makes a subsequent request to a weather service to get the temperature