Book Image

Hands-On Server-Side Web Development with Swift

By : Angus Yeung
Book Image

Hands-On Server-Side Web Development with Swift

By: Angus Yeung

Overview of this book

This book is about building professional web applications and web services using Swift 4.0 and leveraging two popular Swift web frameworks: Vapor 3.0 and Kitura 2.5. In the first part of this book, we’ll focus on the creation of basic web applications from Vapor and Kitura boilerplate projects. As the web apps start out simple, more useful techniques, such as unit test development, debugging, logging, and the build and release process, will be introduced to readers. In the second part, we’ll learn different aspects of web application development with server-side Swift, including setting up routes and controllers to process custom client requests, working with template engines such as Leaf and Stencil to create dynamic web content, beautifying the content with Bootstrap, managing user access with authentication framework, and leveraging the Object Relational Mapping (ORM) abstraction layer (Vapor’s Fluent and Kitura’s Kuery) to perform database operations. Finally, in the third part, we’ll develop web services in Swift and build our API Gateway, microservices and database backend in a three-tier architecture design. Readers will learn how to design RESTful APIs, work with asynchronous processes, and leverage container technology such as Docker in deploying microservices to cloud hosting services such as Vapor Cloud and IBM Cloud.
Table of Contents (18 chapters)

Introducing Swift

Swift is a high-performance modern programming language that was first announced at the Apple World Wide Developers Conference (WWDC) in September 2014. Thanks to Apple's strong support and endorsement from the developer community, Swift has become one of the fastest growing new languages in computer science history. Swift 2.0 was released in September 2015, followed by Swift 3.0 a year later, and Swift 4.0 in September 2017. There have been two additional releases: Swift 4.1 in March 2018 and Swift 4.2 in September 2018.

As a modern language, Swift offers a clean syntax and many modern programming language constructs. Even though Swift is inspired by many other popular programming languages, Swift is an independent language completed with all the core features of a modern language. We will find the familiar low-level constructs in Swift, such as data structure, classes, functions, enums, as well as many useful modern features, such as protocols, optionals, closures, and generics.

Type safety is enforced from the ground up in Swift. The emphasis of type safety shifts the detection of many nasty errors from runtime to compile time. As a result of dramatically reduced runtime errors, Swift developers enjoy relatively increased productivity and an ease of programming.

Swift keeps many of the constructs found in modern programming languages, but also eliminates some features that are frequently seen in other languages. One example is that Swift uses modules instead of headers, eliminating code duplication often seen in using headers. Moreover, Swift does not support exceptions and an automatic garbage collector. In Swift, memory safety is ensured by default. Instead of a garbage collector, Swift uses a thread-safe Automatic Reference Counting (ARC) for an object's life cycle management.

As a compiled language, Swift is very fast at execution. The source code of Swift is first checked for type safety, then compiled into a machine-independent intermediate code in a Low Level Virtual Machine (LLVM) for optimization, and eventually used to generate machine code that is native to the system. Swift's execution performance often matches that of modern native programming languages and exceeds that of interpreted programming languages.

Open sourcing Swift and components

The official version of open source Swift was first launched in December 2015. Since being opened up to wider community support and development, open source Swift continues to grow in both popularity and maturity in terms of the contribution of open source community and the addition of new features. The contributors to open source Swift include Apple, IBM, PayPal, and other industry and academic institutions.

