DEV Community

Caio Ferreira
Caio Ferreira

Posted on • Edited on

Hosting an API in Firebase writen with Typescript and Nest

This week I decided to test if Firebase is suited to a personal project and to do it I needed to discovery how to host an API writen in Typescript with Nest framework and, UOU, it was not an easy task! Because of this, I decided to write down the success path and registry some problems that I had.

As a disclaimer, I know it's a hell of a specificy project and not so many people (if anyone) will build with a stack like this, but if you want you can speed this process with this repository, which I write while making this post as a starter repo.
Now, even if you won't build something with this stack you can get some tips that I will leave at the end of this post and may help you bootstrapting a project with a different stack.

Pre-requisites

You will need the following packages installed:

  • Firebase Tools
  • @google-cloud/functions-emulator
  • WebPack
  • Nodemon

TIP 1

I had seen a lot of people having problems in running the firebase emulator, which is used to run the project locally . I suggest to install in the following way:

  1. If you already have firebase tools installed, uninstall it with $ npm remove -g firebase-tools.

  2. Then, install the package @google-cloud/functions-emulator with $ npm install -g @google-cloud/firebase-functions.

  3. Then, install firebase tools again: $ npm install -g firebase-tools.

Building project scaffold

Create your project folder and enter it

$ mkdir nestjs-firebase
$ cd nestjs-firebase
Enter fullscreen mode Exit fullscreen mode

Use the Firebase CLI to create the initial project

$ firebase init
Enter fullscreen mode Exit fullscreen mode

When you run this command, you will be promped with a configuration menu, then, follow the steps bellow:

  • Mark the Functions and Hosting features with space and press enter. Select the Firebase features we wiil need
  • Set your Firebase project Set your Firebase project
  • Enter n to not install npm dependencies yet Enter n
  • Press enter to use the default hosting directory as public. Press enter
  • Enter n to disable single-app configuration Enter n again

Then, open your favorite code editor. I will be using Visual Studio Code. You will see the following folder structure:
Initial project folder structure

Now enter functions folder with $ cd functions and update the package.json file inside it with the following.

{
  "name": "nestjs-firebase",
  "description": "NestJS app with Cloud Functions for Firebase",
  "scripts": {
    "build": "webpack",
    "serve": "webpack && firebase serve --only functions,hosting",
    "serve:dev": "nodemon -w *.ts --exec npm run serve",
    "deploy": "webpack && firebase deploy --only functions,hosting"
  },
  "dependencies": {
    "firebase-admin": "~4.2.1",
    "firebase-functions": "^0.5.9",
    "@nestjs/common": "*",
    "@nestjs/core": "*",
    "@nestjs/microservices": "*",
    "@nestjs/testing": "*",
    "@nestjs/websockets": "*",
    "@types/express": "^4.0.37",
    "express": "^4.15.4",
    "redis": "^2.7.1",
    "reflect-metadata": "^0.1.10",
    "rxjs": "^5.4.0",
    "typescript": "^2.3.2"
  },
  "devDependencies": {
    "@types/node": "^7.0.5",
    "ts-loader": "^2.3.3",
    "webpack-node-externals": "^1.6.0"
  },
  "private": true
}
Enter fullscreen mode Exit fullscreen mode

Then, run $ npm install. After, create the src folder $ mkdir src and delete index.js. Next, create webpack.config.js $ > webpack.config.js with this.

// webpack.config.js
'use strict';

const nodeExternals = require('webpack-node-externals');

module.exports = {
    entry: './src/server.ts',
    output: {
        filename: 'index.js', // <-- Important
        libraryTarget: 'this' // <-- Important
    },
    target: 'node', // <-- Important
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                loader: 'ts-loader',
                options: {
                    transpileOnly: true
                }
            }
        ]
    },
    resolve: {
        extensions: [ '.ts', '.tsx', '.js' ]
    },
    externals: [nodeExternals()] // <-- Important
};
Enter fullscreen mode Exit fullscreen mode

Now, create the this structure inside src folder, with the following content.
src folder structure

// server.ts
import * as functions from 'firebase-functions';
import * as express from 'express';

import { NestFactory } from '@nestjs/core';
import { ApplicationModule } from './modules/app.module';

const server = express();
const app = NestFactory.create(ApplicationModule, server);

app.init();
exports.api = functions.https.onRequest(server);
Enter fullscreen mode Exit fullscreen mode
// app.module.ts
import { Module } from '@nestjs/common';

@Module({})
export class ApplicationModule {}
Enter fullscreen mode Exit fullscreen mode

Finally, update firebase.json like this.

{
  "hosting": {
    "public": "public",
    "rewrites": [{
      "source": "**",
      "function": "api"
    }],
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

And, if you want to use the root url in your API, you need to delete or rename public/index.html.

TIP 2

If you are on Linux (I don't know if this happens in others OS), you can have problems when running $ firebase serve. It is caused by permission problems and you can solve this in two ways:

  1. Run the serve and deploy commands from firebase with sudo.
  2. Change the owner of the firebase-tools folder in the global node_modules to your user.

I recommend the second way because, otherwise, when the nodemon restart the server it will not kill the previous process, so every restart the firebase tool will see the port 5000 as used and will start to listen in another process and this will pile up in your machine.

Conclusion

Now, you can develop your project and use run it with this commands:

  • To build the app $ npm run build
  • To run the server $ npm run serve
  • To run the server for development $ npm run serve:dev
  • To deploy it to Firebase $ npm run deploy

Wish I helped someone and, if you have questions or suggetions, please leave your comment.

Thank you!

Fonts

https://medium.com/netscape/firebase-cloud-functions-with-typescript-and-webpack-7781c882a05b

https://github.com/ultrasaurus/firebase-functions-typescript

https://stackoverflow.com/questions/44871075/redirect-firebase-hosting-root-to-a-cloud-function-is-not-working

Tips

Tip 1 - Firebase Emulator problem
Tip 2 - Firebase serve commands problem

Top comments (4)

Collapse
 
rezarahmati profile image
Reza Rahmati

great article, although server.ts is different that github source and needs to be updated.

One question, after deploy the api will respond to http requests, I was wondering how can I make a controller to respond to pub/sub or database changes (which firebase supports)

Another question at the end there will be 1 api end point, in matter of micro-srvices we should have fine grained separate apis, (maybe fined grained as modules), what is the best practice for that?

Collapse
 
ayzekuorren profile image
Anatoliy Pogoriliy

Try to use Graphql with nestjs & firebase, Graphql have sub/pub.

Collapse
 
thembeladaphula profile image
Thembela-Daphula

Amazing project. Thank you.

I am in desperate need of your help. I'm creating an app using ionic, can you assist me by showing me how to call data from firebase and do CRUD in an ionic 4 App.

Collapse
 
gueyedsmf profile image
GUEYEDSMF

Great !
Just the @google-cloud/functions-emulator has been deprecated use @google-cloud/functions-framework instead