From iOS Dev to full-stack in no time with Booster đ
Are you an iOS (or mobile) developer who wants to become full-stack in no time? Keep reading!
The Problem
When developing a new app, itâs important to consider which backend stack to use for data synchronization and storage. No-code or low-code platforms like Firebase are often popular choices for app developers because they provide a range of useful features out of the box. While these tools can be helpful for quickly creating an MVP or getting a simple application into production, they may not be suitable for more complex data sets or situations where robust business logic and scalability are required.
On the other hand, setting up and using complex serverless solutions from scratch can be time-consuming and often require a significant amount of effort. There are many different tools and components to manage, and it can be error-prone and involve a lot of boilerplate code. You want to move fast and care most about your business logic, right? Then keep reading.
The good news is that thereâs a new framework called Booster that can make backend development a breeze, even for those who are new to it, thanks to its high level of abstraction.
â
Why this tutorial?
We are two developers from The Agile Monkeys with a strong background in iOS development, but very limited experience with backend production projects. Despite this, we have successfully used the Booster framework in several production projects! We want to share our experience with you, and for that we have created an open-source iOS app and an open-source Booster backend, as well as written two articles detailing the entire process.
- This tutorial covers the iOS integration of a Booster backend, and you can view the iOS code here.
- The tutorial on the Booster backend can be found here, and the Booster code can be accessed here.
In addition, the iOS application built for this tutorial is available on the App Store. The app, called Live Questions, is a tool for live events, keynotes, and Q&A sessions that allows hosts to create a topic and gather questions from other users in real time.
To be transparent, Booster is actually a framework developed by another team within our company. Our backend and event-sourcing experts have been working on creating this high level of abstraction for years. As iOS developers, we have used Booster as if we were external clients of the tool, and have been extremely impressed with the developer experience and support we have received.
In this tutorial, we will guide you through the process of integrating a Booster backend with an iOS app. We assume that you already have a basic understanding of iOS development.
â
WTF is Booster?
The world, businesses, and modern software are all driven by events. As app developers, we understand this concept well, as our apps are designed to respond to user actions and various system and environment events. With Booster, you can build reactive backends that follow this event-driven model, while also enjoying a faster development process thanks to its high level of abstraction. In short, Booster allows you to create reactive cloud-based apps efficiently and effectively.
A backend project using Booster is organized, on-rails, into the following components:
- Commands: Actions that users can take within the system (e.g. create a topic).
- Events: Simple records of facts (e.g. user X reacted to question Y on topic Z). As Booster is an event-driven framework, events are central to the design of a Booster project.
- Entities: The source of truth, representing data about the subjects discussed within your company (e.g. topics, questions, users).
- ReadModels: Public projections of Entities. While Entities are private within the system, ReadModels are publicly accessible (e.g. get topics).
- Handlers: Code that processes commands, reacts to events to trigger other actions, or updates Entities based on new events.
For more in-depth information about Booster and its architecture, we recommend checking out the official documentation.
Booster automatically generates a GraphQL API based on your Commands and ReadModels, which is how your app will communicate with the backend. This API also supports real-time updates through subscriptions using a web socket. Using a GraphQL API is easy and offers numerous benefits over traditional REST APIs, making it an excellent choice for app development!
How to use Booster from your iOS app
To make requests to the GraphQL API exposed by our Booster backend, we need to use a GraphQL library. The best option for iOS is the Apollo client.
Once you have completed the process of creating a Booster backend application (we have a tutorial on this here), you can follow these steps:
1. Add the Apollo dependency to your Xcode project
- Open your Xcode project, go to the File tab in the macOS bar, and click âAdd Packagesâ.
- In the Add New Package window, search for âgithub.com/apollographql/apollo-ios.gitâ and select âAdd Packageâ.
- In the new window that appears, select âApolloâ, âApolloAPIâ, and âApolloWebSocketâ under âPackage Products to addâ.
You can check all the other options available to import Apollo into your project here.
â
2. Set up GraphQL in your project
The Apollo iOS client comes with a command-line interface (CLI) that makes it easy to run code generation, which simplifies the process of working with GraphQL. The CLI will download your Booster GraphQL schema and generate Swift code for your GraphQL queries, mutations, and subscriptions.
Hereâs a brief guide on how to use the CLI:
- Download the code generation CLI tool. Go to the list of Apollo iOS releases on GitHub and find the latest release.In the Assets list for each release, youâll find a pre-built CLI binary called âapollo-ios-cli.tar.gzâ. Download and unzip this file, then move the âapollo-ios-cliâ binary file into the root directory of your project.
- Initialize the code generation CLI. Open a terminal window at the root folder of your project, and run the following command:
./apollo-ios-cli init â schema-name [SchemaName] â module-type embeddedInTarget â target-name [TargetName]
Be sure to replace â[SchemaName]â with the namespace used to scope the generated schema types, and â[TargetName]â with the name of your iOS app as set in your Xcode project. This will create a new configuration file, âApollo-codegen-config.jsonâ, in your root folder.
- Add the schema download method to the configuration file. Youâll need to include the âschemaDownloadConfigurationâ dictionary in the config file and specify the URL of your schema, which is the Booster GraphQL endpoint:
- Create GraphQL files with your queries, mutations, and subscriptions. These are the requests your app will make to the backend. The Apollo code generation tool will look for these files with the .graphql file extension to create the Swift API code.
The public interface of a Booster application consists of Commands and ReadModels. In GraphQL terms, you use mutations for Booster Commands, and queries and subscriptions for ReadModels.
To see examples of queries, mutations, and subscriptions in action, you can check the iOS project. Youâll also find examples of how to filter ReadModels.
- Run the Apollo Code Generation tool. Execute this command in the terminal. It will download your schema and generate the Swift code for the types defined in it.
./apollo-ios-cli generate -f
- Import the generated files to your Xcode project. Drag the updated âgraphqlâ folder into your project (make sure to remove the reference first if youâre re-adding the folder). You should be able to compile your project and make successful GraphQL calls!
Itâs crucial to re-generate the files whenever you make changes to your Booster schema by adding or removing new Commands or ReadModels, or by adding new GraphQL files to your iOS project. This ensures that the frontend and backend are in sync and can communicate effectively.
â
3. Set up the Apollo client
On this project, we needed to execute GraphQL queries and mutations and receive real-time updates via web socket using subscriptions. This way, we can update our UI instantly with any change to our read models. Additionally, we wanted to have an in-memory normalized cache to avoid making unnecessary queries.
Based on those requirements, here is how you could set up the Apollo Client in NetworkClient.swift:
If you want to learn more details about Apollo configurations, you can check the official documentation.
The custom NetworkInterceptorProvider class created in step #2 can be found here. Depending on your applicationâs requirements, you may choose to implement a custom network transport or use Apolloâs DefaultInterceptorProvider. In this app, we needed to restrict access to Boosterâs data to only authorized users, so we implemented a UserManagementInterceptor that adds the userâs access token to the authorization header in each request. However, if your application has different security needs, you may not need to create a custom NetworkInterceptorProvider class.
4. Execute a Query
For example, if we try to use the GetTopic query to fetch a topic by id, we could do the following:
GetTopicQuery matches the query we defined in GetTopic.graphql. Notice that we are taking advantage of the new async/await pattern supported in Swift. As it is not supported yet on Apollo 1.0 by default, we added an extension! You can check it out here.
â
5. Execute a Mutation
Remember that mutations are calls to our Booster Commands. The request is similar to the example above:
â
6. Subscriptions!
Booster provides support for real-time updates using subscriptions via WebSocket. We are taking advantage of Swiftâs asynchronous sequences for this scenario to receive ReadModels updates.
In this example, we subscribe to any question update that belongs to a specific topic:
â
User authentication with Auth0
In our project, only authorized users are allowed to access and interact with the Booster backend. To ensure secure access, Booster uses the OAuth 2.0 protocol for authentication. This protocol involves the use of JSON Web Tokens (JWT) to identify and authorize users. These JWT tokens, also known as access tokens, are issued by an authentication provider such as Auth0, which we are using in this project. Other popular providers that support OAuth 2.0 include Firebase and others.
You can create a free account with Auth0 for your experiments. In our articleon configuring the Booster backend, we provide detailed instructions on how to set up user roles and custom claims in the Auth0 token, which Booster uses to authorize operations. For the iOS counterpart, you just need to follow these steps:
- Create a new native application under Applications in your Auth0 account. Then, follow the official steps to configure the client and obtain the Auth0.plist file for your project. Itâs important to note that we have a Build Script Phase called âAuth0 Plist Selectionâ in our Xcode project, under the LiveQuestions target. This script selects the appropriate Auth0.plist file based on the type of build (development or release). If you only have one environment, you can place the same plist in both folders, or simply remove the script and use a single plist file.
- In AuthService.swift, you can see how we have implemented easy sign in and sign out functionality using the Auth0 framework. It is crucial that you set the audience parameter when signing in, as a missing or incorrect value can result in an incomplete or malformed token. You can use a tool like jwt.io to check the contents of JWT tokens.
The audience parameter refers to the identifier of the custom Auth0 API that you will create for your backend. Donât worry if youâre not sure what this means â we provide a detailed explanation of this step in the authentication section of our backend article.
â
Environment Configuration
Whenever you deploy your Booster development or production environments, youâll see the backendâs endpoints URLs printed in the console. Populate the EnvironmentConfiguration.swift file with these URLs:
And thatâs it! You can now easily interact with your Booster backend from iOS. You can find more details about this app and other Booster use cases by exploring the iOS code on Github.
â
Conclusion
By using Booster, it is possible to create an enterprise-grade, scalable application without needing extensive expertise in cloud technologies or event-sourcing. We found the reactive nature of Booster to be very intuitive and effective in boosting productivity, and we truly believe it has great potential as a solution for building modern, feature-rich mobile apps.
Booster enables mobile engineers to quickly become full-stack developersand manage the backend of their application, making them more versatile and efficient.
Booster is constantly improving. The team is working on new features that will make our lives even easier in the near future. For instance, they are developing a native authentication solution, the ability to delete events and data permanently (currently only logical deletions are possible), and simpler storage options for file uploads. Stay tuned for updates!
If you have any questions or suggestions, donât hesitate to reach out to us on Discord!