The effort of the open source developer community is coordinated through the Swift programming language evolution (https://github.com/apple/swift-evolution) process. The process governs the evolution of Swift by defining the process for accepting new proposals, stating the goals for upcoming Swift releases, reviewing and tracking the status of proposals, and specifying the decision-making procedure for accepting or rejecting a proposal. The evolution process ensures that Swift can evolve into a robust language while imposing constraints to maintain application binary interface (ABI) stability. With ABI stability, the binary compatibility between applications and libraries is ensured with different Swift versions.

Open source Swift includes more than the specification of the Swift programming language. On the official website of open source Swift, https://swift.org/, there is information on the fundamental components for the language, including the Swift compiler, standard library, package manager, core libraries, test framework, and REPL/debugger.

The source code repositories for the fundamental Swift components are hosted on GitHub at https://github.com/apple/swift. The following diagram shows the main components in open source Swift:

The license for the open source Swift projects is Apache 2.0 with a runtime library exception (https://github.com/apple/swift/blob/master/LICENSE.txt) .The runtime library exception clause in such a license allows you to compile the code into the binary product and distribute it.

Swift compiler

The Swift compiler translates Swift source code into efficient machine code in an executable way. When parsing the source code, the Swift compiler will perform full type-checking and generate an intermediate language called the Swift Intermediate Language (SIL) for further code analysis and optimization. The intermediate code will then be reduced to Low Level Virtual Machine Intermediate Representation (LLVM IR) (http://llvm.org/) for the LLVM to turn that into machine code:

Swift standard library

The standard library provides basic language and type system support. The core of the standard library includes the definitions of fundamental data types, collections, protocols, algorithm, and low-level primitives. There is also the language support runtime, which is layered between the compiler and the core of the standard library. This runtime handles the dynamic features of Swift, such as typecasting, generics, reflection, and memory management.

Swift foundation framework

The foundation framework comprises features outside of the language and runtime that are common to all applications. The base layer of functionality provided in the foundation framework includes data storage and persistence, string handling, data formatting, date and time support, sorting and filtering, and networking. The design principle for the foundation framework is to keep the features in small sets of utility class, consistent across in convention, and with internationalization and localization support. As such, the foundation framework is highly portable for cross-platform support. There are two foundation frameworks: Objective-C and the open source Swift foundation.

Dispatch framework

The libdispatch is the wrapper for Grand Central Dispatch (GCD), the concurrency library used across all Swift platforms to provide support for concurrent code execution in multicore processors. GCD uses a dispatch queue to achieve the goal of executing tasks in parallel. Each queue is a block of code (task) that can be executed synchronously or asynchronously on the main thread or worker thread. Tasks submitted to dispatch queues are executed efficiently on a pool of threads managed by the system. Submitted tasks are executed serially by default, but several tasks can be configured to run concurrently when submitted to the dispatch queue.

XCTest testing framework

The XCTest library is a common framework for writing unit tests in Swift. Usually, we just have to write the unit tests once and they can be executed across different platforms without rewriting. Each test is organized into an XCTestCase subclass with many different test methods. Each method shall be started with a prefix "test". We can run the tests from a Terminal on Linux or macOS. For Linux, an extra Linux main file with an array containing all available tests is needed. For macOS, XCode CLI tools to execute the tests are required. The XCTest framework is also well integrated into the workflow in XCode. We can use the scheme editor to specify which targets, classes, and methods to include a test, and use the XCode test navigator to run tests and view the results.

Swift Package Manager

We use the Swift Package Manager (SPM) to manage the distribution of Swift projects. The Swift package manager integrates the package dependencies into the Swift build system, automating the downloading, compiling, and linking the other packages that are required in a Swift project. In a typical Swift project, the source code is organized into packages. We use the Swift package manager to set up target executable modules in a project and specify each executable's dependent modules. An executable is a Swift program that can be run by the host's platform. For example, we build one executable module for product release and another executable module for testing.

LLDB debugger

In open source Swift, the LLDB debugger is both a full-featured debugger for Swift and a read-eval-print-loop (REPL) tool for the language. The LLDB debugger is tightly coupled to the Swift compiler itself, in order for it to inspect Swift types accurately and evaluate expressions correctly. REPL takes advantage of the robust debugging features such as breakpoint settings, interactive context during failures, evaluating expressions, reporting, and formatting results at breakpoints.

CommonMark documentation

CommonMark is the built-in Markdown syntax for documenting source code in open source Swift. Markdown is a plain text format for writing structured documents using very straightforward formatting conventions. Open source Swift adopts CommonMark as the implementation of a strongly defined, unambiguous, and highly compatible specification of Markdown.

Bringing Swift to the server-side

Swift has been used extensively for client-side development in iOS, macOS, tvOS, and watchOS. Since the open source developer community brought Swift to the Linux platforms and made Swift a cross-platform programming language, it makes sense for developers to use Swift for server-side development as well.

Client developers that are already skillful with the Swift language and are accustomed to the tools and libraries used in Swift projects, will find the transition to server-side development straightforward. They can enjoy the same benefits offered by Swift in server-side projects: type-safety, ease of programming, and compiled performance. By using Swift in both client- and server-side development, developers are expected to be more productive and more skillful.

Of course, the client developers are required to learn some new server-side skills. The workflow on the client side is very different from that of server-side development. On the client side, developers often work to enhance user interfaces, build data models and develop application logic that works with remote cloud services. For server-side development, they need to be able to implement and test network requests, add logic to handle the requests, and route the requests to other backend modules to handle them.

As developers gain expertise in writing both server and client code, they will share code between the server and a client's modules, and optimize the code for both client and server-side development.

SwiftNIO

It is worth mentioning SwiftNIO here, together with other Swift technologies. Apple's SwiftNIO is an open source server-side kernel that provides low-level networking support to the high-level event-driven network application framework. Even though SwiftNIO is not part of open source Swift, this server-side kernel is the fundamental building block for Swift server-side frameworks such as Vapor 3.0. Support for SwiftNIO was also added to Kitura 2.5 in August 2018.

SwiftNIO targets high-performance protocol servers and clients with Netty-like event loops and asynchronous non-blocking calls. The rationale for SwiftNIO is that using the thread-per-connection model of concurrency for low-utilization connections in any server is highly inefficient. SwiftNIO uses the non-blocking I/O model, so we do not need to wait for data to be sent from the network or received from it. The kernel will notify us when an I/O operation is complete.

Under the hood of SwiftNIO, the event processing for managing the execution of work items is conceptualized into EventLoop, which is similar to a dispatch queue in Swift. There are usually a few event loops per CPU core. Event loops run for the entire lifetime of the application, dispatching events to all the objects they own in a SwiftNIO application. Event loops are grouped into an EventLoopGroup. When an EventLoopGroup receives tasks, it will distribute work around the event loops while ensuring thread safety in doing so.

We usually ask EventLoop to schedule work but the work itself will be done by ChannelHandlers in a Channel. Each file descriptor (socket, file, or pipe) in SwiftNIO is associated with a Channel, which performs operations on top of it. The Channel uses ChannelHandler to process each work item. ChannelHandler can handle either inbound or outbound data traffic or both. A sequence of ChannelHandler objects forms a ChannelPipeline so the data in a channel can be transformed as it passes through each ChannelHandler object in the pipeline.

There are several implementations of Channels in SwiftNIO, which are listed as follows:

  • ServerSocketChannel: A channel for sockets that accepts connections like a server
  • SocketChannel: A channel for TCP connections
  • DatagramChannel: A channel for UDP sockets
  • EmbeddedChannel: A channel for testing purposes

In a summary, SwiftNIO implements basic I/O primitives and protocols at low levels of abstraction. It is narrowly focused on providing a powerful building block for high-level networked applications.