DEV Community 👩‍💻👨‍💻

Cover image for How to Implement Push Notification with Node.js and Service Worker
Mensaiah
Mensaiah

Posted on • Originally published at blog.mensaiah.com

How to Implement Push Notification with Node.js and Service Worker

Push notification has become an integral part of the web whether you are building a complex social media platform or you are building a simple blog, push notification just makes it easier to get messages across to users on the web easy.

We would be building a mini project to show how push notifications works on the server and client side

Content

So...

What are Push Notifications

Push Notifications are messages sent to a users device whether or not they are currently interacting with your website or application.

How It Works

For push notification to work over the web we need something called Service Workers

Service Worker is a script that works on browser background without user interaction independently.If you need more info on that Click Here

Prequisites

Basic Knowledge of

Let's Begin

We would be starting on the server side
Create a folder for your project let's call our folder my-push-notifier and

Open your terminal and navigate to the folder created then run these commands

npm init -y

npm install express web-push

Create an app.js file

App.js Setup

In the package.json file generated add this to the script object

"start": "node app.js",

Start your server with npm run start or node app.js your server should be running if everything was done correctly

Generating Vapid Keys

Vapid keys are needed before we can send push notifications. Why ?

Well two reasons

The first is to restrict the validity of a subscription to a specific application server (so, by using VAPID, only your server will be able to send notifications to a subscriber).

The second is to add more information to the push notification, so that the push service operator knows who is sending the notifications. If something is going wrong with your notifications, the operator knows who you are and can contact you. Moreover, they can offer you some kind of interface to monitor your push notifications.

Vapid keys can be generated online using

Vapid Keys Generator

OR

In your terminal run this command to install web-push

npm install web-push

Then generate your keys with this command

./node_modules/.bin/web-push generate-vapid-keys

Generated Vapid Keys

Copy the keys generated and save it somewhere.

In the app.js file set up the webpush with your keys

Set Up

Replace {YOUR_EMAIL} with your any email you want to set up with

Registering Push Notification

In our app.js file we would be creating an endpoint that allows users subscribe for push notification,
Create a subscribers.json file, in file add an empty array [], The endpoint gets the subscriber's detail from the request body and saves it to a file

app.post("/subscribe", async (req, res) => {
    try {
        // Subscription Details From the client side , We would get back to this
        const subscription = req.body;
        subscribers.push(subscription);

        // Save the new subscrber to the subscribers file
        fs.writeFileSync("./subscribers.json", JSON.stringify(subscribers));

        res.status(201).send("Subscription Saved");
    } catch (error) {
        console.error(error);
    }
});
Enter fullscreen mode Exit fullscreen mode

Subscribing To Push Notification

Now on the client side, create a client folder in our project folder and create the following files in the client folder

  1. index.html with the following code
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Push Notifications Using Node</title>
    </head>

    <body>
        <h1>Push Notifications Using Node</h1>
    </body>
    <script src="client.js"></script>
</html>
Enter fullscreen mode Exit fullscreen mode
  1. client.js
  2. worker.js

Before we move forward add the following code to your app.js on the server side so html is rendered from the server

const path = require("path")
app.use(express.static(path.join(__dirname, 'client')))
Enter fullscreen mode Exit fullscreen mode

Fist we would be creating a function in client.js that subscribes for push notification on our server for we would be using the browser window navigator


const publicVapidKey = "{VAPID_PUBLIC_KEY}";



async function subscribeToPush() {
    console.log("Registering service worker...");
    const register = await navigator.serviceWorker.register("/worker.js", {
        scope: "/"
    });
    console.log("Service Worker Registered...");

    console.log("Registering Push...");
    const subscription = await register.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array(publicVapidKey)
    });
    console.log("Push Registered...");

    console.log("Subscribing for Push ...");
    await fetch("http://localhost:1999/subscribe", {
        method: "POST",
        body: JSON.stringify(subscription),
        headers: {
            "Content-Type":"application/json"
        }
    });
}



function urlBase64ToUint8Array(base64String) {
    const padding = "=".repeat((4 - base64String.length % 4) % 4);
    const base64 = (base64String + padding)
        .replace(/\-/g, "+")
        .replace(/_/g, "/");

    const rawData = window.atob(base64);
    const outputArray = new Uint8Array(rawData.length);

    for (let i = 0; i < rawData.length; ++i) {
        outputArray[i] = rawData.charCodeAt(i);
    }
    return outputArray;
}
Enter fullscreen mode Exit fullscreen mode

Sending Push Notification

For the tutorial we would be sending notifications every minutes to our subscribers to do that we would create a function in our app.js on the server side

// Sending push notification to subscribers
const subscribers = require("./subscribers.json")
const fs = require("fs")
async  function sendPushNotificaiton() {
    for (let i = 0; i < subscribers.length; i++) {
        const subscription = subscribers[i];
        //Notification Payload, this could contain more information about the notification
        const payload = {
            title: "Push Test", 
            body: " Push Notification Message",
            icon: "https://blog.mensaiah.com/assets/round_logo.png",
        };

        //Pass object into sendNotification
        await webpush.sendNotification(subscription, JSON.stringify(payload));
    }

}

//Send Notification Every Minute
const durationInMillisecond  = 60 * 1000
setInterval(sendPushNotificaiton,durationInMillisecond);

Enter fullscreen mode Exit fullscreen mode

Recieving and Displaying Push Notification

Remember our worker.js file created on the client side. We would be listen for a push notification so it can be displayed


self.addEventListener("push", e => {

    // Data from service
    const data = e.data.json();
    console.log("Push Recieved...");
    self.registration.showNotification(data.title, {
        body: data.body,
        icon: data.icon,
    });
});

Enter fullscreen mode Exit fullscreen mode

You can find more information on displaying push notification here;

Run Application

In our client.js call the subscribeToPush function we created above, NB: Not all browsers support service workers so we would be doing this

// Only subscribe to push notification when browser supports service worker
if ('serviceWorker' in navigator) {
    subscribeToPush().catch(console.log);
}

Enter fullscreen mode Exit fullscreen mode

On your browser (I recommend using chrome), visit http://localhost:1999/ to start recieving notification form the server.
Click on allow when a prompt ask if you want to show notifications

## Conclusion

This tutorial does not exhaust all possibilities of service workers, so I suggest reading and trying out more on the topic. Below are articles I recommend

Top comments (1)

Collapse
 
blavkhadesjazzhr profile image
BlavkhadesJazzHR

Awesome chief

In defense of the modern web

I expect I'll annoy everyone with this post: the anti-JavaScript crusaders, justly aghast at how much of the stuff we slather onto modern websites; the people arguing the web is a broken platform for interactive applications anyway and we should start over;

React users; the old guard with their artisanal JS and hand authored HTML; and Tom MacWright, someone I've admired from afar since I first became aware of his work on Mapbox many years ago. But I guess that's the price of having opinions.