https://d226lax1qjow5r.cloudfront.net/blog/blogposts/restaurant-is-now-delivering-a-facebook-bot-in-node-js/restaurant-closed_1200x600.png

Restaurant liefert jetzt aus: ein Facebook-Bot in Node.js

Zuletzt aktualisiert am October 13, 2021

Lesedauer: 14 Minuten

Einführung

Wenn ich programmiere, werde ich oft hungrig. Und jeder weiß, dass die besten Entwickler faul sind. Anstatt also einzukaufen und zu kochen und putzen, benutze ich normalerweise eine Essenslieferungs-App und bestelle einfach ein leckeres Essen. Das Problem ist, dass meine Lieblingsrestaurants zu oft offline sind. Manchmal sind sie geschlossen, manchmal sind sie zu beschäftigt und nehmen keine Online-Bestellungen mehr an. Also bin ich gezwungen, zu warten und daran zu denken, zu prüfen, ob sie wieder online sind, und dann tatsächlich die App zu öffnen und zu sehen, ob sie wieder online sind. Und manchmal muss ich wieder und wieder und wieder nachsehen. Das ist wirklich eine große Ungerechtigkeit 😆.

Es muss einen besseren, innovativeren Weg geben! Zum Glück habe ich kürzlich entdeckt, dass meine Lieblings-App für Essenslieferungen, Wolt, eine API hat die mich wissen lässt, ob ein Restaurant online ist. Also habe ich mithilfe der Vonage Messages API einen Facebook Messenger Bot erstellt, der mich benachrichtigt, wenn mein Lieblingsrestaurant wieder online ist!

(Dieses Beispiel bezieht sich auf den Anwendungsfall der Lebensmittellieferung, aber derselbe Code kann zur Erstellung eines Facebook-Bots verwendet werden, der Benutzer bei jeder booleschen Änderung benachrichtigt).

Voraussetzungen

Diese Anwendung erfordert Folgendes:

Pseudocode:

Bevor ich mit dem Programmieren anfange, denke ich mir gerne die Logik aus. Lassen Sie uns die Schritte aufschlüsseln, die für die Erstellung dieser App erforderlich sind:

  1. Einrichten eines Express-Servers

  2. Verbindung zur Vonage Messages API Sandbox

  3. Aufruf der Wolt-API für ein gewünschtes Restaurant

  4. Prüfen Sie, ob das empfangene Restaurant online ist

  5. Senden einer Nachricht an den Benutzer basierend auf dem Restaurantstatus

  6. Wenn das Restaurant offline ist, fügen Sie es zu einer Liste von Offline-Restaurants hinzu.

  7. Kontinuierliche Überprüfung der Liste der Offline-Restaurants auf eine Statusänderung

  8. Wenn ein Restaurant online geht, senden Sie eine Benutzernachricht und entfernen Sie es aus der Liste der Offline-Restaurants

Unser Projekt einrichten

Erstellen einer Node-Anwendung

Beginnen wir mit der Erstellung unseres Projekts:

mkdir isItDelivering

Wechseln Sie dann in das Projektverzeichnis:

cd isItDelivering

Initialisieren Sie das Knotenprojekt:

npm init

Installieren Sie unsere benötigten Node-Pakete:

npm install -s @vonage/server-sdk@beta express dotenv got lokijs

Und schließlich erstellen Sie die Dateien, in denen unser Code gespeichert werden soll:

touch index.js .env

Sie werden feststellen, dass wir das Vonage Node Server SDK für den Zugriff auf die Messages API. Da sich die Messages API derzeit in der Beta-Phase befindet, benötigen wir die Beta-Version unseres SDKs.

Um unseren Server einzurichten, benötigen wir einige Informationen aus dem Vonage Entwickler Dashboard. Zunächst erstellen wir eine neue Vonage-Anwendung. Geben Sie ihr einen schönen Namen wie isItDelivering. Und dann klicken Sie auf "Generate public and private key".

Generate Public/Private KeyGenerate Public/Private Key

Dadurch wird automatisch ein Schlüssel für die Authentifizierung erzeugt, den wir später verwenden werden. Verschieben Sie den generierten Schlüssel in das Stammverzeichnis Ihres lokalen Projekts.

Zu diesem Zeitpunkt sollte Ihr Projekt Ihre Indexdatei, Knotenmodule, package.json und Ihre ENV-Datei enthalten. Wenn Sie den Befehl lsausführen, sollte Ihr Projekt wie folgt aussehen:

Project Should Include index.js, node_modules, pack.json, private.keyProject Should Include index.js, node_modules, pack.json, private.key

