Our Firebase Tech Stack

When we started Ayrshare we were keen on using an infrastructure as a service platform and avoid server setup, SSL certs, opening ports, etc. Time to market, right. Amongst the many platforms out there we choose Firebase. It was an easy decision for us since we are very comfortable with Firebase having built, and even sold, apps built upon it. If not Firebase our second choice would have been Netlify.

Today and Tomorrow Requirements

The first question we asked was, “What we need today?” If came down to a few criteria:

  • Authentication, ideally having SSO with the major networks
  • Hosting a static single page app (React)
  • Hosting a landing page. We generally don’t like to build the landing pages in React.
  • A database, preferably noSQL
  • Back-end running NodeJS, preferably serverless
  • Event tracking, e.g. Google Analytics
  • Email service
  • Payment service

Second, we asked, “What we might need tomorrow?”

  • iOS and Android apps
  • Mobile app push notifications
  • ML (machine learning)

Our Stack

We have built on many platform: AWS, Heroku, under our desk (not kidding), and Digital Ocean. We ended up choosing Firebase since it meets a lot of our needs, but certainly not all.

Firebase is a good choice for SPA React hosting and Firestore as a noSQL database. Google Analytics comes built into Firebase. Also, using Firebase’s authentication UI system allowed us to have a secure registration and login process integrated with major SSO providers like Google, Facebook, and GitHub.

The landing page we built in WordPress hosted on Siteground. There are so many great templates and plugins available for WordPress that we see no reason to recreate the wheel in React. Another option we considered was Gatsby hosted on separate Firebase project.

Sending emails requires a mail provider and we are accustomed to using Mailgun. Firebase has recently introduced Extensions, prebuilt cloud functions. One of our favorite is the Email Trigger extension that facilitates sending email from your cloud functions.

For a payment system, we choose Stripe. Stripe has a really nice NPM package that makes integration relatively easy.

Finally, we decided right before launch to add a link shortener, which is very useful when publishing to networks like Twitter that limit the characters. At first we were going to go with bit.ly, but it would soon become more expensive than what we were charging users. We ultimately went with Firebase’s Dynamic Links, Google’s replacement for goo.gl. Dynamic Links real power are with mobile apps, but it can also be used as a link shortener if you are willing use the RESTful API calls.

Firebase Cloud Functions & APIs

Ayrshare is build as an API first platform, so it is critical to have a robust API system. Building a Cloud Function for each API endpoint is not flexible or secure. However, you can add Express to Cloud Function and it is an excellent and battle tested framework to build and expose APIs.

For example, you can add several security and API facilitating packages such as:

const express = require("express");
const cors = require("cors");
const bodyParser = require("body-parser");
const helmet = require("helmet");
const rateLimit = require("express-rate-limit");

If you do add Express, you can add the “app” as an http function and export it.

const app = express();
exports.api = functions.https.onRequest(app);

And then add you typical express functions.

app.get("/fun", (req, res) => {
  console.log("hello fun");
  return res.send('"Hi fun");
});

Looking Towards the Future

In the future we plan on building mobile apps, especially for allowing Instagram posting, and will require push notifications. In previous projects we used Firebase’s Cloud Messaging (FCM) system and found it easy, reliable, and free!

And if we really look ahead, we want to add some ML analysis on ideal posting times. The current Firebase ML offering doesn’t seem a great fit, but perhaps it will be in the future.

Note on Rate Limit

We had an interesting discussion on Reddit regarding the use of express-rate-limit. See the code above for details.

We use express-rate-limit to manage API requests per IP so a user doesn’t make 1000 requests a minute. If you use the express-rate-limit default in-memory state storage, every time Cloud Functions re-initializes your code (and cold starts) and all modules are reloaded and the in-memory rate count starts from zero. For example, if you specify the rate limit to be 20 requests per hour and a user hits their limit, but a cold start occurs, the user could make another 20 calls within that hour.

The right way is to use an external storage for rate limit tracking. Luckly, there are packages that integrate with Redis, Memcache, and MongoDB.