RST Software
Editorial Team
Ross Krawczyk
Reviewed by a tech expert
Szymon Bartczak

Setting up NestJS with Firebase Functions

#Sales
#Sales
#Sales
#Sales
Read this articles in:
EN
PL

What if we could deploy a backend application in just a few steps, without going through the overly complicated configuration process? Imagine doing so without worrying if it can keep up with incoming traffic and get all these domain certificates already on board. This is actually possible with Firebase Functions and any framework based on Express (including Express itself).

Firebase Functions is an alternative to AWS Lambda, created with ease of use and fast deployment in mind. According to official documentation, “Functions let you automatically run backend code in response to events triggered by Firebase features and HTTPS requests.” You can write any JS code and run it with a simple request or by setting up a trigger. What is more, Functions require exactly the same parameters as ExpressJS, meaning we can just forward anything through Functions, and let Express take care of it. This enables the use of the service as a deployment server for the whole backend application.

“NestJS is a framework for building efficient, scalable Node.js server-side applications.” Nest philosophy is to provide good architecture, regardless of the size of the project. Since its architecture was inspired by Angular, it takes advantage of most modern JavaScript and TypeScript practises. Under the hood, it uses either Express or Fastify. We can use this to our advantage, using Express from Nest as a Firebase Function.

Why?

The entire deployment process is very hard to set up right and fast using Kubernetes or Docker. If you are creating a small side project or a startup with little traffic, you want to cheaply set up deployment in minutes. Firebase Functions are (to some extent) free and do all the necessary stuff like load balancing and SSL out of the box. It’s a good match for such needs.

But why mix it with NestJS? Of course, you can simply create a small function to do the exact task you need, but sometimes a more organised structure with more possibilities is needed. NestJS is a good candidate when planning to write a microservice, but it’s also a great tool for a standard backend app.

Pre-setup

Before we begin to set up the whole application, there are some preparations we have to take care of:

  1. Download Firebase CLI – it will be needed for deployment and initial configuration
    $ npm install -g firebase-tools
  2. Create Firebase project (optionally) – this will come in handy when setting up Firebase Functions, because we can already select a project during this process. You can create a new project here: https://console.firebase.google.com. Projects can also be created with the firebase init command.
  3. Download Nestjs CLI – this step could be considered optional, but will massively speed things up, so I’ve decided to keep it. If you really don’t want this module, you can skip it and configure the nest project by yourself, or use some kind of boilerplate.
    $ npm install -g @nestjs/cli

Setup

Now, once you are ready, go to the directory where you want your project to be stored. Please note that you don’t have to create a project directory – it will be created automatically in the 1st step.

  1. Create a Nest project as usual. I’ve chosen the standard way by executing:
    $ nest new project-name
    This will automatically generate directory, all startup files, configuration (including package.json) and initialize the Git version control system.
  2. Login to Firebase:
    $ firebase login
  3. Go to project directory and initialize Firebase Functions:
    $ firebase init functions

There will be 4 steps:

  1. Associating a project.
    From there, you can select the project you created. This will be treated as the default project. This can be modified later if you want.
  2. Choosing language.
    Select TypeScript, as Nest use TypeScript.
  3. Lint configuration.
    It’s up to you whether you want the Firebase Tslint config, but because it’s deprecated, I don’t recommend it. Configure Eslint for your project on your own.
  4. Installing dependencies with npm
    I wouldn’t recommend doing it, because we will use package.json generated by Nest.

Modify package.json

Go to the functions directory and open package.json. We will copy part of this file to package.json in the project directory.

Copy scripts

"serve": "npm run build && firebase serve --only functions",
"shell": "npm run build && firebase functions:shell",
"start": "npm run shell","deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"

If you are using yarn, you should also change all npm run -> yarn

Setup Node version

Firebase supports Node 8 and Node 10 (still Beta when writing this article). Node 8 is what was generated by Firebase, so I left it as is.

"engines": { "node": "8" },

Copy the necessary dependencies

"dependencies": {
"firebase-admin": "^8.6.0",
"firebase-functions": "^3.3.0"
},