Wie Sie sehen, können wir mit unserer Vonage-Anwendung verschiedene Funktionen über die verschiedenen Vonage-APIs ein- und ausschalten. Wir wollen die Messages-Funktionen einschalten. Jetzt werden wir nach zwei URLs gefragt, die den Webhooks entsprechen, die die Messages API zur Interaktion mit unserer Bot-Anwendung verwenden wird.

Verbindung zur Außenwelt

Einrichtung ngrok

Es gibt mehrere Möglichkeiten, unseren lokalen Entwicklungsserver von außen zugänglich zu machen, aber eine der einfachsten ist ngrok. Sie können lesen diesen Artikel für eine genauere Erklärung, wie ngrok funktioniert.

Für unsere Zwecke müssen wir es nur zum Laufen bringen und die URL kopieren, die es uns liefert.

Nachdem Sie ngrok auf Ihrem Rechner installiert haben, müssen wir es starten. Um ngrok zu starten, öffnen Sie ein neues Terminal-Fenster und führen Sie den folgenden Befehl in der Kommandozeile aus:

$ ngrok http 3000

Sie sehen nun eine ngrok-Protokollierungsschnittstelle in Ihrem Terminalfenster. Am oberen Rand der Schnittstelle befindet sich eine Zeile, die mit Forwarding beginnt und zwei URLs enthält. Die erste ist die von außen zugängliche ngrok-URL, die mit ngrok.io gefolgt von http://localhost:3000wobei es sich um Ihren lokalen Entwicklungsserver handelt. Wenn Sie oder Vonage nun die ngrok.io URL kontaktieren, wird sie an Ihren lokalen Server weitergeleitet.

In unserem Vonage Dashboard fügen wir nun unsere ngrok-URLs und die entsprechenden URL-Routen hinzu. Sobald Ihre URLs wie folgt aussehen, können Sie auf die Schaltfläche "Neue Anwendung generieren" klicken.

Webook URLsWebhook URLs

Verbinden Sie sich mit Vonage

Verbinden Sie Ihr Vonage-Konto

In Ihrer ENV-Datei in Ihrem Projekt müssen Sie 3 Umgebungsvariablen hinzufügen; API_KEY , API_SECRET, und APP_ID.

Sie finden Ihre API_KEY und API_SECRET auf der Startseite Ihres Vonage Dashboards:

Dashboard ENV VariablesDashboard ENV Variables

Ihre APP_ID finden Sie auf der Konfigurationsseite für die von Ihnen erstellte Anwendung. Sie finden Ihre Anwendung unter Your Applications in der linken Navigationsleiste. Ihre APP_ID sieht wie folgt aus:

APP_ID in DashboardAPP_ID in Dashboard

Sobald Sie diese in Ihr Projekt kopiert und eingefügt haben, sollte Ihre ENV-Datei etwa so aussehen:

API_KEY="XXXXXXXXX"
API_SECRET="XXXXXXXXX"
APP_ID="XXXXXXXXX"

Erste Schritte mit der Messages API Sandbox

Hinzufügen von Benutzern zu Ihrer Sandbox

Wir nutzen die Vonage Facebook-Sandkasten. Sie finden die Sandbox in Ihrem Vonage Dashboard unter der Registerkarte Nachrichten und Versand auf der linken Seite, oder klicken Sie hier. Sobald Sie auf Add to Sandbox für die Registerkarte Facebook Messenger klicken, sollte Ihr Bildschirm wie folgt aussehen:

Set up your sandboxSet up your sandbox

Die Messages API Sandbox ermöglicht das schnelle Testen von Applications, ohne auf die Genehmigung des Business Accounts warten zu müssen. Die Sandbox verwendet einen Whitelist-Ansatz, um Testbenutzer zuzulassen. Sie können zusätzliche Benutzer in die Whitelist einladen, indem Sie die Send invite email button oder indem Sie ihnen den Hyperlink click this link. Über den Link wird eine Facebook Messenger-Sitzung geöffnet. Der Benutzer muss dann die Passphrase senden, um in die Whitelist aufgenommen zu werden. Alle Einzelheiten finden Sie hier.

Verbinden Ihrer Anwendung mit Ihrer Sandbox

Wir müssen nun unserer Sandbox mitteilen, dass sie auf Anfragen von unserer Anwendung hören und sie an Facebook Messenger übermitteln soll. Dies geschieht über unsere ngrok-URLs. Wir müssen die gleichen ngrok-URLs wie zuvor hinzufügen, etwa so:

Messages API Sandbox ngrok URLSMessages API Sandbox ngrok URLS

