Firebase Cloud Functions with firebase-backend package by FilledStacks
Tags: flutter, firebase, typescript, serverless
Published: 2021-03-28 02:46:22

# Introduction

In this article, we will learn about how to use [firebase-backend](https://www.npmjs.com/package/firebase-backend) package by [FilledStacks](https://www.filledstacks.com/). Why does this package exist and why should we use it? Let's think of a scenario where your app will have a lot of cloud functions, you can export these into their own separate files but it might be challenging or you might have to structure it in a certain way it is maintainable and easier for you. Firebase Backend package handles this for you but we have to follow certain conventions otherwise during build your defined function wouldn't be recognized and will not be deployed, this means Firebase Backend is opinionated in my opinion.

There is a video tutorial for this package which Dane Mackier explains from Fireship's YouTube channel, so in case you haven't seen the video yet here is the link for you to watch

https://www.youtube.com/watch?v=W_VV2Fx32_Y

Also be sure to subscribe to [Fireship](https://www.youtube.com/channel/UCsBjURrPoezykLs9EqgamOA) and [FilledStacks](https://www.youtube.com/channel/UC2d0BYlqQCdF9lJfydl_02Q) channel, they both produce quality content for Firebase and Flutter!

Otherwise if you prefer learning it here, continue to read!

# Installation

Suppose you already have a Firebase project created from the console and in your code base as well, but make sure you enable Firebase Blaze plan to enable Cloud Functions. Now let's get right to it:

While you are in your root directory, install the package via NPM

```bash
$ npm install firebase-backend
``` 

Once that is done we can then proceed to setup `index.ts` or `index.js` file. But in this article I will choose TypeScript so we will be setting up `firebase-backend` package on `index.ts`

```ts
import { FunctionParser } from "firebase-backend";
import * as admin from "firebase-admin";

admin.initializeApp();

exports = new FunctionParser(__dirname, exports).exports;
```

Here we import `FunctionParser` from `firebase-backend` and we also import `firebase-admin` suppose that we will use Firestore with Admin SDK. This is the only place we initialize admin by `admin.initializeApp()`

Then we set the `exports` with the returned value from the `FunctionPaser` exports

# File Structure

When using this package, your file structure would be in a feature based structure and have two sub-directories to distinguish whether it is a REST endpoint or a cloud function that is event driven based on Firestore queries (onCreate, onDelete, onUpdate, onWrite)

```
src/
 - orders
   - reactive
     - onOrderCreated.function.ts
   - restful
     - confirmOrder.endpoint.ts
index.ts
```

`orders` is a feature folder then it contains `reactive` sub directory and `restful` sub directory. Where `reactive` are the ones that are event driven and listens to any changes from Firestore queries and the `restful` sub directory is our REST endpoints and can be accessible with any specified HTTP methods (GET, POST, PUT, DELETE, etc)

As you may have noticed under `reactive` folder we name the file as `onOrderCreated.function.ts` where `onOrderCreated` is the cloud function name and `function` will tell the FunctionParser that this is a cloud function, in its code we will also call it `onOrderCreated` 

### onOrderCreated.function.ts

```ts
import * as functions from "firebase-functions";

exports.onOrderCreated = functions.firestore
  .document('orders/{orderId}')
  .onCreate((snapshot, context) => {
     // code
  })
```

alternative way of doing it is,

```ts
import * as functions from "firebase-functions";

export const onOrderCreated  = functions.firestore
  .document('orders/{orderId}')
  .onCreate((snapshot, context) => {
     // code
  })
```

### confirmOrder.endpoint.ts

And now for creating the REST endpoint we import `Endpoint` from `firebase-backend` and the enum `RequestType` as well to tell what HTTP method should be used to access this endpoint

```ts
import { Request, Response } from "express";
import { RequestType, Endpoint } from "firebase-backend";

export default new Endpoint(
  "confirmOrder/:id",
  RequestType.PATCH,
  (request: Request, response: Response) => {
  const params = request.params
   
  response.status(200).json({ message: `Order confirmed for ID ${params.id}` })
})
```

And that's how we define our cloud functions and a REST endpoint

# Building and deployment

Before anything else, we must install `rimraf` and make a little bit of configuration on or `package.json` file

Now install `rimraf` as a dev dependency via

```bash
npm i -d rimraf
```

And let us then modify our `package.json` under scripts

```json
"scripts": {
    ...
    "clean": "rimraf lib/",
    "prebuild": "npm run clean",
  },
```

Now just add "clean" and "prebuild", where "prebuild" will always get executed every time you execute a build

Once that is done you can start up your emulators and test it out or you can then deploy your cloud function to Firebase servers.

# Conclusion

The `firebase-backend` package definitely helped us to structure a production level code for our Cloud Functions, this means our Cloud Functions is maintainable, readable, and very good for debugging because of how we name things and how `firebase-backend` encourages us to do that.

This is still a new package by FilledStacks but definitely it is a good one and one I would use for any of my apps that will get built for production.

FilledStacks always impresses me so if you like Flutter be sure to check out https://www.filledstacks.com/

That is all I have and thank you for taking the time to read this article, I appreciate it and I am happy if this was anything that helped you out. Cheers!