Parte 1: Se você não tem tempo para ler
- Responder a um comando desconhecido, isso pode ser uma instrução ou sua mensagem de boas-vindas;
- Enviar mensagem regular;
- Enviar imagem;
- Enviar arquivo;
- Enviar vídeo;
- Enviar contato (vCard);
- Enviar produto;
- Criar novo grupo, enviar convite e enviar mensagem para o grupo;
- Receber e ler mensagens recebidas;
Parte 2: Introdução
O que é um bot de WhatsApp e por que você precisa de um?
Por que Node.js?
- Programação Assíncrona. Node.js é não bloqueante, o que significa que pode lidar com várias conexões simultaneamente, perfeito para um chatbot que precisa gerenciar múltiplas interações de uma só vez.
- Amplo Suporte da Comunidade. Com um ecossistema vibrante e um grande número de módulos gratuitamente disponíveis no registro npm, você nunca está realmente sozinho quando está programando em Node.js.
- Facilidade de Aprendizado. Se você já está familiarizado com JavaScript, aprender Node.js será muito fácil. Mesmo que você não esteja, JavaScript é uma das linguagens de programação mais fáceis de aprender.
- Nosso Suporte. Estamos felizes em ajudar os desenvolvedores nesta linguagem de programação. Se você nos enviar um fragmento do seu código onde algo não está funcionando, será mais fácil para nós ajudá-lo, dar uma dica ou melhorar seu trabalho.
Configurando o Ambiente de Desenvolvimento
- Node.js e npm. Se você não tem Node.js e npm (Node Package Manager) instalados em seu computador, precisará instalá-los. Você pode baixar a última versão no site oficial do Node.js.
- Editor de Texto. Qualquer editor de texto servirá, mas IDEs como o Visual Studio Code ou o WebStorm oferecem recursos adicionais como depuração e auto-completar que podem facilitar sua vida.
- Terminal ou Prompt de Comando. É aqui que você executará todos os seus scripts Node.js.
Passos para a Instalação
- Passo 1: Instale Node.js e npm. Visite o site oficial do Node.js e baixe o instalador para o seu sistema operacional. Execute o instalador e siga as instruções na tela. Isso instalará tanto o Node.js quanto o npm.
- Passo 2: Configure a pasta do seu projeto. Crie uma nova pasta onde você armazenará todos os arquivos relacionados ao seu bot do WhatsApp. Navegue até a pasta usando o terminal. Inicialize um novo projeto Node.js. Isso criará um arquivo package.json que conterá todos os metadados e dependências do seu projeto.
- Passo 3: Instale os pacotes necessários. Como estaremos trabalhando com a API do WhatsApp, precisaremos instalar alguns pacotes para nos ajudar na tarefa.
Conectando o provedor de API do WhatsApp
Como conectar ao Whapi.Cloud
Estabelecendo a base do bot de WhatsApp
Inicializando o servidor com Express
npm install express --save
const express = require('express');
const app = express();
const port = 3000;
app.listen(port, () => {
console.log(`Server running on http://localhost:${port}/`);
});
Noções básicas de programação assíncrona em Node.js
async function fetchData() {
const data = await getData();
console.log(data);
}
Gerenciando Mensagens Recebidas
Exploramos todos os detalhes do trabalho com webhooks em mais detalhes na nossa base de conhecimento: Ver artigo sobre webhooks
Vamos configurar esse link!
Local ou no servidor
Execute ./ngrok http PORT_NUMBER, substituindo PORT_NUMBER pela porta em que seu servidor Express está operando localmente.
Agora você deve ter um URL público que pode usar como URL do webhook.
Copie este link para o arquivo config.js:
botUrl: "https://84c7-151-33-282-113.ngrok-free.app/hook"
Roteamento e Manipulação de Requisições
const express = require('express');
const app = express();
app.use(express.json());
app.post('/webhook', (req, res) => {
// Handle incoming messages
});
app.listen(3000, () => {
console.log('Server started');
});
app.post('/webhook', async (req, res) => {
const message = req.body.message.text;
if (message === 'hello') {
await sendMessage('Hi there!');
} else if (message === 'help') {
await sendMessage('How can I assist you today?');
}
res.sendStatus(200);
});
Enviar mensagem do WhatsApp usando Node JS
Enviando mensagens de texto
const request = require('request');
const options = {
method: 'POST',
url: 'https://gate.whapi.cloud/messages/text?token=YOUR_API_TOKEN',
headers: {accept: 'application/json', 'content-type': 'application/json'},
body: {typing_time: 10, to: '[email protected]', body: 'Hello, world!'},
json: true
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
Enviando multimídia, documentos
const request = require('request');
const options = {
method: 'POST',
url: 'https://gate.whapi.cloud/messages/document?token=YOUR_API_TOKEN',
headers: {accept: 'application/json', 'content-type': 'application/json'},
body: {
to: '[email protected]',
media: 'data:application/octet-stream;name=site.webmanifest;base64,ewogICAgIm5hbWUiOiAiIiwKICAgICJzaG9ydF9uYW1lIjogIiIsCiAgICAiaWNvbnMiOiBbCiAgICAgICAgewogICAgICAgICAgICAic3JjIjogIi9hbmRyb2lkLWNocm9tZS0xOTJ4MTkyLnBuZyIsCiAgICAgICAgICAgICJzaXplcyI6ICIxOTJ4MTkyIiwKICAgICAgICAgICAgInR5cGUiOiAiaW1hZ2UvcG5nIgogICAgICAgIH0KICAgIF0sCiAgICAidGhlbWVfY29sb3IiOiAiI2ZmZmZmZiIsCiAgICAiYmFja2dyb3VuZF9jb2xvciI6ICIjZmZmZmZmIiwKICAgICJkaXNwbGF5IjogInN0YW5kYWxvbmUiCn0K'
},
json: true
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
Trabalhando com grupos de WhatsApp usando Node.JS
Obtendo a lista de grupos
const request = require('request');
const options = {
method: 'GET',
url: 'https://gate.whapi.cloud/groups?token=YOUR_API_TOKEN',
headers: {accept: 'application/json'}
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
Contando o número de participantes no grupo do WhatsApp
request(options, function (error, response, body) {
if (error) throw new Error(error);
const groups = JSON.parse(body);
groups.forEach(group => {
console.log(`Group Name: ${group.name}`);
console.log(`Number of Participants: ${group.participants.length}`);
});
});
Gerenciando mensagens de grupo
app.post('/webhook', (req, res) => {
const message = req.body;
if (message.from.endsWith('@g.us')) {
// This is a group message
handleGroupMessage(message);
} else if (message.type === 'text') {
// Handle Text Messages
sendTextMessage(message.from, 'You said: ' + message.body);
}
res.status(200).end();
});
function handleGroupMessage(message) {
console.log(`Received a group message from ${message.from}: ${message.body}`);
// Further logic for group messages can be implemented here.
}
Resolução de problemas
Bot não responde a mensagens recebidas
- Certifique-se de que você está enviando mensagens para o número em que o bot está ativo, de outro telefone. O bot não poderá responder mensagens enviadas do mesmo número.
- Se o bot não responder a mensagens de outros números, verifique o funcionamento dos webhooks. Use serviços de simulação de webhooks, como o Webhook.site, para confirmar como as solicitações de callback estão chegando. Depois, verifique se o caminho corresponde ao configurado por você. Além disso, certifique-se de que seu servidor responde com 200Ok.
Bot envia mensagens sem parar
Bot funciona em alguns chats, mas não em outros
Deploy e uso de servidores
Firebase
- Crie um projeto no Firebase Console;
- Instale o Firebase CLI, seguindo as instruções;
- Initialize o Firebase no diretório do seu projeto usando o comando firebase init;
- Implante seu bot usando o comando firebase deploy --only functions.
AWS (Amazon Web Services)
- Registre-se ou entre no Console de Gerenciamento da AWS;
- Crie uma nova função Lambda através do console da AWS, escolhendo o API Gateway como gatilho;
- Carregue o código do seu bot na função Lambda;
- Configure o API Gateway para interação do seu bot com o mundo externo.
Heroku
- Crie uma conta no Heroku;
- Instale o Heroku CLI e faça login;
- Crie um novo aplicativo no Heroku através do console ou usando o comando heroku create;
- Associe seu repositório Git ao Heroku e faça o deploy usando os comandos git push heroku master;
- Configure o URL do webhook fornecido pelo Heroku.
Código-fonte de um bot de WhatsApp simples pronto para usar em Node.JS
module.exports = {
// API endpoint URL
apiUrl: "https://gate.whapi.cloud",
// API token from your channel
token: "YOUR CHANNEL TOKEN",
// The ID of the group to which we will send the message. Use to find out the ID: https://whapi.readme.io/reference/getgroups
group: '[email protected]',
// The ID of the product we will send for the example. Create a product in your WhatsApp and find out the product ID: https://whapi.readme.io/reference/getproducts
product: '6559353560856703',
// Bot`s URL (for static file). Webhook Link to your server. At ( {server link}/hook ), when POST is requested, processing occurs
botUrl: "https://yoursite.com/hook",
// Bot's Port (for hook handler). Don't use 443 port.
port: "80"
}
const express = require('express');
const bodyParser = require('body-parser');
const fs = require('fs');
const fetch = require('node-fetch');
const FormData = require('form-data');
const config = require('./config.js');
process.on('unhandledRejection', err => {
console.log(err)
});
const COMMANDS = { // bot commands
TEXT: 'Simple text message',
IMAGE: 'Send image',
DOCUMENT: 'Send document',
VIDEO: 'Send video',
CONTACT: 'Send contact',
PRODUCT: 'Send product',
GROUP_CREATE: 'Create group',
GROUP_TEXT: 'Simple text message for the group',
GROUPS_IDS: 'Get the id\'s of your three groups'
}
const FILES = { // file path
IMAGE: './files/file_example_JPG_100kB.jpg',
DOCUMENT: './files/file-example_PDF_500_kB.pdf',
VIDEO: './files/file_example_MP4_480_1_5MG.mp4',
VCARD: './files/sample-vcard.txt'
}
async function sendWhapiRequest(endpoint, params= {}, method = 'POST') { // send request to endpoint with params, with POST by default
let options = {
method: method,
headers: {
Authorization: `Bearer ${config.token}`
},
};
if (!params.media) options.headers['Content-Type'] = 'application/json'; // if in params media is null - set json in headers
let url = `${config.apiUrl}/${endpoint}`;
if(params && Object.keys(params).length > 0) {
if(method === 'GET')
url += '?' + new URLSearchParams(params); // if GET method set in params, then params move to query
else
options.body = params?.media ? toFormData(params) : JSON.stringify(params); // if in params media - transform to formData, else - json
}
const response = await fetch(url, options); // send request
let json = await response.json();
console.log('Whapi response:', JSON.stringify(json, null, 2));
return json;
}
/**
* Convert object to FormData
* @param obj
* @returns {FormData}
*/
function toFormData(obj) {
const form = new FormData();
for (let key in obj) {
form.append(key, obj[key]);
}
return form;
}
async function setHook() { // request for set hook and recieve messages
if (config.botUrl) {
/** type {import('./whapi').Settings} */
const settings = {
webhooks: [
{
url: config.botUrl,
events: [
// default event for getting messages
{type: "messages", method: "post"}
],
mode: "method"
}
]
}
await sendWhapiRequest('settings', settings, 'PATCH');
}
}
async function handleNewMessages(req, res){ // handle messages
try {
/** type {import('./whapi').Message[]} */
const messages = req?.body?.messages;
for (let message of messages) {
if (message.from_me) continue;
/** type {import('./whapi').Sender} */
const sender = {
to: message.chat_id
}
let endpoint = 'messages/text';
const command = Object.keys(COMMANDS)[+message.text?.body?.trim() - 1];
switch (command) { // depending on the command, perform an action
case 'TEXT': {
sender.body = 'Simple text message';
break;
}
case 'IMAGE': {
sender.caption = 'Text under the photo.';
sender.media = fs.createReadStream(FILES.IMAGE); // read file
endpoint = 'messages/image';
break;
}
case 'DOCUMENT': {
sender.caption = 'Text under the document.';
sender.media = fs.createReadStream(FILES.DOCUMENT);
endpoint = 'messages/document';
break;
}
case 'VIDEO': {
sender.caption = 'Text under the video.';
sender.media = fs.createReadStream(FILES.VIDEO);
endpoint = 'messages/video';
break;
}
case 'CONTACT': {
sender.name = 'Whapi Test';
sender.vcard = fs.readFileSync(FILES.VCARD).toString();
endpoint = 'messages/contact';
break;
}
case 'PRODUCT': {
/* you can get real product id using endpoint https://whapi.readme.io/reference/getproducts */
endpoint = `business/products/${config.product}`;
break;
}
case 'GROUP_CREATE': {
/* Warning : you can create group only with contacts from phone contact list */
const res = await sendWhapiRequest(`groups`, {subject: 'Whapi.Cloud Test', participants: [message.chat_id.split('@')[0]]});
sender.body = res.group_id ? `Group created. Group id: ${res.group_id}` : 'Error';
break;
}
case 'GROUP_TEXT': {
/*To get group id, use /groups endpoint */
sender.to = config.group;
sender.body = 'Simple text message for the group';
break;
}
case 'GROUPS_IDS': { // get groups
const {groups} = await sendWhapiRequest('groups', {count: 3}, 'GET');
sender.body = groups && groups.reduce((prevVal, currVal, i) => {
return i === 0 ? `${currVal.id} - ${currVal.name}` : prevVal + ',\n ' + `${currVal.id} - ${currVal.name}`;
}, '') || 'No groups';
break;
}
default: { // if command not found - set text message with commands
sender.body = 'Hi. Send me a number from the list. Don\'t forget to change the actual data in the code! \n\n' +
Object.values(COMMANDS).map((text, i) => `${i + 1}. ${text}`).join('\n');
}
}
await sendWhapiRequest(endpoint, sender); // send request
}
res.send('Ok');
} catch (e) {
res.send(e.message);
}
}
// Create a new instance of express
const app = express();
app.use(bodyParser.json());
app.get('/', function (req, res) {
res.send('Bot is running');
});
app.post('/hook/messages', handleNewMessages); // route for get messages
setHook().then(() => {
const port = config.port || (config.botUrl.indexOf('https:') === 0 ? 443 : 80) // if port not set - set port 443 (if https) or 80 (if http)
app.listen(port, function () {
console.log(`Listening on port ${port}...`);
});
});
- Inicializamos o servidor com Express e instalamos um webhook para lidar com mensagens recebidas.
- Quando uma mensagem de texto é recebida, o bot responde repetindo o texto recebido.
- Para enviar mensagens, usamos as funções sendTextMessage e sendImageMessage.