How many times were you thinking about writing your backend for mobile apps you are working on? And how many times have you chosen Firebase instead? Are there any better options at the moment?
An asynchronous framework for creating microservices, web applications, and more. It’s fun, free, and open source.
Why backend is needed?
Codeforces WatchR started almost 3 years ago as a pet-project, which used official Codeforces API to simply fetch and display data from server. But with time we came up with many additional features, for which the existing API wasn't convenient or even sufficient. So what to do in such a case?
For a while, we were implementing all the logic on mobile clients. Fortunately enough, we had migrated to Kotlin Multiplatform about a year ago, so at least we needed to implement the logic only once in the common module.
BTW, full story is described in article Kotlin Multiplatform: ready, steady, …
But eventually, we hit the roadblock with features, which are simply can't be done without some kind of real backend:
- working with big amounts of historical and operational data
- storing users' accounts and related data
- communication between users
- sending push notifications and so on
In general, backend is needed for anything, that requires cross-device communication and data/logic centralization.
Why not Firebase?
First of all, Firebase is a great choice for some kinds of projects, especially MVPs (Minimum Viable Product). It allows shipping the first versions of your apps faster and cheaper. But it has 3 disadvantages once you get the traction:
- you are locked inside the platform because all your code heavily relies on Firebase, and you can't simply swap to other services
- aggressive "pay-as-you-go" pricing model without easy-to-set limits, which makes you worry about waking up with huge bills due to DDOS attacks or bugs in your code
- technical limitations of NoSQL databases (Firestore, Firebase Realtime Database) and other Firebase services, which may not be obvious
Shortly, Firebase's main advantage is simplicity, but you certainly can find alternatives with much better flexibility and price/value ratio.
Our previous experience is in mobile development, so we are mainly used to Kotlin and Swift. Even though there is decent progress in bringing Swift to backend, it's not officially supported by Apple and community is rather small.
On other hand, Ktor is officially developed and supported by JetBrains, creators of Kotlin. They aren't only investing into the dedicated team, but also actively promoting the technology, organizing conferences, etc.
Ktor is the first-class citizen of the Kotlin ecosystem, which means deep integration with the language itself and all its features, like coroutines, sealed classes, multiplatform distribution, extensibility, and so on.
Ktor design has been obviously inspired by other popular frameworks. For example, I've noticed a close resemblance to Laravel. So experienced backend developers won't be surprised too much when switching to Kotlin world.
Kotlin is fully compatible with any existing Java libraries or frameworks, so you can easily integrate Ktor with Spring or Hibernate, for example. But of course, there are Kotlin-first libraries for the most popular tasks.
Ktor is a minimalistic modular framework, so there are only a few absolutely necessary things available out of the box. Everything else is implemented as pluggable features, which are injected directly into Pipeline.
The pipeline is a structure containing a sequence of functions (blocks/lambdas) that are called one after another, distributed in phases topologically ordered, with the ability to mutate the sequence and to call the remaining functions in the pipeline and then return to current block.
Pipelines are used in Ktor as an extension mechanism to plug functionality in at the right place. For example, a Ktor application defines five main phases: Setup, Monitoring, Features, Call and Fallback. The routing feature defines its own nested pipeline inside the application’s call phase.
Other than that, Ktor isn't forcing you for any particular approach, so you are free to choose and implement the architecture that fits your needs best.
In our case, we implemented classical MVC (Model — View — Controller) architecture with a public API instead of View and dedicated Interactors, which encapsulate all business logic related to each endpoint.
To create Ktor server, you simply need to create new project, declare the application entry point, and install a few features to start with. In our case, these features are ContentNegotiation and Routing.
At the moment we have a single route, which returns compiled Newsfeed from different sources, ready to be consumed by mobile clients.
GetNewsInteractor is using Codeforces, YouTube, and other repositories to fetch data from 3rd party resources and database, which is abstracted through Exposed library (officially supported by JetBrains as well).
All data transformation happens thanks to another officially supported library — kotlinx.serialization, but you have other popular libraries available too.
The best part here that you can simply copy your API classes from Kotlin Backend to Kotlin Multiplatform common module, and it will work.
Ktor application is compiled to a jar file, which then can be run anywhere you want, from Raspberry Pi to the dedicated AWS instance. We've chosen Heroku for its simplicity, free plans, and transparent subscription-based pricing.
Voilà! We have our own fully-functional backend written in Kotlin, which is perfectly suited to our needs, and open to changes in any direction we would like to take in the future. And we still can use some Firebase on the backend ;)
I hope this article will motivate more mobile engineers to get the full potential from their mobile apps by applying their Kotlin skills on the backend side. Let's unlock more cool stuff together!