Swift is a strongly and statically typed programming language that has been used extensively for client-side development in iOS, macOS, tvOS, and watchOS. The open source developer community has brought Swift to the Linux platforms, making Swift a cross-platform programming language. In this chapter, we will explain why the open source developer community has extended Swift for server-side development, and how they have streamlined the workflow for both server and client-side development using the same programming language.
There are several server-side Swift frameworks, and most of them are developed and maintained by the Swift developer community. We will take a closer look at the three top server-side Swift frameworks: Vapor, Kitura, and Perfect. Each of these frameworks has a different set of features and benefits. We hope that you feel comfortable with choosing the right Swift server-side framework for your next server-side project.
In this chapter, we will cover the following topics:
- Introducing Swift
- Surveying Swift server-side frameworks
- Choosing the right framework
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.
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.
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:
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.
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.
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.
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.
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.
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 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.
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.
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.
There are many Swift web frameworks that aim to bring the benefits of Swift to server-side development. We will take a quick survey of several top Swift server-side frameworks now.
Vapor is one of the most popular frameworks, and it enjoys the support of a very active developer community. The support from a developer community means that there are a lot of releases, bug fixes, and help that can be expected. In fact, the development of Vapor has been closely following the Swift evolution development. With the launch of SwiftNIO from Apple, as well as Swift 4.1, the Vapor developer community quickly launched Vapor 3.0 (https://github.com/vapor/vapor/releases/tag/3.0.0), which adopts asynchronous and non-blocking event-driven networking stacks, alongside futures and promises throughout the framework, fully aligning with the latest technology in the Swift ecosystem.
Overall, Vapor caters for both beginner and veteran server-side Swift developers with simple and concise syntax, strong community support, and the appeal of pure Swift implementation.
Kitura, a Swift server-side framework from IBM that is Apache 2.0 licensed, is the result of the enterprise partnership between IBM and Apple, announced in 2014. It goes without saying that the framework has a strong backing from IBM. Kitura is well integrated into IBM's cloud product offerings, including Watson and IBM Cloud. It offers native connectors for some Watson API services, and it is easy to deploy a Kitura project to Bluemix hosting platforms using Kitura CLI. On IBM's website, there are also plenty of educational resources and support for Kitura.
The Kitura framework was migrated to support Swift 4.0 in the Kitura 2.0 that was released in October 2017. In Kitura 2.5, released in August 2018, the framework also added the support of SwiftNIO (enabled using env KITURA_NIO=1 swift build). The development of Kitura follows closely with the evolution of Swift itself.
For many Swift server-side developers, Kitura is an ideal framework choice for tapping into IBM's extensive cloud technology ecosystem and developing with enterprise applications in mind.
Perfect (https://github.com/PerfectlySoft/Perfect) stands out as a mature and powerful Swift server-side framework. The first version of Perfect was released to the public even before Apple made Swift open source in 2015. It offers a complete array of features that a software developer may need for developing a lightweight and maintainable web application. Perfect uses a high-performance asynchronous networking engine called Perfect-Net (https://github.com/PerfectlySoft/Perfect-Net), supports secure sockets layer encryption, and adds the option for WebSockets and iOS push notifications that are commonly required by internet servers. Perfect even provides a macOS desktop application, Perfect Assistant, to help server-side developers with the deployment of their Perfect projects to AWS and Google Cloud.
We see Perfect as a good choice for Swift server-side developers who are looking for a mature and well-balanced framework for developing a scalable and solid web application.
When it comes to choosing the right Swift server-side framework to work with, we shall compare the different frameworks in terms of the several factors that follow:
- How fast is the framework's execution performance?
- How complete are the features that the framework offers?
- What kind of ecosystem does the framework adopt?
- What kind of community support is there for the framework?
Since Swift is a compiled language, server-side frameworks written in pure Swift are not necessarily slower than frameworks written in other native programming languages. However, different Swift server-side frameworks may adopt different low-level software stacks or handle events differently.
If you are interested in evaluating different aspects of a web framework, for example, the performance for handling routing and parsing path parameters, you can use the Benchmark tool (https://github.com/vapor/benchmarks) to generate specific benchmarks for comparison.
Performance is not the only factor we should consider. A production release of web application includes a complete set of robust features. Swift server-side frameworks often offer many useful functions that are common to most applications. Some common feature sets for Swift frameworks are listed as follows:
- CLI tool: Offers tools for generating boilerplates, building, and deploying an application
- Templating engine: Supports templating language for web content
- Networking I/O: Facilitates the handling of requests over the network
- Database ORM: Simplifies the querying for the back-end database
- Logging framework: Helps catch useful information during runtime
- Test framework: Creates unit tests for testing the web application
- Authentication: Provides authentication features, such as user login or social login
- Security framework: Adds encryption to communication and messaging pipelines, and sockets
- Monitoring and diagnostics: Offers real-time monitoring and diagnostics
- User session management: Manages a user's session after login
- Cloud deployment: Helps deploy a server application in an automated way
- Swift support: Updates to the latest Swift version quickly
When choosing the right server-side framework, we will need to check whether any of the features mentioned have already been integrated in the framework, or if integration of third-party libraries that implement such features are easy and straightforward.
Ecosystem here can be interpreted as the choices of libraries or tools that a Swift server-side adopts and integrates into the framework. We may have preferences for some technologies, and at the same time, we may have reasons for avoiding other technologies as trade-offs in the design of our application. Sometimes, the effort will be daunting if we want to integrate a third-party library into the chosen framework that does not have the library included already. The best time-saving tip is to choose the framework that has the most preferred libraries so we can minimize the effort to do integration ourselves.
The main components and choices of third-party libraries in Vapor and Kitura are listed in the following table:
|OS support||macOS, Linux||macOS, Linux|
|CLI||Vapor Toolbox CLI, Vapor Console API||Kitura CLI, Project Generator|
|Templating engine||Leaf||Stencil, Mustache, Markdown|
|Networking I/O||SwiftNIO||Kitura-NIO (use SwiftNIO and NIOOpenSSL), BlueSocket, Kitura-net|
|ORM||Fluent: SQLite, MySQL, PostgreSQL, Redis||Swift-Kuery-ORM, Swift-Kuery:, PostgreSQL, SQLite, Redis|
|Logging||Logging API, PrintLogger, SwiftyBeaver Logging||LoggerAPI, HeliumLogger|
|Route-type validation||Vapor Validation||n/a|
|Authentication||Turnstile||Kitura-Credentials: HTTP, Facebook, Google, GitHub|
|Security||Vapor-Crypto / SwiftNIO SSL||BlueSSLService|
|Monitoring & diagnostics||n/a||SwiftMetrics, Health|
|Orchestration||n/a||Kubernetes / Helm|
|Cloud deployment||Vapor Cloud||IBM Cloud|
In the rest of this book, we will visit most of the previously mentioned technologies again when we learn how to build web applications and services with Vapor and Kitura.
Developer community support is sometimes a deciding factor in the choice of a Swift server-side framework. Strong developer community support means that a framework's feature set is more complete, and there will be enough support when we encounter hurdles in working with the framework.
Vapor enjoys healthy developer community support. Vapor users are well-known for their support and eagerness to help newcomers to Vapor community. There is a lot of activity in social channels. The Vapor community has recently moved their forums from Slack to Discord (http://discord.gg/BnXmVGA). There are also plenty of online learning resources, sample codes, tutorials, books, and community-contributed library plugins available to Vapor users. A word of caution, though: many of the tutorial and learning material for Vapor 2.0 or earlier, are outdated. Due to the substantial changes in Vapor 3.0, especially the migration to asynchronous non-blocking stacks based on SwiftNIO, many of the tutorials need to be revised and updated for Vapor 3.0.
Kitura may have smaller community involvement currently, but IBM's engineers have been active and helpful on GitHub and online forums for new learners of server-side Swift. Kitura has a more complete cloud computing stack. It is easy for users to find the documentation and learning materials for not only the Swift server-side framework but also for other cloud technologies that are often used together with the Swift framework.
Perfect stands out as having extensive tutorials, documentation, and training materials available on its website (https://perfect.org/tutorials.html) for Swift server-side developers. The Perfect framework is more mature, and its learning materials are well-organized. Currently, the Perfect user community has 69 repositories in the Perfect examples (https://github.com/PerfectExamples) repository on GitHub. New Perfect users can use the Slack (http://www.perfect.ly/) channels to interact with other developers and to get help from others.
In this chapter, we have covered open source Swift and its components and learned about the advantages of using Swift in server-side development. We have also reviewed three top server-side Swift frameworks: Vapor, Kitura, and Perfect, and explained how to choose a suitable Swift web framework for your own project. The background material in this chapter helps prepare you for hands-on server-side development. In the next chapter, you will roll your sleeves up and install both Vapor and Kitura frameworks on your system.