Android Tutorial: How to Simulate a Backend in a Serverless App

Michael Ganchas
The Startup
Published in
4 min readNov 12, 2020
Image from https://www.manypixels.co/gallery/

Hi all!

Today I’d like to share with you how we can design a serverless app to be able to invoke third-party APIs outside of its native scope, without the need for a dedicated backend and its server management.

When it might be useful

Let’s suppose we have a mobile app written natively for Android and we’re about to roll out an iOS version. Excluding using some cross-platform technology, it would be useful to abstract the business logic from our native apps and having it available, to both, in a dedicated place.

For this, we might want to implement some (or all) of the following functionalities:

  • Reacting to a document being modified in a database (trigger)
  • Periodically running a piece of code (scheduled)
  • Calling a function to run some business logic or to invoke a third-party API (call)

To simplify each case, let’s use a waiter’s job as an analogy to achieve this:

  • When new customers arrive at the door, it goes to them and accompanies them to their table (trigger)
  • Every half an hour, it will go check if the bathrooms are impeccable (scheduled)
  • Being called by the customer to receive its order and pass that information over to the *third-party* kitchen staff (call)
  • Being asked by the customer for the bill (call)

Details

To achieve the aforementioned, we’re going to use Firebase and what is now called Cloud Functions. There are certainly other good options out there, but, for a free-ish platform, it has a lot of features that we can use to create a robust, fast, and scalable development environment.

I’m currently using it in my MapCrumbs app, and it works like a charm.

As for the coding part, we’re going to use Kotlin for the native code and Node.js for the Cloud Functions’ code.

The first thing we need to do is to configure the project to include the necessary Firebase dependencies. To prevent deviating from this article’s aim, please follow the steps listed here.

Backend

Our backend resides in the newly created “index” (.js or .ts) file. Here is where we’ll write the functions exposed to our app and from where to run the business logic.

Trigger

One of the requirements is to have a function that reacts to when new customers arrive at the door.

For this exercise, it means when a new document for the “customers” Cloud Firestore collection is created. We’ll then check if there’s any table available for that number of customers and book the table if there’s any. Something like the following:

Note: Read more about promises and how to query and update Cloud Firestore collections.

Scheduled

For this one, we want a function that’ll run some piece of code every half an hour. A possible implementation for that could be something like the following:

Note: I couldn't come up with an algorithm for this one :)

Call

For me, this is the most interesting feature. It really mimicks the main goal of a backend, where it will expose business logic functionalities that should have its implementation abstracted from the native app.

We can use these calling functions to either fire-and-forget or to retrieve something back to its invoker.

Let’s see how this can be implemented in our backend.

The “receiveMealOrder” function is an example of a fire-and-forget function, whereas when invoking the “askForTheBill” function, we’ll expect a return value.

Native app

On the native side, we’ll need a component to access the calling functions, to pass them relevant data and wait for its result (if applicable).

Models

We need a representation of a Meal being ordered, which could be something like the following:

When asking for the bill, we’ll be expecting for a result that fits the following representation:

Note: Read more about data classes.

The companion objects holding every property’s name stored as keys will be explained further down.

Backend APIs

Even though we’re currently using Cloud Functions, it’s useful to detach our APIs access components from specific providers, so that if one day we’d want to change it for another provider, we just need to change the implementation, but keeping the abstraction as it is. Read more about this here.

Let’s define our abstractions:

Note: We’re using the suspend keyword because invoking the functions will be done asynchronously.

For this exercise, we’ll use a singleton object for the Cloud Functions’ implementations, that look like this:

Note: We need to map the Meal type to pass it over as an argument for the “receiveMealOrder” function.

Note: We convert the result (data) of the invocation to a Map<*,*> to be able to access the functions return value mapped as key-value pairs. It will require casting each entry’s value when assigning or reading its value.

The await methods will hold the execution until the invocation has finished before it resumes to its scope.

Side note: It would be useful for Kotlin to add a sort of C#’s nameOf(property) to get the property’s name. In this case, there’d be no need to add all the KEY_XXX constants.

Backend Manager

The Backend Manager is the middle layer between the controller and the APIs access components. It is…our good waiter.

It should, at least, have the following behavior:

So, when implementing, it must provide the access to those APIs:

Controllers

For simplicity, let’s just consider button clicks as actions on the customer’s point of view. It could look like this:

Note: We’re using Kotlin’s coroutines to invoke the Cloud Functions in the IO scope and handling the post execution in the Main scope.

That’s it for today. Feel free to ask any questions or add suggestions if you’d like!

Cheers!

Our entities will represent each of the database tables considered for this exercise.

--

--