Building A “Serverless” API using Firebase Cloud Functions.

Bakani Pilime
codeburst
Published in
5 min readJan 9, 2018

--

A couple of days ago, as I was taking a shower, I had a Eureka moment! It occurred to me how possible it is to build a complete REST API using Firebase Cloud Functions. At first I thought, “This is just your very ambitious brain mumbling Bakani”, but after really thinking about the possibilities, I was convinced. I even tweeted about it and Abe Haskins said it’s possible and actually wished me good luck. So I set out to prove my theory.

A Bit of Background

I have always wanted to build a news app. I’ve iterated over several different versions of what would this app would be, most of which remain permanent residents of Localhost Valley. With each trial, getting international news was not a challenge because a while ago I discovered NewsAPI.org (or @NewsAPIorg on Twitter). It is a well documented API for news articles from over 60 sources world wide. Being from Zimbabwe, it was a bit of a bummer that Zimbabwean news sites were not on that list of sources.

Fast forward to the launch of Puppeteer (a headless chrome node API), I knew this was how I could finally get local news onto my news app(s). So I built my first web scrapper and I was now able to get almost up-to-date news from Chronicle & The Herald. I simply setup a cron job that would curl the scrapper twice an hour. Then every time I opened my news app I’d have 30 minutes or less fresh local stories. Great right? Yes, but with Firebase I could do more.

But wait, what do you mean ‘Serverless’?

Serverless huh?

Well, I definitely do not mean there are no servers involved. Actually according to Martin Fowler, Serverless architectures refer to applications that significantly depend on third-party services (known as Backend as a Service or “BaaS”) or on custom code that’s run in ephemeral containers (Function as a Service or “FaaS”). This simply means the application developer does not need to worry about provisioning servers and scaling them but simply relies on infrastructure and services already built for all of that. Instead, developers then focus on making their apps awesome and deliver more value to their users.

Scene 3: Enter Firebase Cloud Functions

Firebase is one of the many FaaS vendors out there. Firebase Cloud Functions allow you to have Node.js code which gets run in response to a trigger from any of the suite of Firebase products (Real-time Database, Cloud Firestore, Hosting & Storage). You can setup a function that runs when an image is uploaded to your Storage bucket or a new document is stored in Cloud Firestore.

One of the triggers is HTTPs requests to a given endpoint which can run a function when specified routes are requested. So this means you could setup HTTPs functions that respond to requests using any of the supported HTTP methods which are GET, POST, PUT, DELETE & OPTIONS. The best part is you can test all your functions even locally, read the docs for more.

exports.myAwesomeFunction = functions.https.onRequest((req, res) => {
// ...
});

Since basically this is just node, you can even setup Express in your function. This will allow you to gracefully handle different routes and request methods to your API.

const app = express();

// Automatically allow cross-origin requests
app.use(cors({ origin: true }));

// Add middleware if you want.
app.use(myMiddleware);

// build multiple CRUD interfaces:
app.get('/news', (req, res) => {//...});
app.post('/', (req, res) => {//...});
app.put('/:id', (req, res) => {//...});
app.delete('/:id', (req, res) => {//...});
// Expose Express API as a single Cloud Function:
exports.myAwesomeFunction = functions.https.onRequest(app);

ZimNewsAPI — The API for Zimbabwean News??

Largely inspired by NewsAPI.org, I built my own version which hopefully will get used by other developers as well. This API is basically built using two https functions, one that receives stories from the above mentioned scrapper, and the other that actually responds to traffic from the consumers of the API.

const functions = require('firebase-functions');//Scrapa (Scrapper) Express App
import scrapa from './scrapa';
//Main API Express App
import api from './api';
exports.scrapa = functions.https.onRequest(scrapa);
exports.main = functions.https.onRequest(api);

The Scrapa Function simply waits for stories from the web scrapper. It then stores these stories in a Cloud Firestore database. Because Firestore is a schema-less document database, the story document can easily adapt to the changes as they come from the scrapper. In general a story has a title, description, date when published, an author and source. Sources are also stored in the database and can be requested via the Main API function.

The Main API Function responds to requests made by clients consuming the API. At the time of this writing, the available API endpoints are simply GET /sources and GET /news and these requests are handled by the express routes setup in api.js.

A few Gotchas

1. Verbose endpoints for the functions

When you deploy your function, Firebase gives you an endpoint like https://us-central1-your-project-id.cloudfunctions.net/function_name. This might not be the coolest of URLs to send to your developer friends for them to try out your API. It’s Ok for that background service no one will never know makes a request to such a URL. But… Firebase has got you covered. Just add the following lines to your firebase.json under “hosting”

"hosting":{
// ...,
"rewrites":[
{"source":"/api/**", "function":"main"}
]
}

Now you can use the more friendly Firebase Hosting domain which is https://your-project-id.firebaseapp.com/api or simply https://yourcustomdomain.com/api if you have setup a custom domain.

2. External Network is not accessible on the Spark Plan

This means your Cloud Functions can not make requests to remote services/APIs. Well it does make sense because Firebase is giving you almost everything for free, and they are a business too.

3. Lack of out-of-the-box support for ES6+

Cloud Functions ship with Node v6.11.5. The docs say “The Cloud Functions Node.js execution environment follows the Node “LTS” releases, starting with the v6 LTS release published on 2016–10–18. The current Node.js version running in Cloud Functions is Node v6.11.5". But this can be solved by using a transpiler like Babel.js to turn your ES6+ code into the ES5 or lower i.e Javascript understood by v6.11.5.

The below article is the best way you can achieve this. I highly recommend it.

Conclusion

So after all my brain wasn’t mumbling, it is actually possible to develop a complete REST API using Firebase Cloud Functions. A complete scalable API with HTTPs, who knew?

I look forward to exploring this concept further by including authentication and possibly rate limiting because even though Firebase can handle the heat it would be cool to restrict our “Robot” friends from abusing the service.

Thank you for reading ❤.

--

--

Lover of God, code & food. Backend Developer. Guardian of the localhost.