DEV Community

Cover image for 🗨️ Build a WhatsApp API using Node & Express
Max Programming
Max Programming

Posted on • Updated on • Originally published at blog.usmans.me

🗨️ Build a WhatsApp API using Node & Express

hey.gif

Today, you will be able to build a WhatsApp REST API using Node.js and Express using Puppeteer and web scraping.

Although we won't be doing any web scraping, we will use a library that does everything for you already and makes it very easy to work with WhatsApp programmatically.

Setup

Express server setup

To set up the express server, we are not going to do it from scratch, we'll use a generator called express-draft by YoursTruly. Firstly, install express-draft globally and use the following command to generate an express app.

npm i -g express-draft
exp .
Enter fullscreen mode Exit fullscreen mode

image.png

Install Whatsapp Web library

Caution: Installing this package will also download Chromium because of Puppeteer. To disable Chromium download, follow the steps on this post

So there's an awesome open-source Whatsapp client that connects through the Whatsapp Web browser app made by Pedro S. Lopez.

GitHub logo pedroslopez / whatsapp-web.js

A WhatsApp client library for NodeJS that connects through the WhatsApp Web browser app


WWebJS Website


npm Depfu WhatsApp_Web 2.2346.52 Discord server


About

A WhatsApp API client that connects through the WhatsApp Web browser app

The library works by launching the WhatsApp Web browser application and managing it using Puppeteer to create an instance of WhatsApp Web, thereby mitigating the risk of being blocked. The WhatsApp API client connects through the WhatsApp Web browser app, accessing its internal functions. This grants you access to nearly all the features available on WhatsApp Web, enabling dynamic handling similar to any other Node.js application.

Important

It is not guaranteed you will not be blocked by using this method. WhatsApp does not allow bots or unofficial clients on their platform, so this shouldn't be considered totally safe.

Links

Installation

The module is now available on npm! npm i whatsapp-web.js

Note

Node v18+ is required.

QUICK STEPS TO UPGRADE NODE

Windows

First, we'll install it through NPM or yarn.

npm i whatsapp-web.js
Enter fullscreen mode Exit fullscreen mode

After we're done with that, we can set it up in our app.js file by following the given example.

We can alter the file as follows,

const express = require('express');
const createError = require('http-errors');
const morgan = require('morgan');
const { Client } = require('whatsapp-web.js');
require('dotenv').config();

const SESSION_FILE_PATH = './session.json';
let sessionCfg;
if (fs.existsSync(SESSION_FILE_PATH)) {
  sessionCfg = require(SESSION_FILE_PATH);
}

const client = new Client({
  puppeteer: { headless: false }, // Make headless true or remove to run browser in background
  session: sessionCfg,
});

client.initialize();
Enter fullscreen mode Exit fullscreen mode

While using this library, whenever a user logs in, their information will be stored in a session.json file, which is then used to authenticate the user the next time when the server starts.

Important: Create a nodemon.json file in the root folder and add these contents to ignore the session.json file whenever it changes.

// "$schema" can be omitted it's used for IntelliSense. REMOVE THIS COMMENT
{
  "$schema": "https://json.schemastore.org/nodemon.json",
  "ignore": ["session.json"]
}
Enter fullscreen mode Exit fullscreen mode

Creating routes and user login

Using events

whatsapp-web.js has a lot of events to work with, and we'll now use some of them to get the QR code, check the authentication, etc.

// Add this after express code but before starting the server

client.on('qr', qr => {
  // NOTE: This event will not be fired if a session is specified.
  console.log('QR RECEIVED', qr);
  app.get('/getqr', (req, res, next) => {
    res.send({ qr });
  });
});

client.on('authenticated', session => {
  console.log('AUTHENTICATED', session);
  sessionCfg = session;
  fs.writeFile(SESSION_FILE_PATH, JSON.stringify(session), function (err) {
    if (err) {
      console.error(err);
    }
  });
});

client.on('auth_failure', msg => {
  // Fired if session restore was unsuccessfull
  console.error('AUTHENTICATION FAILURE', msg);
});

client.on('ready', () => {
  console.log('READY');
});

// Listening for the server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`🚀 @ http://localhost:${PORT}`));
Enter fullscreen mode Exit fullscreen mode

The above code uses events provided by the library to tackle different situations. They are pretty self-explanatory so I am not gonna explain each of them.

In the "qr" method, we create a route that sends the QR code as the response. The QR code is in raw format, meaning it needs to be generated so for the purpose of this tutorial, we'll use a library called qrcode-terminal to show the QR Code in the terminal.

// Run `npm i qrcode-terminal` before this

const qrcode = require('qrcode-terminal')

client.on('qr', qr => {
  // NOTE: This event will not be fired if a session is specified.
  console.log('QR RECEIVED', qr);
  qrcode.generate(qr, { small: true }); // Add this line
  app.get('/getqr', (req, res, next) => {
    res.send({ qr });
  });
});
Enter fullscreen mode Exit fullscreen mode

The sendmessage endpoint

Now that we have everything set up, let's do the most exciting part that is to send a message using our own API.

For that, we create a route in the app.js file itself.

Let's create the POST endpoint for sendmessage and it will be an async function with a try-catch block.

app.post('/sendmessage', async (req, res, next) => {
  try {
    // Magic happens here
  } catch (error) {
    next(error)
  }
})
Enter fullscreen mode Exit fullscreen mode

In the body of the request, the user has to enter two pieces of data.

  1. Mobile number
  2. Message

We'll identify those as number and message respectively. Hence, we get them from the request body, and use them to very easily send the message from the client to the given number.

To send a message, we use the client.sendMessage method and these are the arguments we need to pass in

image.png

app.post('/sendmessage', async (req, res, next) => {
  try {
    const { number, message } = req.body; // Get the body
    const msg = await client.sendMessage(`${number}@c.us`, message); // Send the message
    res.send({ msg }); // Send the response
  } catch (error) {
    next(error);
  }
});
Enter fullscreen mode Exit fullscreen mode

Now here, in the sendMessage method, we pass in the mobile number and the message itself. With the mobile number, we have to attach @c.us at the very end, so we do that with template literals in JavaScript.

Testing the API

In order to test our API, we first run it using npm run dev. That will open up a browser (if you've set headless to false)

Running the server will give us the QR Code to authenticate because it's the first time. So, you have to scan it through WhatsApp.

image.png

Once authenticated, you will notice that a session.json file has been created with the following contents.

image.png

Now in VS Code itself, we'll use an extension called Thunder Client, which works like Postman for API testing. Here's the link

image.png

Create a New Request in Thunder Client, and then add the following details. In the number field, add the mobile number followed by the country code of the number.

image.png

Look at the image carefully

And then hit Send.

If the message is sent successfully, the number you entered will receive it and you will get back the msg as the response. If not, then an error.

image.png

success.gif

Conclusion

You can read more about the library here

https://wwebjs.dev/

I hope you enjoyed building out the WhatsApp API using Node.js, Express, and whatsapp-web.js.

Comment down your thoughts! There is always room for improvement so let me know your suggestions on this project!

Connect with me on my YouTube channel and my Twitter 😉

Until next time, keeping awesome ✌️.

Top comments (1)

Collapse
 
raphaelvserafim profile image
Raphael Serafim

I use the unofficial api-wa.me, which is stable, well-documented, and easy to use