https://d226lax1qjow5r.cloudfront.net/blog/blogposts/serverless-sms-nexmo-ibm-dr/sms-fortune-cookie.png

Serverlose SMS-Glückskekse mit Nexmo und IBM

Zuletzt aktualisiert am May 3, 2021

Lesedauer: 9 Minuten

Die Kommunikation mit Nutzern per SMS ist eine hervorragende Möglichkeit, mit Menschen informell zu interagieren. Ganz gleich, ob Sie die Beantwortung der am häufigsten gestellten Fragen automatisieren, ein Gewinnspiel veranstalten oder mit Ihren Nutzern über etwas ganz anderes in Kontakt treten möchten, SMS sind eine ausgezeichnete Wahl. In diesem Beitrag sehen wir uns ein lustiges und triviales Beispiel an, während wir uns im Detail ansehen, wie man diese Aufgaben erfüllt. Wir werden ein System aufbauen, das auf eine eingehende SMS mit einem "Glückskeks" antwortet. Dies sind die Grüße, die in der "Nachricht des Tages"-Funktion auf alten *nix-Workstations verwendet werden. Stellen Sie sich das als eine geekigere Version der liebenswerten Lade-Nachrichten vor, die Sie auf Slack sehen.

Serverless ist die ideale Wahl für eine Aufgabe wie diese, bei der jede eingehende Nachricht unabhängig von allen anderen ist. Serverlose Plattformen wie IBM Cloud-Funktionen (in diesem Beispiel verwendet), Amazon Lambda oder Azure-Funktionen skalieren alle horizontal, wenn sie ausgelastet sind. Der große Vorteil liegt im Preismodell: Serverlose Plattformen berechnen nur für die Zeit, in der die Funktion läuft, sodass keine feste Gebühr für einen laufenden Server gezahlt werden muss. Ein weiterer Vorteil ist, dass für die Bereitstellung einer Funktion weniger Schritte erforderlich sind als für die Einrichtung eines Servers, was den Einstieg erleichtert.

Bevor Sie beginnen

Es gibt einige Voraussetzungen, die Sie erfüllen müssen, bevor Sie diesem Lernprogramm folgen können:

  • Ein IBM Cloud-Konto damit wir unsere serverlose Funktion bereitstellen können (kostenlos)

  • Das bx Befehlszeilenwerkzeug für IBM Cloud und wsk Cloud Functions Plugin - verwenden Sie die Installationsanleitung. Melden Sie sich an und legen Sie Ihren Ziel-Arbeitsbereich bevor Sie fortfahren.

Vonage API-Konto

Um dieses Tutorial durchzuführen, benötigen Sie ein Vonage API-Konto. Wenn Sie noch keines haben, können Sie sich noch heute anmelden und mit einem kostenlosen Guthaben beginnen. Sobald Sie ein Konto haben, finden Sie Ihren API-Schlüssel und Ihr API-Geheimnis oben auf dem Vonage-API-Dashboard.

Schritt 1: Erstellen und Bereitstellen einer serverlosen Funktion

Eine serverlose Funktion ist eine Funktion (in diesem Fall JavaScript; IBM Cloud unterstützt viele andere Programmiersprachen), die in der Cloud bereitgestellt wird. Die Funktion wird als Reaktion auf ein Ereignis ausgeführt, und eines der häufigsten Ereignisse ist eine Webanforderung. Indem wir eine einzige Funktion erstellen und bereitstellen, können wir schnell eine SMS von einem Benutzer empfangen.

Holen Sie sich die Funktion von diesem Link zu einer bestimmten Version auf GitHub. Sie sollten einen Inhalt haben, der in etwa wie diese gekürzte Version aussieht:

function main(params) {
  // pick a random cookie from the data
  var data = getCookies();
  var random = Math.floor(Math.random() * 430);
  var cookie = data[random];

  // log the cookie and then return it as body data
  console.log(cookie);
  return { body: cookie };
}