"devDependencies": {
"typescript": "^3.2.2", – this is probably already added
"firebase-functions-test": "^0.1.6" – this is optional
},

Setup main

"main": "dist/index.js"

The file should look like this:

{
"name": "nest-functions",
"version": "0.0.1",
"description": "",
"author": "",
"license": "MIT",
"main": "dist/index.js",
"engines": {
"node": "8"
},

"scripts": {
"build": "rimraf dist && tsc -p tsconfig.build.json",
"serve": "npm run build && firebase serve --only functions",
"shell": "npm run build && firebase functions:shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log",
"format": "prettier --write "src/**/*.ts"",
"start": "ts-node -r tsconfig-paths/register src/main.ts",
"start:func": "npm run shell",
"start:dev": "tsc-watch -p tsconfig.build.json --onSuccess "node dist/main.js"",
"start:debug": "tsc-watch -p tsconfig.build.json --onSuccess "node --inspect-brk dist/main.js"",
"start:prod": "node dist/main.js",
"lint": "tslint -p tsconfig.json -c tslint.json",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json"
},

"dependencies": {
"@nestjs/common": "^6.7.2",
"@nestjs/core": "^6.7.2",
"@nestjs/platform-express": "^6.7.2",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.0",
"rxjs": "^6.5.3",
"firebase-admin": "^8.6.0",
"firebase-functions": "^3.3.0"
},

"devDependencies": {
"@nestjs/cli": "^6.8.1",
"@nestjs/schematics": "^6.6.6",
"@nestjs/testing": "^6.7.1",
"@types/express": "^4.17.1",
"@types/jest": "^24.0.18",
"@types/node": "^12.7.5",
"@types/supertest": "^2.0.8",
"jest": "^24.9.0",
"prettier": "^1.18.2",
"supertest": "^4.0.2",
"ts-jest": "^24.1.0",
"ts-loader": "^6.1.1",
"ts-node": "^8.4.1",
"tsc-watch": "^2.4.0",
"tsconfig-paths": "^3.9.0",
"tslint": "^5.20.0",
"typescript": "^3.6.3"
},

"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],

"rootDir": "src",
"testRegex": ".spec.ts$",
"transform": {
"^.+\.(t|j)s$": "ts-jest"
},

"coverageDirectory": "./coverage",
"testEnvironment": "node"
}
}

Remove the functions directory, as it is not needed anymore

Modify firebase.json

We need to tell Firebase where to look for functions. Firebase is looking for the index file in the specified directory. Since firebase.json is in the same directory as the Nest application, we can just add:

"source": "."
Important! This should be added inside the functions property.

The whole file should look like this:

{
"functions": {
"predeploy": "npm --prefix "$RESOURCE_DIR" run build",
"source": "."
}
}

Run package installation

$ yarn or $ npm install

Create the index file as an entry point

The file should be located in the same directory as the source of firebase.json.

import { NestFactory } from '@nestjs/core';
import { ExpressAdapter } from '@nestjs/platform-express';
import * as express from 'express';
import * as functions from 'firebase-functions';
import { AppModule } from './app.module';

const expressServer = express();

const createFunction = async (expressInstance): Promise => {
const app = await NestFactory.create(
AppModule,
new ExpressAdapter(expressInstance),
);
await app.init();
};

export const api = functions.region('europe-west1')
.https.onRequest(async (request, response) => {
await createFunction(expressServer);
expressServer(request, response);
});

The essential thing is whatever you name that exported variable, that will be the name of the function in Firebase Functions. I called mine api, so the entry point to my application will be {FIREBASE_ADRESS}/api.

Another critical thing is that if you don’t specify a region, it’s set by default to us-central1.

OK, that’s it for now, I hope you like this article, and you’ll find it useful! Cheers!

People also ask

No items found.
Want more posts from the author?
Read more

Want to read more?

Web

Post-deployment application performance monitoring

If you're a member of a development team (particularly a tester), this place is perfect for you. At a certain stage of the project, you publish the application.
No results found.
There are no results with this criteria. Try changing your search.
en