JavaScript

Firebase Cloud Firestore using Node.js

Hello. In this tutorial, we will explain the implementation of Firebase Firestore in the node.js application. The application will be responsible to perform the crud operations.

1. Introduction

Firebase is a Backend-as-a-Service (BaaS) that helps to store real-time data in the database. Allows syncing the real-time data across all devices. Features –

  • Serverless
  • Highly secure
  • Offers minimal setup
  • Provides three-way binding via angular fire
  • Easily access data, authentication, and more
  • Offers JSON storage that means no barrier between data and objects
  • Has a good storage potential

Just like any other storage solution firebase also have some advantages i.e.

  • Limited querying and indexing support
  • No support for aggregation and map-reduce functionality

1.1 Setting up Node.js

To set up Node.js on windows you will need to download the installer from this link. Click on the installer (also include the NPM package manager) for your platform and run the installer to start with the Node.js setup wizard. Follow the wizard steps and click on Finish when it is done. If everything goes well you can navigate to the command prompt to verify if the installation was successful as shown in Fig. 1.

Firebase Firestore in node.js - verifying npm installation
Fig. 1: Verifying node and npm installation

2. Firebase Cloud Firestore using Node.js

To set up the application, we will need to navigate to a path where our project will reside. For programming stuff, I am using Visual Studio Code as my preferred IDE. You’re free to choose the IDE of your choice.

2.1 Setting up the Firebase project

To set up the project implementation we will need a firebase project with the real-time database enabled. Once the project is created copy the firebase configuration which will be used in the .env properties. Refer to Section 2.2.2 for details. You can take a look at this link to quickly create a firebase project in the google console.

2.2 Setting up the implementation

Let us write the different files which will be required for practical learning.

2.2.1 Setting up dependencies

Navigate to the project directory and run npm init -y to create a package.json file. This file holds the metadata relevant to the project and is used for managing the project dependencies, script, version, etc. Add the following code to the file wherein we will specify the required dependencies.

package.json

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
  "name": "node-firebase",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "nodemon index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.19.0",
    "cors": "^2.8.5",
    "dotenv": "^10.0.0",
    "express": "^4.17.1",
    "firebase": "^8.0.1"
  },
  "devDependencies": {
    "nodemon": "^2.0.15"
  }
}

To download the dependencies navigate to the directory path containing the file and use the npm install command. If everything goes well the dependencies will be loaded inside the node_modules folder and you are good to go with the further steps.

2.2.2 Creating an environment file

Add the following code to the environment file. The file will be responsible to have the configuration variables spread across the application for further use.

.env

01
02
03
04
05
06
07
08
09
10
11
12
13
#express server configuration
PORT=3000
HOST=localhost
 
#firebase configuration
API_KEY=your_api_key
AUTH_DOMAIN=app_auth_domain
DATABASE_URL=app_realtime_database_url
PROJECT_ID=app_id
STORAGE_BUCKET=app_storage_bucket
MESSAGING_SENDER_ID=messaging_sender_id
APP_ID=app_id

2.2.3 Creating configuration file

Add the following code to the configuration file. The file will be responsible to import the environment variables from the .env file and perform the initialization assertions. The assertions to helps to avoid the common failures post the application startup.

config.js

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
const dotenv = require("dotenv");
const assert = require("assert");
 
dotenv.config();
 
const {
  PORT,
  HOST,
  HOST_URL,
  API_KEY,
  AUTH_DOMAIN,
  DATABASE_URL,
  PROJECT_ID,
  STORAGE_BUCKET,
  MESSAGING_SENDER_ID,
  APP_ID
} = process.env;
 
// adding init assertions
assert(PORT, "Application port is required");
assert(HOST_URL, "Service endpoint is required");
assert(DATABASE_URL, "Firebase database endpoint is required");
assert(PROJECT_ID, "Firebase project id is required");
assert(APP_ID, "Firebase app id is required");
 
module.exports = {
  port: PORT,
  host: HOST,
  url: HOST_URL,
  firebaseConfig: {
    apiKey: API_KEY,
    authDomain: AUTH_DOMAIN,
    databaseURL: DATABASE_URL,
    projectId: PROJECT_ID,
    storageBucket: STORAGE_BUCKET,
    messagingSenderId: MESSAGING_SENDER_ID,
    appId: APP_ID
  }
};

2.2.4 Creating database configuration

Add the following code to the database configuration file. The file will be responsible to initialize the Firebase configuration required for this application.

db.js

1
2
3
4
5
6
const firebase = require("firebase");
const config = require("./config");
 
const db = firebase.initializeApp(config.firebaseConfig);
 
module.exports = db;

2.2.5 Creating a model class

Add the following code to the model class which will be responsible to map the data to/from the Firebase Firestore collection.

employee.js

01
02
03
04
05
06
07
08
09
10
11
class Employee {
  constructor(id, fullName, age, contact, department) {
    this.id = id; // represents the id generated by the firestore
    this.fullName = fullName;
    this.age = age;
    this.contact = contact;
    this.department = department;
  }
}
 
module.exports = Employee;

2.2.6 Creating a controller class

