Bölüm 1: Okumaya Zamanınız Yoksa
- Bilinmeyen bir komuta yanıt, bu talimatlarınız veya karşılama mesajınız olabilir;
- Normal mesaj gönderme;
- Resim gönderme;
- Dosya gönderme;
- Video gönderme;
- Kişi (vCard) gönderme;
- Ürün gönderme;
- Yeni bir grup oluşturma, davetiye gönderme ve gruba mesaj gönderme;
- Gelen mesajları almak ve okumak;
Bölüm 2: Giriş
WhatsApp botu nedir ve neden buna ihtiyacınız var?
Neden Node.js?
- Asenkron Programlama. Node.js, engelleyici olmayan bir yapıya sahiptir, bu da birden fazla bağlantıyı aynı anda işleyebildiği anlamına gelir, bu da aynı anda birden fazla etkileşimi yönetmesi gereken bir sohbet botu için idealdir.
- Güçlü Topluluk Desteği. Canlı bir ekosistemi ve npm kayıt defterindeki birçok ücretsiz kullanılabilir modülü ile, Node.js üzerinde kodlama yaparken asla yalnız olmazsınız.
- Öğrenme Kolaylığı. Eğer JavaScript ile zaten tanıdıksanız, Node.js'yi öğrenmek kolay olacaktır. Eğer tanıdık değilseniz, JavaScript öğrenmek için en basit programlama dillerinden biridir.
- Bizim Desteğimiz. Bu programlama dilindeki geliştiricilere yardım etmekten memnuniyet duyarız. Eğer bize çalışmayan bir kod parçanızı gönderirseniz, size yardımcı olmak, öneride bulunmak veya işinizi geliştirmek bizim için daha kolay olur.
Geliştirme Ortamınızı Ayarlama
- Node.js ve npm. Eğer bilgisayarınızda Node.js ve npm (Node Package Manager) yüklü değilse, bunları kurmanız gerekecek. En son sürümü Node.js resmi web sitesinden indirebilirsiniz.
- Metin Editörü. Herhangi bir metin editörü işinizi görecektir, ancak Visual Studio Code veya WebStorm gibi IDE'ler, hata ayıklama ve otomatik tamamlama gibi ek özellikler sunarak işinizi kolaylaştırır.
- Terminal veya Komut Satırı. Tüm Node.js betiklerinizi burada çalıştıracaksınız.
Kurulum Aşamaları
- Adım 1: Node.js ve npm kurun. Node.js resmi web sitesini ziyaret edin ve işletim sisteminiz için yükleyiciyi indirin. Kurulum programını çalıştırın ve ekrandaki talimatları takip edin. Bu, hem Node.js hem de npm'yi yükleyecektir.
- Adım 2: Proje klasörünüzü ayarlayın. WhatsApp botunuzla ilişkili tüm dosyaların saklanacağı yeni bir klasör oluşturun. Terminali kullanarak bu klasöre gidin. Yeni bir Node.js projesi başlatın. Bu, projenizin tüm meta bilgilerini ve bağımlılıklarını içeren bir package.json dosyası oluşturacaktır.
- Adım 3: Gerekli paketleri yükleyin. WhatsApp API'si ile çalışacağımız için, görevi gerçekleştirmek için birkaç paket yüklememiz gerekecek.
WhatsApp API Sağlayıcısına Bağlanma
Whapi.Cloud'a Nasıl Bağlanılır
WhatsApp Botunuzun Temelini Atmak
Express ile Sunucu Başlatma
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}/`);
});
Node.js'de Asenkron Programlamaya Giriş
async function fetchData() {
const data = await getData();
console.log(data);
}
Gelen Mesajların İşlenmesi
Webhook'larla çalışmanın tüm inceliklerini bilgi bankamızda ayrıntılı olarak ele aldık: Webhook'lar hakkındaki makaleyi görüntüleyin
Bu linkin ayarlarına geçelim!
Yerel mi yoksa Sunucu mu
Yerel olarak çalışan Express sunucunuzun portunu belirterek ./ngrok http PORT_NUMARASI komutunu çalıştırın.
Şimdi, web kancası için kullanabileceğiniz bir halka açık URL'niz olmalı.
Bu linki config.js dosyasına kopyalayın:
botUrl: "https://84c7-151-33-282-113.ngrok-free.app/hook"
Yönlendirme ve İstek İşleme
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);
});
Node JS Kullanarak WhatsApp'ta Mesaj Gönderme
Metin Mesajları Gönderme
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);
});
Multimedya, Doküman Gönderme
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);
});
Node.JS Üzerinde WhatsApp Grupları ile Çalışma
Grup Listesini Alma
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);
});
WhatsApp Grubundaki Üye Sayısını Hesaplama
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}`);
});
});
Grup Mesajlarını İşleme
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.
}
Sorun Giderme
Bot Gelen Mesajlara Yanıt Vermiyor
- Botun çalıştırıldığı numaraya, başka bir telefondan mesaj gönderdiğinizden emin olun. Bot, aynı numaradan gönderilen mesajlara yanıt veremez.
- Eğer bot diğer numaralardan gelen mesajlara yanıt vermiyorsa, web kancalarının çalışıp çalışmadığını kontrol edin. Örneğin, Webhook.site gibi web kancası simülasyon servislerini kullanarak, geri çağırma isteklerinin hangi yoldan geldiğini doğrulayın. Daha sonra, yolun yapılandırmanızda belirttiğiniz yola uyup uymadığını kontrol edin. Ayrıca, sunucunuzun 200Ok yanıtı verdiğinden de emin olun.
Bot Durmaksızın Mesaj Gönderiyor
Bot Bazı Sohbetlerde Çalışıyor, Diğerlerinde Çalışmıyor
Dağıtım ve Sunucuları Kullanma
Firebase
- Firebase Console'da bir proje oluşturun;
- talimatları takip ederek Firebase CLI yükleyin;
- Proje dizininizde firebase init komutu ile Firebase'i başlatın;
- Botunuzu firebase deploy --only functions komutu kullanarak dağıtın.
AWS (Amazon Web Services)
- AWS Yönetim Konsolu'na kaydolun veya giriş yapın;
- AWS konsolu üzerinden API Gateway tetikleyici olarak seçilerek yeni bir Lambda fonksiyonu oluşturun;
- Botunuzun kodunu Lambda fonksiyonuna yükleyin;
- Botunuzun dış dünya ile etkileşimde bulunması için API Gateway'i yapılandırın.
Heroku
- Heroku'da bir hesap oluşturun;
- Heroku CLI yükleyin ve sisteme giriş yapın;
- Konsol üzerinden veya heroku create komutunu kullanarak Heroku'da yeni bir uygulama oluşturun;
- Git reposunu Heroku ile ilişkilendirin ve git push heroku master komutları ile dağıtım yapın;
- Heroku tarafından sağlanan web kancası URL'sini ayarlayın.
Node.JS ile Hazır Basit WhatsApp Botunun Kaynak Kodu
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}...`);
});
});
- Express ile sunucuyu başlatıyoruz ve gelen mesajları işlemek için bir webhook ayarlıyoruz.
- Metin mesajı alındığında, bot alınan metni tekrarlayarak cevap verir.
- Mesaj göndermek için sendTextMessage ve sendImageMessage fonksiyonlarını kullanıyoruz.