Really the first question that needs to be answered before going into why we chose Vapor is why use Swift on the server at all? The basis of that answer to that is quite simple, we write Swift code all the time and are very familiar with it.
Currently we have a server application written in Ruby, which contains a lot of deprecated functionality and obsolete complexity. Now we are at a time where, because of aggressive app usage growth, this application needs to be out-scaled. When the application was first created Swift on the server was not yet an option, but now that it is, this is the ideal chance for a rewrite. The core functionality does not entail very much so rewriting it is not too much work, and we have a backlog that contains features requiring the application to grow. Because we are much more confident with Swift than Ruby, the initial extra effort would later pay off in maintenance and expansion.
Before starting a rewrite we needed to know if all the functionalities needed were available in Swift. Because server-side Swift is such a young technology, and there are but few developers who have experience with it, this meant creating a proof of concept application. For this I researched the different frameworks for server-side Swift. Because the interest in Swift on the server seems to be growing among iOS developers, this blogs details the main reasons why we chose Vapor for our application.
Reason 1: Database queries and relations
Our server application needs to be able to connect to an external PostgreSQL database, and the objects represented by the database tables ideally need to be represented in code to reduce the need for writing extensive queries.
Representing tables in code is similar in both frameworks and does not take a lot of time and makes use of the Swift
Codable protocol. And if you only need basic queries on the database without filtering they are also similar. However, if you often need to add filters to you queries, then Vapor's ORM
Fluent outclasses Kitura's
Swift-Kuery-ORM. If you want to filter in Kitura you need to either use
findAll and then filter the returned objects or write your own function for each kind of filter in an extension of the model. In Vapor it is as easy as creating a query with a filter applied.
To demonstrate, here is the code to get all
Books from the database which have a given publication year with Kitura.
Often if you only need a few results you don't want to first query the database for all objects and then filter the result in code, but you want to query with a filter included. Using
QueryParams you can create a
struct where you add each of the fields you want to filter on. The name must match the name in the
Model. This is a step up, but it is still extra work for each filter.
In Vapor, adding a filter to a query is done by adding a
filter command to the query.
If you need a lot of filtering, then creating a
struct for each of these filters can become a lot of work, while in Vapor you can just chain commands such as
sort on the query. And if this is still not enough, you can always create a raw query on a database connection instead.
Kitura also does not have support for relations between models, though in 2018 they did indicate plans to implement this in the future (see Filtering in Swift-Kuery-ORM). In Vapor this is possible and well-documented. For example, a one-to-many relationship (called a Parent-Child relation in Vapor) between a
Notebook and a
Page can be defined as follows:
While a many-to-many relationship (called a Sibling relation in Vapor) is a bit more complex, because it includes creating a
Pivot, once you understand how they work it is quite easy to add all the relations you need.
Reason 2: Full stack Swift
Kitura has based many of their APIs on standards from the broader web community and their syntax is modeled on Express. Vapor's APIs have been built based on the best practices of Swift code, which also eliminates the need for any non-Swift dependencies.
The heavy use of
Futures in Vapor might dissuade people from using Vapor if they are not comfortable writing more functional style code which includes heavy use of methods like
Kitura looks more concrete than Vapor, because it exposes its async functionality less in its API, preferring to use closures over
flatMap() like methods.
A simple example demonstrates the difference between the two frameworks:
The Kitura code looks a bit more concrete when you take a quick look at it, if you understand how
map() methods work, the Vapor code is easy to understand and more compact. And since we have also used
map() methods are not unknown territory to us.
The eliminated need for any non-Swift dependencies and the syntax together makes Vapor stand out to us as the preferred framework.
Reason 3: Community
While Kitura has had IBM behind it from the start, and thus appealed to large enterprises that absolutely need the stability their slower adoption of new technologies and focus on backwards compatibility brought, the community is a lot smaller than the Vapor community.
The following statistics demonstrate the difference in community size and the results of that difference:
On Stack Overflow there are just under 600 questions tagged with Vapor, and less than a hundred tagged with Kitura. Note that 600 questions is also a very small amount, compare it for example to Swift with more than 250k questions and Django with 220k questions.
From the GitHub statistics you can see that development on Vapor is generally more active, and that the repository for Vapor has more than a thousand forks and over 18k stars, compared to Kitura with just under 500 forks and over 7k stars.
iOS Developer Community Survey
And while this data wasn't available at the moment of making the choice, the results form the iOS Developer Community Survey do support the other data, with 87.2% of having deployed to a production environment with Vapor compared to 14.9% with Kitura.
A larger community and more active development means that getting an answer to your question or a solution to your problem is more likely, and that possible issues found could be solved quicker.
Reason 4: Documentation
Personally, I have found the Kitura documentation to be lacking. Their documentation exists completely of Guides which show how to do some specific things, but don't explain the syntax, nor do they show best practices, a lot of the Guides tell you to write code in
Application.swift, which would make it get cluttered very quickly after adding some functionalities.
When looking into their documentation on databases, models and Swift-Kuery(-ORM) I moved a lot between different sites from IBM and Kitura, instead of having most if not all of the documentation in a central easy to find location.
The Vapor documentation (for
3.0) consist of explanations with examples for each of the official Vapor packages on top of instructions for installation, getting started, and extras such as a style guide. The Vapor documentation very readable and contains database specific examples for i.e. MySQL, PostgreSQL, SQLite.
Succinct, clear and easy to find centralized documentation makes the development process a lot smoother, with less frustration for the developer(s).
The reasons listed in this post are some of the big reasons we had for choosing Vapor, in the end the decision was made after researching multiple options and getting a feel for the different frameworks. For our purpose Vapor is a good fit, but it might not be for everyone.
The code snippets for Vapor in this article are for Vapor 3, the release of Vapor 4 has come with the release of Swift 5.2. If you want to know about the changes between the versions I recommend reading What's New in Vapor 4 - Swift forums. To keep up to date with releases and changes, you can join the Vapor Discord.
We are currently developing our application using Vapor 4. After we have gone live there will be a follow up blog post on our experiences. Subscribe to our newsletter to not miss any new posts or developments.