Add the following code to the controller class which will be responsible to get the data from the client and interact with the Firebase Firestore collection. The class consists of different methods to save a new employee, update/delete/get an employee by id, and get all employees.

employeeController.js

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
const firebase = require("../db");
const Employee = require("../models/employee");
const fireStore = firebase.firestore();
 
// performing crud operations in the firebase firestore
// add
// get all
// get
// update
// delete
 
const addEmployee = async (req, res, next) => {
  try {
    console.log("Adding new employee");
    const data = req.body;
    await fireStore.collection("employees").doc().set(data);
    res.status(201).json({ message: "Record saved successfully" });
  } catch (error) {
    res.status(400).json({ message: error.message });
  }
};
 
const getAllEmployees = async (req, res, next) => {
  try {
    console.log("Getting all employees");
    const employees = await fireStore.collection("employees");
    const data = await employees.get();
    const arr = [];
    if (data.empty) {
      res.status(200).json({ message: "No records found" });
    } else {
      let total = 0;
      data.forEach((item) => {
        const employee = new Employee(
          item.id,
          item.data().fullName,
          item.data().age,
          item.data().contact,
          item.data().department
        );
        arr.push(employee);
        total = total + 1;
      });
      res.status(200).json({
        listing: arr,
        count: total
      });
    }
  } catch (error) {
    res.status(400).json({ message: error.message });
  }
};
 
const getEmployee = async (req, res, next) => {
  try {
    const id = req.params.id;
    console.log("Getting employee= %s", id);
    const employee = await fireStore.collection("employees").doc(id);
    const data = await employee.get();
    if (!data.exists) {
      res.status(404).json({ message: "Record not found" });
    } else {
      res.status(200).json(data.data());
    }
  } catch (error) {
    res.status(400).json({ message: error.message });
  }
};
 
const updateEmployee = async (req, res, next) => {
  try {
    const id = req.params.id;
    console.log("Updating employee= %s", id);
    const data = req.body;
    const employee = await fireStore.collection("employees").doc(id);
    await employee.update(data);
    res.status(204).json({ message: "Record updated successfully" });
  } catch (error) {
    res.status(400).json({ message: error.message });
  }
};
 
const deleteEmployee = async (req, res, next) => {
  try {
    const id = req.params.id;
    console.log("Deleting employee= %s", id);
    await fireStore.collection("employees").doc(id).delete();
    res.status(204).json({ message: "Record deleted successfully" });
  } catch (error) {
    res.status(400).json({ message: error.message });
  }
};
 
// todo - add delete all employees
 
module.exports = {
  addEmployee,
  getAllEmployees,
  getEmployee,
  updateEmployee,
  deleteEmployee
};

2.2.7 Creating a router class

Add the following code to the router class which will be responsible to map the incoming request from the client with the appropriate controller method.

employeeController.js

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const express = require("express");
const {
  addEmployee,
  getAllEmployees,
  getEmployee,
  updateEmployee,
  deleteEmployee
} = require("../controllers/employeeController");
 
const router = express.Router();
 
router.post("/employee", addEmployee);
 
router.get("/employees", getAllEmployees);
 
router.get("/employee/:id", getEmployee);
 
router.put("/employee/:id", updateEmployee);
 
router.delete("/employee/:id", deleteEmployee);
 
module.exports = {
  routes: router
};

2.2.8 Creating an index file

Add the following code to the index file which will be responsible for the application startup and act as a welcome point for the application.

index.js

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
const express = require("express");
const cors = require("cors");
const bodyParser = require("body-parser");
const config = require("./config");
const employeeRoutes = require("./routes/employeeRoutes");
 
const app = express();
 
app.use(express.json());
app.use(cors());
app.use(bodyParser.json());
 
app.use("/api", employeeRoutes.routes);
 
app.listen(config.port, () => {
  console.log("Service endpoint= %s", config.url);
});

3. Run the Application

To run the application navigate to the project directory and enter the following command as shown in Fig. 2. If everything goes well the application will be started successfully on a port number read from the .env file. In this case, the application will be started successfully on a port number – 3001.

Fig. 2: Starting the application

4. Demo

You are free to use postman or any other tool of your choice to make the HTTP request to the application endpoints.

Endpoints

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
// add an employee
// http post
 
// get all employees
// http get
 
// get an employee
// http get
 
// update an employee
// http put
 
// delete an employee
// http delete

That is all for this tutorial and I hope the article served you with whatever you were looking for. Happy Learning and do not forget to share!

5. Summary

In this tutorial, we learned about integrating Firebase in the nodejs application. Firebase offers a real-time database that offers the data to be stored in a JSON format and offers a fast way to implement the BaaS solution. You can download the source code and the postman collection from the Downloads section.

6. Download the Project

This was a tutorial to integrate Firebase in the nodejs application.

Download
You can download the full source code of this example here: Firebase Cloud Firestore using Node.js

Yatin Batra

An experience full-stack engineer well versed with Core Java, Spring/Springboot, MVC, Security, AOP, Frontend (Angular & React), and cloud technologies (such as AWS, GCP, Jenkins, Docker, K8).
Subscribe
Notify of
guest


This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button