function getCookies() {
  return [
    "A day for firm decisions!!!!! Or is it? ",
    // ~400 more lines
    "Your talents will be recognized and suitably rewarded. ",
    "Your temporary financial embarrassment will be relieved in a surprising manner. ",
    "Your true value depends entirely on what you are compared with. "
  ];
}

Speichern Sie den Inhalt in index.js und werfen Sie einen kurzen Blick auf die main() Funktion oben an. Es sind nur ein paar Zeilen Code, um das große Array von Glückskeksen (aus Ubuntu's fortune-mod Paket) und wählt einen nach dem Zufallsprinzip aus, bevor er ihn protokolliert und zurückgibt. Wenn Sie die Funktion bearbeiten möchten, um getCookies() Funktion bearbeiten möchten, um alternative Glückskekse anzubieten, nur zu!

In der serverlosen Programmierung werden "Funktionen" normalerweise als "Aktionen" bezeichnet.

Um diese Aktion in die Cloud zu bringen, erstellen wir zunächst ein Paket um es darin abzulegen. Ein Paket hilft dabei, Aktionen zusammenzuhalten und ermöglicht es ihnen, Parameter gemeinsam zu nutzen.

Verwenden Sie den bx den Sie zuvor eingerichtet haben, erstellen Sie das Paket mit diesem Befehl:

bx wsk package create sms-fortune

Sie sollten eine glückliche "OK"-Ausgabe sehen, und da das Paket nun vorhanden ist, können wir auch die Funktion bereitstellen. Hier ist der Befehl dafür:

bx wsk action update sms-fortune/incoming --kind nodejs:8 --web raw index.js

Achten Sie auch hier auf das "OK", das anzeigt, dass der Befehl erfolgreich ausgeführt wurde. Wir haben eine Funktion implementiert. Sie heißt incoming (da sie eingehende SMS verarbeitet) und sie existiert im sms-fortune Paket. Die anderen Argumente hier sind --kind um anzugeben, welche Version von JS verwendet werden soll und --web raw damit wir sofort eine Web-Anfrage an diese Aktion stellen können.

Der Aufruf von update bei einer Aktion, die nicht existiert, löst create aus, so dass dieser Befehl unabhängig vom aktuellen Zustand funktioniert. Noch besser: Er funktioniert auch dann, wenn Sie index.js und erneut einsetzen.

Also, worauf warten wir noch? Lassen Sie uns die URL unserer Aktion herausfinden und sie dann anfordern. Hier ist der Befehl, um herauszufinden, welche URL die Aktion hat:

bx wsk action get --url sms-fortune/incoming

Kopieren Sie die URL aus der Antwort auf den obigen Befehl. Sie können fortfahren und cURL, Ihren Browser oder einen anderen HTTP-Client verwenden, um eine Anfrage an diese URL zu stellen. Wenn alles nach Plan gelaufen ist, sollte die Antwort eine witzige Bemerkung enthalten. Wenn Sie möchten, können Sie die Anfrage ein paar Mal wiederholen, um weitere witzige Bemerkungen zu erhalten.

Schritt 2: Bearbeiten einer eingehenden SMS

Der Endpunkt, auf den unser Webhook verweisen soll, ist bereits eingerichtet, also legen wir los und verkabeln ihn. Sie können auch einen Blick auf unseren Baustein für den Empfang von SMS als Referenz ansehen.

Zunächst einmal brauchen wir eine Möglichkeit zu sehen, wann Nexmo unsere Funktion aufruft. Bis jetzt haben wir es direkt angefordert, aber wenn wir eine SMS erhalten, gibt es keine Antwort, die wir sehen können. Öffnen Sie stattdessen ein neues Terminalfenster und zeigen Sie die Protokolle Ihrer Aktionen mit dem folgenden Befehl an:

bx wsk activation poll

Lassen Sie diese Funktion laufen (ich lasse sie gerne auf meinem zweiten Monitor laufen, wenn ich einen habe) und verwenden Sie die gleiche curl/browser-Anfrage wie zuvor, damit Sie sehen können, was passiert, wenn die Funktion läuft. Wie Sie vielleicht bemerken, handelt es sich nicht um Echtzeit, und wir müssen manchmal ein paar Sekunden warten, bis die Protokolle erscheinen.

Jetzt können wir feststellen, ob die Funktion erfolgreich ausgeführt wird. Versuchen wir, sie zu unserem Endpunkt für SMS zu machen. Besuchen Sie Ihre Telefonnummern Seite auf dem Nexmo Dashboard und klicken Sie auf "Bearbeiten" für die zu verwendende Nummer und fügen Sie unter "SMS" die Aktions-URL in das Feld "Webhook URL" ein. Vergessen Sie nicht, auf "Aktualisieren" zu klicken.

Wir sind bereit: Senden Sie eine SMS an Ihre Eingangsnummer, und beobachten Sie die Protokolle, um zu sehen, wie die Aktion läuft!

Schritt 3: Ermitteln Sie die Nummer, auf die Sie antworten sollen

Zu diesem Zeitpunkt haben wir eine serverlose Aktion bereitgestellt und sie als Endpunkt für den Webhook für eingehende SMS festgelegt. Um dem Benutzer, der die SMS gesendet hat, antworten zu können, müssen wir die mit dem Webhook eingehenden Daten prüfen, um zu sehen, wer sie gesendet hat.

Die IBM Cloud Functions (und auch Apache OpenWhisk im Allgemeinen) akzeptieren einen einzigen Parameter, der in diesem Beispiel params. Wenn Sie console.log(params) zu Ihrem Code hinzufügen, können Sie alles sehen, was wir erhalten, wenn die Funktion ausgeführt wird. Prüfen Sie die API-Dokumente für eingehende SMSkönnen wir sehen, dass die Telefonnummer, die wir beantworten wollen, als Abfrageparameter mit dem Namen msisdn.

Um die Telefonnummer zu erfassen, können wir einen Abschnitt in die main() Funktion (kurz vor der Rückkehr) hinzufügen, um die eingehenden Variablen in ein Array namens query_data damit wir sie verwenden können:

// who are we texting? Get phone number
var query_pieces = params.__ow_query.split("&");
var query_data = [];
query_pieces.forEach(function(item) {
  item_pieces = item.split("=");
  query_data[item_pieces[0]] = item_pieces[1];
});
console.log("Destination: " + query_data["msisdn"]);

Der obige Code ist nicht schön, und Sie sollten sehr vorsichtig sein, was passiert, wenn diese Variablen nicht vorhanden sind, aber wenn Sie diesen Abschnitt zu index.js hinzufügt und dann mit demselben Befehl wie zuvor neu verteilt:

bx wsk action update sms-fortune/incoming --kind nodejs:8 --web raw index.js

Schicken Sie, während Sie die Protokolle beobachten, erneut eine SMS an Ihre Eingangsnummer. Diesmal sollten Sie die Zeile Destination: und die Rufnummer, von der Sie die Nachricht gesendet haben, in den Protokollen erscheinen. Wir haben die Informationen, die wir brauchen, um eine SMS zurückzuschicken.

Schritt 4: Einige Geheimnisse einrichten

Wir können die eingehenden SMS per Webhook empfangen, da wir die URL, an die die Daten gesendet werden, durch Anmeldung bei unserem Konto festlegen mussten. Bevor wir jedoch die Antwort-SMS senden können, müssen wir uns authentifizieren können.

Für diesen Abschnitt benötigen Sie Ihren API-Schlüssel und Ihr API-Geheimnis - diese sind oben auf Ihrem Nexmo Dashboard. Um der Best Practice im Umgang mit solchen Geheimnissen zu folgen, vermeiden wir es, diese Werte in Dateien zu schreiben und verwenden stattdessen Umgebungsvariablen. Die Idee ist, dass wir die Variablen für die aktuelle Umgebung setzen; wenn Sie ein neues Terminalfenster öffnen oder Ihren Computer neu starten, bleiben sie nicht bestehen und Sie müssen sie erneut setzen.

Die zu setzenden Variablen sind NEXMO_API_KEY und NEXMO_API_SECRETund die Befehle sehen wie folgt aus (ersetzen Sie Ihre Werte nach den = Zeichen);

export NEXMO_API_KEY=awesomeKey
export NEXMO_API_SECRET=awesomeSecret

Da unsere aktuelle Umgebung nun die Geheimnisse kennt, können wir sie in unseren Befehlen verwenden.

Als Nächstes werden wir diese Geheimnisse dem Paket beibringen, das wir zuvor erstellt haben. Dazu aktualisieren wir es und setzen dabei die Parameter. Hier ist der Befehl:

bx wsk package update sms-fortune -p apikey $NEXMO_API_KEY -p apisecret $NEXMO_API_SECRET

Diese Parameter befinden sich nicht in unserem Code, sondern im Paket, so dass sie für unsere Aktion verfügbar sind, da sie sich im selben Paket befindet. Wenn Sie den console.log(params) Befehl zu Ihrer Aktion hinzufügen, sie dann einsetzen und die Protokolle während der Ausführung beobachten, werden Sie diese Werte sehen.

Wir haben nun alle Informationen, die wir zum Senden der Antwort-SMS benötigen: das Cookie, die Telefonnummer und unsere API-Anmeldeinformationen.

Schritt 5: Glückskeks per SMS versenden

Um eine SMS an dieselbe Nummer zurückzuschicken, die uns eine Nachricht geschickt hat, müssen wir einen API-Aufruf tätigen; dieser Abschnitt befasst sich mit diesem letzten Teil des Puzzles. Vielleicht finden Sie auch unseren Baustein für den SMS-Versand als Referenz nützlich sein.

Eine Sache, auf die man bei serverlosem JavaScript achten sollte, ist, dass es keine Ereignisschleife wie wir sie gewohnt sind. Folglich müssen alle asynchronen Vorgänge wie Datenbankabfragen oder die API-Anfrage, die wir in unserem Code durchführen wollen, mit async/await angekündigt oder behandelt werden. Dieses Beispiel verwendet die request-promise Bibliothek, um diesen promisifizierten API-Aufruf zu ermöglichen.

Das Hinzufügen von Bibliotheken macht die Sache etwas komplizierter, als wir es bisher mit einer einzigen Datei index.js Datei hatten, aber das ist nichts, was wir nicht in den Griff bekommen können.

Für den Anfang benötigen wir eine package.json Datei. Meine sieht so aus:

{
  "name": "sms-fortunes",
  "description": "Simple demo for getting a fortune cookie by SMS",
  "dependencies": {
    "request": "^2.85.0",
    "request-promise": "^4.2.2"
  }
}

Sie können auch diese Datei kopieren von GitHub. Bearbeiten Sie sie, wenn Sie möchten (wahrscheinlich ist das nicht nötig), und installieren Sie dann diese Abhängigkeiten mit npm:

npm install

Wenn wir unsere Aktion bereitstellen, müssen wir sowohl die Bibliotheken als auch die index.js Datei enthalten. Um dies zu erreichen, können wir alles, was wir brauchen, in eine Datei packen und diese stattdessen bereitstellen. Da dies ein mehrstufiger Prozess ist (okay, zwei Schritte, aber immerhin), erstelle ich gerne ein Skript, das dies erledigt. Auf diese Weise vergesse ich nie, die Zip-Datei neu zu erstellen oder sie in die Cloud zu übertragen, oder was es sonst noch zu vergessen gibt!

Hier ist meine deploy.sh Datei (und auch hier finden Sie das Original auf GitHub:

#!/bin/bash

rm -f sms-fortune.zip
zip -rq sms-fortune.zip index.js node_modules

bx wsk action update sms-fortune/incoming --kind nodejs:8 --web raw sms-fortune.zip

Dieses Skript löscht die alte Zip-Datei, fügt unsere Datei und unsere Anforderungen in eine neue Datei ein und führt dann denselben Aktualisierungscode aus, den wir zuvor verwendet haben, liefert aber stattdessen die Zip-Datei. Aktualisieren wir index.js um unsere schönen neuen Bibliotheken zu verwenden und dann entweder dieses Skript oder die oben gezeigten Befehle zu verwenden, um die Aktion bereitzustellen.

Zur Verwendung deploy.shzu verwenden, müssen Sie es für Ihren Benutzer ausführbar machen, damit Sie es ausführen können

Holen Sie sich die aktualisierte Version von index.js von dieser Ressource auf GitHub und fügen Sie sie in Ihr Projekt ein. Ich habe eine gekürzte Version dieses Codes unten eingefügt:

const rp = require("request-promise");

exports.main = function(params) {
  // choose a fortune cookie for this user
  var data = getCookies();
  var random = Math.floor(Math.random() * 430);
  var cookie = data[random];
  console.log("Fortune: " + cookie);

  // who are we texting? Get phone number
  // WARNING fails horribly if this data isn't present
  var query_pieces = params.__ow_query.split("&");
  var query_data = [];
  query_pieces.forEach(function(item) {
    item_pieces = item.split("=");
    query_data[item_pieces[0]] = item_pieces[1];
  });
  console.log("Destination: " + query_data["msisdn"]);

  // text the cookie to the user who texted us
  var options = {
    method: "POST",
    uri: "https://rest.nexmo.com/sms/json",
    body: {
      from: "SMS Fortunes Demo",
      text: cookie,
      to: query_data["msisdn"],
      api_key: params.apikey,
      api_secret: params.apisecret
    },
    json: true
  };

  return rp(options).then(function(response) {
    // response has info from Nexmo SMS service
    return Promise.resolved({ statusCode: 200, body: cookie });
  });
};

function getCookies() {
  return [
    "A day for firm decisions!!!!! Or is it? ",
    // ~400 more lines
    "Your talents will be recognized and suitably rewarded. ",
    "Your temporary financial embarrassment will be relieved in a surprising manner. ",
    "Your true value depends entirely on what you are compared with. "
  ];
}

Fügen Sie alles zusammen, packen Sie es ein, stellen Sie es bereit, beobachten Sie die Protokolle - falls etwas Unerwartetes passiert - und senden Sie eine SMS an Ihre Eingangsnummer. Tada! Ein dummer Glückskeks als Antwort :)

Schlussfolgerung

SMS ist für Benutzer einfach, und hoffentlich haben Sie anhand dieses Beispiels gesehen, dass es auch für Entwickler recht einfach zu realisieren ist. Der Code hier empfängt SMS und identifiziert den Benutzer, dann sendet er eine SMS zurück an denselben Benutzer. Es wird ein serverloses Backend verwendet, weil es kostengünstig ist und sich leicht einführen lässt. Dieses Beispiel lieferte einige triviale Inhalte, aber ich bin sicher, dass es Ideen für Ihre Anwendungen liefert. Sie könnten zum Beispiel die eingehende Nachricht parsen und verschiedene Antworten darauf geben oder eine API aufrufen, um Inhalte abzurufen, anstatt sie hart zu kodieren, wie wir es in diesem Beitrag getan haben, um die Dinge einfach zu halten. Der Himmel ist die Grenze, und wir würden gerne wissen, was Sie machen!

Nächste Schritte

Wenn dies Ihr Interesse geweckt hat, mehr mit SMS zu machen, finden Sie hier einige Ideen, was Sie als Nächstes ausprobieren können:

Teilen Sie:

https://a.storyblok.com/f/270183/250x250/e3d3b71060/lornajane.png
Lorna MitchellVonage Ehemalige

Lorna ist eine Software-Ingenieurin mit einer unheilbaren Blogging-Sucht. Sie versucht, Worte und Code gleichermaßen zu bändigen.