BlogAnnounced at MongoDB.local NYC 2024: A recap of all announcements and updatesLearn more >>
MongoDB Developer
Swift
plus
Sign in to follow topics
MongoDB Developer Centerchevron-right
Developer Topicschevron-right
Languageschevron-right
Swiftchevron-right

Building a Full Stack application with Swift

Kaitlin Mahar5 min read • Published May 30, 2022 • Updated May 30, 2022
iOSSwift
Facebook Icontwitter iconlinkedin icon
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


Facebook Icontwitter iconlinkedin icon
Rate this code example
star-empty
star-empty
star-empty
star-empty
star-empty
Related
News & Announcements

Goodbye NSPredicate, hello Realm Swift Query API


Oct 19, 2022 | 6 min read
Quickstart

Working with Change Streams from Your Swift Application


Jan 25, 2023 | 4 min read
Code Example

Building a Mobile Chat App Using Realm – The New and Easier Way


Jul 18, 2023 | 22 min read
Code Example

Building a Mobile Chat App Using Realm – Data Architecture


Mar 06, 2023 | 12 min read
Technologies Used
Languages
Technologies
Table of Contents