Sobald wir auf die Schaltfläche Save webhooks drücken, ist die Einrichtung abgeschlossen und wir können mit dem Programmieren beginnen!

Der gesamte nachfolgende Code wird in unserer index.js Datei.

Einrichten eines Express-Servers

Erstellen eines Boilerplate-Servers mit Abhängigkeiten

Als Erstes richten wir einen Express-Server in unserer index.js Datei einen Boilerplate-Express-Server ein, der unsere benötigten Bibliotheken importiert und einfach auf Port 3000 läuft:

// access our environment variables
require('dotenv').config();
// access the Vonage SDK so we can use the Voange object and API
const Vonage = require('@vonage/server-sdk');
// access Got library which allows us to make HTTP request to WOLT API
const got = require('got');

// boilerplate Express setup
const express = require('express');
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: false }));

app.listen(3000);

Versenden einer einfachen Facebook-Nachricht

Eine Facebook-Nachricht von unserer Anwendung aus senden

Wir müssen eine Vonage-Instanz initialisieren, indem wir unsere ENV-Variablen übergeben, und ihr dann mitteilen, dass sie die Vonage-Sandbox als Host für die HTTP-Anfragen verwenden soll. Wir können den folgenden Code in unsere

// initialize a new Vonage instance, with ENV variables/keys
const vonage = new Vonage(
  {
    apiKey: process.env.API_KEY,
    apiSecret: process.env.API_SECRET,
    applicationId: process.env.APP_ID,
    privateKey: './private.key'
  },
  {
    apiHost: 'https://messages-sandbox.nexmo.com/',
  }
 );

Als Nächstes verwenden wir das Vonage-Objekt, um eine POST-Anfrage an unsere Route zu senden. /inbound Route zu senden, und wir müssen zwei minimale Parameter angeben: type und text.

// Basic Sandbox Messaging
app.post('/inbound', (req, res) => {
  vonage.channel.send(
    req.body.from,
    req.body.to,
    {
      content: {
        type: 'text',
        text: 'You must be hungry! 🍕'
      },
    },
    (err, data) => {
      if(err){
        console.log(err);
      } else{
          console.log(data.message_uuid);
      }
    }
  );
  res.send('ok');
});

app.post('/status', (req, res) => {
  res.send('ok');
});

Nun müssen wir in einem zweiten Terminalfenster, getrennt von unserem ngrok-Server, unseren Express Server starten:

$ node index.js

Und wir können mit unserem Facebook-Bot interagieren!

Basic Facebook SandBox MessageBasic Facebook SandBox Message

Empfangen von Restaurantinformationen von der Wolt API

Die HTTP-Anfrage stellen

Durch die Verwendung des https://restaurant-api.wolt.com/v3/venues/slug/{restaurant} Endpunkt wissen wir, dass wir alle möglichen Informationen über das Restaurant erhalten können. Das zurückgegebene JSON sieht wie folgt aus:

Wolt Returned JSONWolt Returned JSON

Wie wir sehen können, gibt es innerhalb des Index Null eine Eigenschaft namens name vom Typ Array. Bei dem Index Null von name befindet sich ein boolescher Wert namens online, der den aktuellen Lieferstatus des Restaurants angibt. Wir können also eine Funktion erstellen, die den Namen eines Restaurants annimmt und das Restaurant-Objekt von Wolt zurückgibt:

// call Wolt API for restaurant info
const getRestaurant = async (reqRestaurant) => {
  const response = await got.get(`https://restaurant-api.wolt.com/v3/venues/slug/${reqRestaurant}`)
      .json();
  return response.results[0];
}

Prüfen Sie, ob das empfangene Restaurant online ist

Die Verwendung der Eigenschaft online innerhalb des restaurant Objekts wollen wir eine Logik erstellen, die bestimmt, welche Nachricht wir an den Benutzer senden. Wir können die folgende Funktion schreiben:

const firstStatusCheck = (restaurant, recipient) => {
  if (restaurant.online) {
    sendFacebookMessage(`Hey, ${restaurant.name[0].value} is now accepting orders!!`, recipient);
  } else {
	  sendFacebookMessage(`Sorry, ${restaurant.name[0].value} is currently offline. I'll ping you when it's open again!`, recipient);
    }
}

Die Funktion firstStatusCheck Funktion hat unseren Vonage-Code zum Senden der Facebook-Nachricht in eine Funktion namens sendFacebookMessage. Diese Funktion kann nun jede beliebige Nachricht von unserem Sandbox Account senden, solange wir ihr zwei Parameter übergeben text und recipient.

