DEV Community

Cover image for Send Push Notification Using Firebase
DrSimple
DrSimple

Posted on

Send Push Notification Using Firebase

Send push notification with Firebase Cloud Messaging

This is a simple example of how to send push notifications with Firebase Cloud Messaging (FCM) using Node.js and Express.

First, you need to set up a Firebase project and enable FCM in the Firebase console. Go to https://console.firebase.google.com/ and click on Create a Project.

Then choose a project name

Choose the type of project

Register the app name:

On register, you will see your credentials and setup instructions:


Click on continue to console.

Generate new private key

You can also generate new Private key by going to Service Accounts and Generate New Private Key section of the Firebase console..

Note:Save your key, which will be in json format somewhere in your project directory.

Express server

Now, you can create a Typescript Express server that sends push notifications using FCM. Here's an example of how you can do it:

npm install express firebase-admin mongoose 
npm i nodemon -g
tsc --init
Enter fullscreen mode Exit fullscreen mode

Create a app.ts file

touch /app.ts
Enter fullscreen mode Exit fullscreen mode

Create your Models and Schemas to hold the device tokens

import { Schema, model, Document } from "mongoose";

export interface IDeviceToken extends Document {
    identifierId: string; // the unique identifier for the user (e.g userId, adminId)
    token: string;
    userType: string;
}

export enum UserType {
    USER = "USER",
    ADMIN = "ADMIN"
}

const DeviceTokenSchema = new Schema<IDeviceToken>(
    {
        identifierId: { type: String, required: true },
        token: { type: String, required: true, unique: true },
        userType: { type: String, required: true, enum: Object.values(UserType) }
    },
    { timestamps: true }
);

const DeviceToken = model<IDeviceToken>("DeviceToken", DeviceTokenSchema);
export default DeviceToken;
Enter fullscreen mode Exit fullscreen mode

Configure database

// db/db.ts

import mongoose from "mongoose";

const connectDB = async () => {
    try {
        await mongoose.connect("mongodb://localhost:27017/fireproj");
        console.log("MongoDB connected");
    } catch (error) {
        console.error(error);
        process.exit(1);
    }
};

export default connectDB;
Enter fullscreen mode Exit fullscreen mode

Configure your firebase admin


import admin from "firebase-admin";
import path from "path"

if (!admin.apps.length) {
  try {
    const serviceAccount = require(path.resolve(__dirname, "./firebase.json")); //firebase.json file we downloaded earlier

    admin.initializeApp({
      credential: admin.credential.cert(serviceAccount),
    });

    console.log("Firebase initialized successfully.");
  } catch (error) {
    console.error("Failed to initialize Firebase:", error);
    throw new Error("Firebase initialization failed.");
  }
}

const fcm = admin.messaging();
export default fcm;
Enter fullscreen mode Exit fullscreen mode

The keys you downloaded earlier are stored in the firebase.json file.

Write a service to save and update your deviceToken

import DeviceToken from "./device.model";
import { NotificationPayload, NotificationService, PushNotification } from "./firebaseservice";

export const saveDeviceToken = async (
  identifierId: string,
  token: string,
  userType: string
): Promise<void> => {
  const existingToken = await DeviceToken.findOne({ token });

  if (!existingToken) {
    await DeviceToken.create({ identifierId, token, userType });
  } else if (existingToken.identifierId !== identifierId) {
    existingToken.identifierId = identifierId;
    await existingToken.save();
  }
};

Enter fullscreen mode Exit fullscreen mode

Write a service to send push notifications

import fcm from "./firebase.config";

export interface NotificationPayload {
  title: string;
  body: string;
  data?: Record<string, string>; 
}

export interface PushNotification {
  token: string; 
  payload: NotificationPayload;
}

export class NotificationService {
  static async sendNotification(notification: PushNotification): Promise<void> {
    const message = {
      token: notification.token,
      notification: {
        title: notification.payload.title,
        body: notification.payload.body,
      },
      data: notification.payload.data || {},
    };

    try {
      const response = await fcm.send(message);
      console.log("Notification sent successfully:", response);
    } catch (error) {
      console.error("Error sending notification:", error);
      throw new Error("Failed to send notification");
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Write a controller to handle save deviceToken and send push notifications

import { Request, Response } from "express";
import  { UserType } from "../model/devicetoken";
import { NotificationPayload, NotificationService } from "../services/push.service";
import { saveDeviceToken } from "../services/devicetoken.service";

export class NotificationController {
    static async saveDeviceToken(req: Request, res: Response) {
        const { token } = req.body;

        try {
            if (!token) return res.status(400).json({ message: "Token is required" });

            await saveDeviceToken("000000000000000000000000", token, UserType.USER)

            res.status(200).json({ message: "Device token saved successfully" });
        } catch (error) {
            return res.status(500).json({ message: "Failed to save device token" });
        }
    }

    static async sendNotification(req: Request, res: Response) {
        const { title, body, token } = req.body;

        try {
            const userNotificationPayload: NotificationPayload = {
                title,
                body
            };
            await NotificationService.sendNotification({
                token, 
                payload: userNotificationPayload,
            });

            res.status(200).json({ message: "Notification sent successfully" });
        } catch (error) {
            res.status(500).json({ message: "Failed to send notification" });
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

In this example, we have two methods in the NotificationController class: saveDeviceToken and sendNotification. The saveDeviceToken method takes a token from the request body and saves it to the database using the DeviceToken model. The sendNotification method takes a title, body, and data from the request body and sends a push notification using the NotificationService class.

To use this controller, you can create a new instance of the NotificationController class and pass it to the Express app:

import express from 'express';
import { NotificationController } from './controller/notification.controller';
import connectDB from './db/db';

const app = express();

app.use(express.json());

connectDB();
app.post('/save-device-token', NotificationController.saveDeviceToken);
app.post('/send-notification', NotificationController.sendNotification);

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});
Enter fullscreen mode Exit fullscreen mode

Package.json


{
  "name": "push-notification-server",
  "version": "1.0.0",
  "description": "A simple push notification server using Node.js and Firebase Cloud Messaging",
  "main": "app.js",
  "scripts": {
    "start": "node dist/app.js",
    "dev":"nodemon app.ts"
  },
  "dependencies": {
    "express": "^4.21.1",
    "firebase-admin": "^13.0.1",
    "mongoose": "^8.8.3"
  }
}
Enter fullscreen mode Exit fullscreen mode

Start your app

npm run dev
Enter fullscreen mode Exit fullscreen mode

Create a test.http file and add the following content


POST http://localhost:3000/send-notification
Content-Type: application/json

{
  "title": "Hello",
  "body": "This is a test notification",
  "token": ["YOUR_DEVICE_TOKEN"]
}
Enter fullscreen mode Exit fullscreen mode
POST http://localhost:3000/save-device-token
Content-Type: application/json

{
  "token": "YOUR_DEVICE_TOKEN"
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)