
Partager:
Lorna est une ingénieure en informatique qui a la manie incurable de bloguer. Elle tente d'apprivoiser les mots et le code à parts égales.
Des SMS sans serveur avec Nexmo et IBM
Temps de lecture : 10 minutes
Communiquer avec les utilisateurs par SMS est un excellent moyen d'interagir avec les gens de manière informelle. Que vous souhaitiez automatiser les réponses à vos questions les plus fréquentes, organiser un concours ou communiquer avec vos utilisateurs sur un sujet complètement différent, le SMS est un excellent choix. Dans ce billet, nous allons nous pencher sur un exemple amusant et trivial tout en examinant en détail la manière de réaliser ces tâches. Nous allons créer un système qui répond à un SMS entrant par un "fortune cookie". Il s'agit des messages d'accueil utilisés dans la fonction "message du jour" sur les anciennes stations de travail *nix, pensez-y comme une version plus geek des adorables messages de chargement que vous voyez sur Slack.
Serverless est un choix idéal pour une tâche comme celle-ci, où chaque message entrant est indépendant de tous les autres. Les plateformes sans serveur comme IBM Cloud Functions (utilisé dans cet exemple), Amazon Lambda ou Azure Functions s'étendent toutes horizontalement lorsqu'elles sont soumises à une charge. Le grand avantage réside dans le modèle de tarification ; les plateformes sans serveur ne facturent que le temps d'exécution de votre fonction, il n'est donc pas nécessaire de payer une redevance fixe pour un serveur en cours d'exécution. En prime, le déploiement d'une fonction comporte moins d'étapes que la mise en place d'un serveur, ce qui permet de démarrer plus rapidement.
Avant de commencer
Il y a quelques conditions préalables à remplir avant de suivre ce tutoriel :
Un IBM Cloud Account pour pouvoir déployer notre fonction sans serveur (c'est gratuit).
L'outil de ligne de commande
bxOutil de ligne de commande pour IBM Cloud etwskCloud Functions plugin - utilisez les instructions d'installation. Connectez-vous et définissez votre espace de travail cible avant de continuer.
Vonage API Account
To complete this tutorial, you will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the Vonage API Dashboard.
Étape 1 : Créer et déployer une fonction sans serveur
Une fonction serverless est une fonction (ici JavaScript ; IBM Cloud prend en charge de nombreux autres langages de programmation) déployée dans le cloud. La fonction s'exécute en réponse à un événement, et l'un des événements courants est une requête web. En créant une seule fonction et en la déployant, nous pouvons rapidement être prêts à recevoir un SMS d'un utilisateur.
Obtenez la fonction à partir de ce lien vers une version spécifique sur GitHub. Vous devriez avoir un contenu qui ressemble à cette version abrégée :
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. "
];
}Enregistrez le contenu dans index.js et jetez un coup d'œil à la fonction main() en haut de la page. Il s'agit de quelques lignes de code pour récupérer ce grand tableau de biscuits de la fortune (provenant de l'application Ubuntu fortune-mod d'Ubuntud'Ubuntu) et en choisir un au hasard, avant de l'enregistrer et de le renvoyer. Si vous souhaitez modifier la fonction getCookies() pour proposer d'autres biscuits de la fortune, n'hésitez pas !
Dans la programmation sans serveur, les "fonctions" sont généralement appelées "actions".
Pour transférer cette action dans le nuage, nous allons d'abord créer un paquet dans lequel nous la placerons. Un paquet permet de conserver les actions ensemble et de leur permettre de partager des paramètres.
En utilisant la commande bx que vous avez définie plus tôt, créez le paquet à l'aide de cette commande :
bx wsk package create sms-fortuneVous devriez voir un "OK" heureux, et avec le paquet en place, nous pouvons aller de l'avant et déployer la fonction aussi. Voici la commande pour cela :
bx wsk action update sms-fortune/incoming --kind nodejs:8 --web raw index.jsUne fois encore, vérifiez que le message "OK" indique que la commande s'est déroulée correctement. Nous avons déployé une fonction. Elle s'appelle incoming (puisqu'elle gère les SMS entrants) et elle existe dans le paquetage sms-fortune et elle existe dans le paquetage Les autres arguments sont les suivants --kind pour indiquer la version de JS à utiliser et --web raw pour nous permettre de faire une requête web à cette action.
L'appel
updatesur une action qui n'existe pas déclenche à la placecreatece qui fait que cette commande fonctionne quel que soit l'état actuel. Encore mieux : elle fonctionne toujours si vous voulez éditerindex.jset déployer à nouveau.
Alors, qu'attendons-nous ? Découvrons l'URL de notre action et demandons-la. Voici la commande pour découvrir l'URL de l'action :
bx wsk action get --url sms-fortune/incomingCopiez l'URL de la réponse à la commande ci-dessus. Vous pouvez utiliser cURLvotre navigateur ou tout autre client HTTP pour envoyer une requête à cette URL. Si tout s'est déroulé comme prévu, la réponse devrait inclure une remarque spirituelle. Répétez la requête plusieurs fois pour plus d'humour si vous le souhaitez.
Étape 2 : Traiter un SMS entrant
Nous avons défini le point de terminaison vers lequel notre webhook doit pointer, alors allons-y et câblons-le. Vous pouvez également consulter notre bloc de construction pour la réception de SMS à titre de référence.
Tout d'abord, nous avons besoin d'un moyen de voir quand Nexmo appelle notre fonction. Jusqu'à présent, nous l'avons demandé directement, mais lors de la réception d'un SMS, il n'y aura pas de réponse que nous puissions voir. A la place, ouvrez une nouvelle fenêtre de terminal et commencez à voir les logs de vos actions avec la commande suivante :
bx wsk activation pollLaissez tourner cette fonction (j'aime la mettre sur mon deuxième moniteur si j'en ai un) et utilisez la même requête curl/navigateur que précédemment afin de voir ce qui se passe lorsque la fonction s'exécute. Comme vous pouvez le remarquer, ce n'est pas du temps réel, et nous devons parfois attendre quelques secondes pour que les journaux apparaissent.
Maintenant que nous pouvons savoir quand la fonction s'exécute correctement, essayons d'en faire notre point de terminaison pour les SMS. Visitez votre page Numbers sur le tableau de bord Nexmo et cliquez sur "Modifier" sur le numéro à utiliser, et sous "SMS" collez l'URL de l'action dans le champ "Webhook URL". N'oubliez pas de cliquer sur "Mettre à jour".
Tout est prêt : envoyez un SMS à votre numéro entrant, et surveillez ces journaux pour voir l'action se dérouler !
Étape 3 : Découvrir le numéro auquel répondre
À ce stade, nous avons déployé une action serverless et l'avons définie comme point de terminaison pour le webhook SMS entrant à utiliser. Pour pouvoir répondre à l'utilisateur qui a envoyé le SMS, nous devons inspecter les données qui arrivent avec le webhook pour savoir qui l'a envoyé.
Les actions IBM Cloud Functions (et d'ailleurs Apache OpenWhisk en général) acceptent un seul paramètre, qui dans cet exemple s'appelle params. Si vous ajoutez console.log(params) à votre code, vous pouvez voir tout ce que nous recevons lorsque la fonction s'exécute. Vérifier dans la documentation de l API docs for incoming SMSentrants, nous pouvons voir que le numéro de téléphone auquel nous voulons répondre arrive sous la forme d'un paramètre de requête appelé msisdn.
Pour capturer le numéro de téléphone, nous pouvons ajouter une section à la fonction main() (juste avant de retourner) pour récupérer les variables entrantes dans un tableau appelé query_data afin de pouvoir les utiliser :
// 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"]);
Le code ci-dessus n'est pas très joli, et vous devriez faire très attention à ce qui se passe si ces variables ne sont pas présentes, mais si vous ajoutez cette section à index.js puis redéployez en utilisant la même commande que précédemment :
bx wsk action update sms-fortune/incoming --kind nodejs:8 --web raw index.jsTout en continuant à observer ces journaux, envoyez à nouveau un SMS à votre numéro entrant. Cette fois, vous devriez voir apparaître dans les journaux la ligne Destination: et le numéro de téléphone à partir duquel vous avez envoyé le message apparaissent dans les journaux. Nous avons obtenu les informations dont nous avons besoin pour répondre au SMS.
Étape 4 : Établir des secrets
Nous pouvons recevoir le SMS entrant par webhook parce que nous avons dû définir l'URL à laquelle les données sont envoyées en nous connectant à notre Account. Cependant, avant de pouvoir envoyer le SMS de réponse, nous devons être en mesure de nous authentifier.
Pour cette section, vous avez besoin de votre clé API et de votre secret API - ils sont visibles en haut de votre tableau de bord Nexmo. Pour respecter les meilleures pratiques en matière de gestion de secrets de ce type, nous éviterons d'écrire ces valeurs dans des fichiers et utiliserons plutôt des variables d'environnement. L'idée est de définir les variables pour l'environnement actuel ; si vous ouvrez une nouvelle fenêtre de terminal ou redémarrez votre ordinateur, elles ne persistent pas et vous devrez les définir à nouveau.
Les variables à définir sont NEXMO_API_KEY et NEXMO_API_SECRETet les commandes ressemblent à ceci (remplacez vos valeurs après les signes = ) ;
export NEXMO_API_KEY=awesomeKey
export NEXMO_API_SECRET=awesomeSecretMaintenant que notre environnement actuel connaît les secrets, nous pouvons les utiliser dans nos commandes.
Ensuite, nous allons enseigner ces secrets au paquet que nous avons créé plus tôt. Pour ce faire, nous le mettons à jour et définissons les paramètres au fur et à mesure. Voici la commande :
bx wsk package update sms-fortune -p apikey $NEXMO_API_KEY -p apisecret $NEXMO_API_SECRETCes paramètres ne sont pas dans notre code, mais ils sont dans le paquetage, donc ils sont disponibles pour notre action puisqu'elle est dans le même paquetage. Si vous ajoutez la commande console.log(params) à votre action, puis la déployez et observez les logs lorsque vous l'exécutez, vous verrez ces valeurs.
Nous disposons désormais de toutes les informations nécessaires pour envoyer le SMS de réponse : le cookie, le numéro de téléphone et les informations d'identification de l'API.
Étape 5 : Envoyer le biscuit chinois par SMS
Pour renvoyer un SMS au même numéro que celui qui nous a envoyé un message, nous devons faire un appel à l'API ; cette section traite de cette dernière pièce du puzzle. Vous pouvez également trouver notre module d'envoi de SMS à titre de référence.
Une chose à laquelle il faut faire attention avec le JavaScript sans serveur est qu'il n'a pas de boucle d'événements comme nous en avons l'habitude. Par conséquent, toutes les opérations asynchrones telles que les requêtes de base de données ou la demande d'API que nous sommes sur le point d'effectuer dans notre code doivent être promises ou gérées à l'aide d'async/await. Cet exemple utilise la bibliothèque request-promise pour activer cet appel API promisifié.
L'ajout de bibliothèques crée un peu plus de complexité que ce que nous avons eu jusqu'à présent avec tout dans un seul fichier, mais ce n'est rien que nous ne puissions gérer. index.js mais ce n'est rien que nous ne puissions gérer.
Pour commencer, nous avons besoin d'un package.json . Le mien ressemble à ceci :
{
"name": "sms-fortunes",
"description": "Simple demo for getting a fortune cookie by SMS",
"dependencies": {
"request": "^2.85.0",
"request-promise": "^4.2.2"
}
}Vous pouvez également copier ce fichier depuis GitHub. Modifiez-le si vous le souhaitez (vous n'avez probablement pas besoin de le faire) et installez ensuite ces dépendances avec npm:
npm installLorsque nous déployons notre action, nous devons inclure les bibliothèques ainsi que le fichier index.js . Pour ce faire, nous pouvons compresser tout ce dont nous avons besoin dans un seul fichier et le déployer à la place. Comme il s'agit d'un processus en plusieurs étapes (d'accord, deux étapes, mais tout de même), j'aime bien créer un script pour le gérer. De cette façon, je n'oublie jamais de recréer le fichier zip, ni de l'envoyer sur le cloud, ni rien d'autre !
Voici mon fichier deploy.sh (et encore une fois, vous pouvez trouver l'original sur 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.zipCe script supprime l'ancien fichier zip, ajoute notre fichier et nos exigences à un nouveau fichier, puis exécute le même code de mise à jour de l'action que nous avons utilisé précédemment, mais en fournissant le fichier zip à la place. Mettons à jour index.js pour utiliser nos jolies nouvelles bibliothèques, puis utilisons soit ce script, soit les commandes présentées ci-dessus pour déployer l'action.
Pour utiliser
deploy.shvous devez le rendre exécutable pour votre utilisateur afin que vous puissiez l'exécuter
Téléchargez la version mise à jour de index.js à partir de cette ressource sur GitHub et mettez-la dans votre projet. J'ai inclus une version abrégée de ce code ci-dessous :
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. "
];
}
Assemblez le tout, fermez la fermeture éclair, déployez-le, surveillez les journaux - au cas où quelque chose d'inattendu se produirait - et envoyez un SMS à votre numéro d'appel. Tada ! Un biscuit chinois en réponse :)
Conclusion
Les SMS sont faciles à utiliser pour les utilisateurs, et j'espère que cet exemple vous a montré que pour les développeurs, c'est également tout à fait réalisable. Le code ici reçoit des SMS et identifie l'utilisateur, puis renvoie un SMS à ce même utilisateur. Il utilise un backend sans serveur parce qu'il est peu coûteux à exécuter et facile à démarrer. Cet exemple a renvoyé un contenu trivial, mais je suis sûr qu'il suscite des idées pour vos Applications. Par exemple, vous pourriez analyser le message entrant et donner différentes réponses en fonction de celui-ci, ou faire un appel à une API pour obtenir le contenu plutôt que de l'avoir codé en dur comme nous l'avons fait dans ce post pour garder les choses simples. Il n'y a pas de limite, et nous serions ravis de savoir ce que vous créez !
Prochaines étapes
Si cela vous a donné envie d'en faire plus avec les SMS, voici quelques idées pour la suite :
Une discussion sur les différents types de messagerie et les bots : https://developer.vonage.com/en/blog/ai-bot-messaging-push-notifications-sms-dr/
Cette excellente introduction aux appels SMS et Voice https://developer.vonage.com/en/blog/sms-voice-programmable-communications-dr/
Un exemple d'application de chat de groupe par SMS (en PHP) https://developer.vonage.com/en/blog/sms-voice-programmable-communications-dr/
Un billet de plus haut niveau sur la façon dont les SMS peuvent vous aider à dialoguer avec vos utilisateurs : https://developer.vonage.com/en/blog/top-5-ways-to-use-sms-to-increase-mobile-user-acquisition-and-engagement/
