Swift
MongoDB Developer Center
chevron-right
Developer Topics
chevron-right
Languages
chevron-right
Swift
chevron-right

Building a Full Stack application with Swift

Kaitlin MaharPublished May 30, 2022 • Updated May 30, 2022
iOSSwift
FULL APPLICATION
facebook icontwitter iconlinkedin icon
random alt
Rate this code example
star-empty
star-empty
star-empty
star-empty
star-empty
I recently
revealed on Twitter
something that may have come as a surprise to many of my followers from the Swift/iOS community: I had never written an iOS app before! I've been writing Swift for a few years now but have focused entirely on
library development
and
server-side Swift
.
A highly compelling feature of Swift is that it allows you to write an iOS app and a corresponding backend – a complete, end-to-end application – all in the same language. This is similar to how using
Node.js
for a web app backend allows you to write Javascript everywhere.
To test this out and learn about iOS development, I decided to build a full-stack application entirely in Swift. I settled on a familiar CRUD app I've created a web version of before, an application that allows the user to manage a list of kittens and information about them.
I chose to build the app using the following components:
  • A backend server, written using the popular Swift web framework
    Vapor
    and using the
    MongoDB Swift driver
    via
    MongoDBVapor
    to store data in MongoDB
  • An iOS application built with
    SwiftUI
    and using
    SwiftBSON
    to support serializing/deserializing data to/from
    extended JSON
    , a version of JSON with MongoDB-specific extensions to simplify type preservation
  • A
    SwiftPM
    package containing the code I wanted to share between the two above components
I was able to combine all of this into a single code base with a folder structure as follows:
Overall, it was a great learning experience for me, and although the app is pretty basic, I'm proud of what I was able to put together!
Here
is the finished application, instructions to run it, and documentation on each component.
In the rest of this post, I'll discuss some of my takeaways from this experience.

1. Sharing data model types made it straightforward to consistently represent my data throughout the stack.

As I mentioned above, I created a shared SwiftPM package for any code I wanted to use both in the frontend and backend of my application. In that package, I defined Codable types modeling the data in my application, for example:
When you use separate code/programming languages to represent data on the frontend versus backend of an application, it's easy for implementations to get out of sync. But in this application, since the same exact model type gets used for the frontend and backend representations of kittens, there can't be any inconsistency.
Since this type conforms to the Codable protocol, we also get a single, consistent definition for a kitten's representation in external data formats. The formats used in this application are:
  • Extended JSON
    , which the frontend and backend use to communicate via HTTP, and
  • BSON
    , which the backend and MongoDB use to communicate
For a concrete example of using a model type throughout the stack, when a user adds a new kitten via the UI, the data flows through the application as follows:
  1. The iOS app creates a new Kitten instance containing the user-provided data
  2. The Kitten instance is serialized to extended JSON via ExtendedJSONEncoder and sent in a POST request to the backend
  3. The Vapor backend deserializes a new instance of Kitten from the extended JSON data using ExtendedJSONDecoder
  4. The Kitten is passed to the MongoDB driver method MongoCollection<Kitten>.insertOne()
  5. The MongoDB driver uses its built-in BSONEncoder to serialize the Kitten to BSON and send it via the MongoDB
    wire protocol
    to the database
With all these transformations, it can be tricky to ensure that both the frontend and backend remain in sync in terms of how they model, serialize, and deserialize data. Using Swift everywhere and sharing these Codable data types allowed me to avoid those problems altogether in this app.

2. Working in a single, familiar language made the development experience seamless.

Despite having never built an iOS app before, I found my existing Swift experience made it surprisingly easy to pick up on the concepts I needed to implement the iOS portion of my application. I suspect it's more common that someone would go in the opposite direction, but I think iOS experience would translate well to writing a Swift backend too!
I used several Swift language features such as
protocols
,
trailing closures
, and
computed properties
in both the iOS and backend code. I was also able to take advantage of Swift's new built-in features for
concurrency
throughout the stack. I used the async APIs on
URLSession
to send HTTP requests from the frontend, and I used Vapor and the MongoDB driver's async APIs to handle requests on the backend. It was much easier to use a consistent model and syntax for concurrent, asynchronous programming throughout the application than to try to keep straight in my head the concurrency models for two different languages at once.
In general, using the same language really made it feel like I was building a single application rather than two distinct ones, and greatly reduced the amount of context-switching I had to do as I alternated between work on the frontend and backend.

3. SwiftUI and iOS development are really cool!

Many of my past experiences trying to cobble together a frontend for school or personal projects using HTML and Javascript were frustrating. This time around, the combination of using my favorite programming language and an elegant, declarative framework made writing the frontend very enjoyable. More generally, it was great to finally learn a bit about iOS development and what most people writing Swift and that I know from the Swift community do!
In conclusion, my first foray into iOS development building this full-stack Swift app was a lot of fun and a great learning experience. It strongly demonstrated to me the benefits of using a single language to build an entire application, and using a language you're already familiar with as you venture into programming in a new domain.
I've included a list of references below, including a link to the example application. Please feel free to get in touch with any questions or suggestions regarding the application or the MongoDB libraries listed below – the best way to get in touch with me and my team is by filing a
GitHub issue
or
Jira ticket
!

References

hamburgerView Code

Copy Link
facebook icontwitter iconlinkedin icon
Rate this code example
star-empty
star-empty
star-empty
star-empty
star-empty
Related
Article
Document our Realm-Powered Swift Frameworks using DocC

May 13, 2022
Tutorial
Most Useful iOS 15 SwiftUI Features

May 12, 2022
News & Announcements
Goodbye NSPredicate, hello Realm Swift Query API

May 26, 2022
Tutorial
Continuously Building and Hosting our Swift DocC Documentation using Github Actions and Netlify

May 10, 2022
Table of Contents