Wir können eine konstante Variable verwenden SENDER verwenden, um die Absender-ID-Informationen des Sandbox-Accounts zu übermitteln. Zuerst deklarieren wir sie.

let SENDER;

Und dann weisen wir es zu, wenn wir die req von dem /inbound Endpunkt erhalten:

app.post('/inbound', async(req, res) => {
  SENDER = req.body.from;

Jetzt sollte die sendFacebookMessage sollte so aussehen:

const sendFacebookMessage = async (text, recipient) => {
  vonage.channel.send(
    SENDER,
    recipient,
    {
      content: {
        type: 'text',
        text: text,
      },
    },
    (err, data) => {
      if (err) {
        console.log(err);
      } else {
        console.log(data.message_uuid);
      }
     }
   );
 }

Senden einer Nachricht an den Benutzer basierend auf dem Restaurantstatus

Durch die Kombination unserer neuen Funktionen können wir unsere einfache Sandbox-Nachricht aktualisieren, um dem Nutzer mitzuteilen, ob das angefragte Restaurant derzeit online ist oder nicht.

// Enhanced Sandbox Messaging
app.post('/inbound', async(req, res) => {
	SENDER = req.body.from;
	const recipient = await req.body.to;
	const requestedRestaurant = await req.body.message.content.text.split('/').pop();
	const restaurant = await getRestaurant(requestedRestaurant);
	firstStatusCheck(restaurant, recipient);
	res.send('ok');
});

Schleife, wenn das Restaurant offline ist

Nachdem wir nun die Logik basierend auf dem Status des Restaurants erstellt haben, wollen wir diesen Status so lange überprüfen, bis das Restaurant wieder online ist. Wir müssen also die letzten drei Schritte unseres Pseudocodes ausarbeiten:

  1. Wenn das Restaurant offline ist, fügen Sie es zu einer Liste von Offline-Restaurants hinzu.

  2. Kontinuierliche Überprüfung der Liste der Offline-Restaurants auf eine Statusänderung

  3. Wenn ein Restaurant online geht, senden Sie dem Benutzer eine Nachricht und entfernen Sie es aus der Liste der Offline-Restaurants

Erstellen einer In-Memory-Datenbank mit Offline-Restaurants

An diesem Punkt werden wir unsere LokiJS Bibliothek. LokiJS ist eine In-Memory-Datenbank, die es uns ermöglicht, jedes Restaurant, das angefordert wird, auf einfache Weise zur Laufzeit zu verfolgen. Wenn Sie MongoDB verwendet haben, wird Ihnen LokiJS sehr vertraut vorkommen.

Zunächst müssen wir Loki in unsere anderen Abhängigkeiten einbinden:

const loki = require('lokijs');

Dann müssen wir unsere Datenbank instanziieren:

let db = new loki("restaurants.db");
let restaurants = db.addCollection("restaurants");

Jeder Restauranteintrag enthält 4 Datenpunkte: Name, Online-Status, Empfänger und Slug. Name ist der Name des Restaurants. Online status ist eine boolesche Angabe, ob das Restaurant derzeit online ist. Recipient ist die Benutzerinformation aus der Messages API, die es uns ermöglicht zu verfolgen, wer benachrichtigt werden muss. Und schließlich, slug ist die URL-Endung, mit der die Wolt-API ein Restaurant findet.

Nun, da wir eine Datenbank haben, können wir damit beginnen, unsere Offline-Restaurants hinzuzufügen! Wir können die folgende Funktion verwenden, um unserer Offline-Liste Restaurants hinzuzufügen:

 const addRestaurantToDb = (restaurant, recipient) => {
  restaurants.insert({name: restaurant.name[0].value, online: restaurant.online, recipient: recipient, slug: restaurant.slug});
 }

Wir müssen nun unsere firstStatusCheck aktualisieren, um Restaurants in die Offline-Liste aufzunehmen.

// Check initially whether restaurant is online or should it be added to list of offline restaurants to check
const firstStatusCheck = (restaurant, recipient) => {
  if (restaurant.online) {
    sendFacebookMessage(`Hey, ${restaurant.name[0].value} is now accepting orders!!`, recipient);
  } else {
      sendFacebookMessage(`Sorry, ${restaurant.name[0].value} is currently offline. I'll ping you when it's open again!`, recipient);
      addRestaurantToDb(restaurant, recipient);
    }
}

Kontinuierliche Überprüfung auf Statusänderungen

Jetzt, da wir eine Liste von Offline-Restaurants haben, wollen wir prüfen, ob sie wieder online gehen. Da wir dies regelmäßig und kontinuierlich tun wollen, verwenden wir die eingebaute setInterval Funktion:

setInterval(function(){offlineRestaurantLookup(req)} , INTERVAL);

Die Konstante INTERVAL Konstante teilt setInterval mit, wie oft es die offlineRestaurantLookup Funktion ausführen soll. Wir definieren dies am Anfang der Datei neben SENDER. Standardmäßig prüfen wir alle 60 Sekunden:

const INTERVAL = 60000;

Die offlineRestaurantLookup ruft alle Restaurants in der Offline-Datenbank ab und prüft dann für jedes Restaurant, ob es noch offline ist.

const offlineRestaurantLookup = async () => {
  let offlineRestaurants = restaurants.data;
  offlineRestaurants.forEach(await checkIsStill0ffline);
}

Die Funktion checkIsStill0ffline Funktion wiederum prüft, ob ein Restaurant jetzt online ist. Wenn das Restaurant online gegangen ist, wird der richtige Benutzer benachrichtigt und das Restaurant aus der Liste der Offline-Restaurants gelöscht.

const checkIsStill0ffline = async (restaurant) => {
  const checkedRestaurant = await getRestaurant(restaurant.slug);
  if (checkedRestaurant.online) {
    sendFacebookMessage(`Hey, ${restaurant.name} is now accepting orders!!`, restaurant.recipient);
    restaurants.chain().find({'name': restaurant.name}).remove();
  }
}

Jetzt können wir die setInterval Funktionalität unterhalb unserer Sandbox-Messaging-Logik hinzufügen:

// Enhanced Sandbox Messaging
app.post('/inbound', async(req, res) => {
  SENDER = req.body.from;
  const recipient = await req.body.to;
  const requestedRestaurant = await req.body.message.content.text.split('/').pop();
  const restaurant = await getRestaurant(requestedRestaurant);
  firstStatusCheck(restaurant, recipient);
  res.send('ok');
});

app.post('/status', (req, res) => {
  res.send('ok');
});

setInterval(function(){offlineRestaurantLookup()} , INTERVAL);

app.listen(3000);

Und jetzt können wir das Programm laufen lassen und sehen, dass wir eine Nachricht erhalten, wenn ein Restaurant offline ist, und wenn Restaurants online gehen, werden wir über den neuen Status informiert. Ich empfehle, die App morgens auszuprobieren und zu sehen, wie Restaurants plötzlich zum Mittagessen öffnen. Es ist amüsant, wenn die Push-Benachrichtigungen von Facebook Messenger auf Ihrem Telefon ankommen!

Enhanced Facebook SandBox MessageEnhanced Facebook SandBox Message

Was kommt als Nächstes?

  • In diesem Tutorial haben wir die Facebook Messenger-Funktionalität der Messages API verwendet, aber wir könnten diese Anwendung erweitern, um Omnichannel-Funktionen mit WhatsApp und SMS bereitzustellen. Stellen Sie sich einen sehr dringenden Anwendungsfall vor (ich denke da an einen bestimmten Bagel-Shop am Samstagmorgen), bei dem Sie sofort über eine Statusänderung benachrichtigt werden möchten; Omnichannel-Benachrichtigungen wären nützlich.

  • Wir könnten diesen Code erweitern, um die Warnungen intelligenter zu gestalten, basierend auf Lieferplänen, der Nähe des Benutzers zu Restaurants und mehr. Wir könnten auch mehrere Aufträge verwalten.

  • Wir könnten die App aus der Sandbox nehmen und sie mit einem geschäftlichen Facebook Account verbinden.

Den endgültigen Code für das Tutorial finden Sie auf GitHub zu finden. Ich würde gerne hören, was Sie mit der Vonage Messages API gebaut haben! Bitte beteiligen Sie sich an der Diskussion auf unserem Gemeinschaft Slack und teilen Sie Ihre Geschichte!

Teilen Sie:

https://a.storyblok.com/f/270183/384x384/e4e7d1452e/benjamin-aronov.png
Benjamin AronovAdvokat für Entwickler

Benjamin Aronov ist ein Entwickler-Befürworter bei Vonage. Er ist ein bewährter Community Builder mit einem Hintergrund in Ruby on Rails. Benjamin genießt die Strände von Tel Aviv, das er sein Zuhause nennt. Von Tel Aviv aus kann er einige der besten Startup-Gründer der Welt treffen und von ihnen lernen. Außerhalb der Tech-Branche reist Benjamin gerne um die Welt auf der Suche nach dem perfekten Pain au Chocolat.