https://d226lax1qjow5r.cloudfront.net/blog/blogposts/checking-the-tube-status-with-nexmo-and-tfl-apis-dr/Elevate-Tube-Status.png

Vérifier l'état du métro de Londres avec l'API SMS de Vonage

Publié le April 30, 2021

Temps de lecture : 21 minutes

Aujourd'hui, nous allons créer une application qui nous permettra de vérifier le statut d'une ligne donnée du métro londonien en utilisant l'API Vonage SMS DE VONAGE. Nous allons nous appuyer sur l'API de Transport for London (API TFL) pour récupérer des données en temps réel sur l'état d'une ligne de métro choisie par l'utilisateur. Le déclencheur sera un SMS entrant vers notre numéro virtuel. Cela ressemble-t-il à un projet ? Suivez ce tutoriel. Nous obtiendrons le même état que sur leur site web directement dans notre téléphone via SMS. C'est particulièrement pratique si, pour une raison ou une autre, vous n'avez pas accès à Internet pour consulter Google Maps/Citymapper ou si vous avez dépassé votre allocation mensuelle de données.

Le flux de travail de notre application ressemblera au diagramme suivant :

sketch diagram of workflowsketch diagram of workflow

Je sais 😌 il y a de fortes chances que vous ne viviez pas à Londres, et vous pouvez penser que ce tutoriel n'est pas pertinent pour vous. Cependant, je crois sincèrement qu'il s'agit d'un exemple très illustratif de ce que vous pouvez construire au-dessus de Vonage.

Ce tutoriel vous guidera à travers toutes les étapes pour créer cette application à partir de zéro. Cependant, si vous préférez vous procurer le dépôt dépôt terminéterminé, n'hésitez pas à aller le consulter !

Conditions préalables

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.

This tutorial also uses a virtual phone number. To purchase one, go to Numbers > Buy Numbers and search for one that meets your needs.

Pour la première partie du tutoriel, nous aurons besoin de.. :

  • Connaissances de base en Javascript/node.js.

  • Vous devrez utiliser ngrok pour exposer votre serveur local à l'internet afin que Vonage puisse l'atteindre. Nous avons un tutoriel détaillé sur ce sujet.

Si vous souhaitez que votre application soit déployée sur Heroku, vous aurez également besoin de :

  • A Compte Heroku (nous n'utiliserons que le Free-tier).

  • Quelques principes de base de git pour déployer notre application sur Heroku.

Mise en place du projet

Créez un dossier de projet nommé tubestatus sur votre machine locale et accédez-y.

mkdir tubestatus && cd tubestatus

Créons notre fichier principal dans lequel nous stockerons notre code. Nous allons également créer notre fichier .env dans lequel nous stockerons notre Vonage et nos informations d'identification ainsi que d'autres variables.

touch server.js .env

L'étape suivante consiste à créer le fichier package.json fichier.

npm init -y

Installons et sauvegardons les dépendances nécessaires.

npm install --s express dotenv @vonage/server-sdk body-parser request

Il faut maintenant créer une appli Vonage et acheter un numéro.

Installez le CLI de Vonage globalement avec cette commande :

npm install @vonage/cli -g

Ensuite, configurez le CLI avec votre clé et votre secret API Vonage. Vous pouvez trouver ces informations dans le tableau de bord du développeur.

vonage config:set --apiKey=VONAGE_API_KEY --apiSecret=VONAGE_API_SECRET

Lançons ngrok sur le même port que celui sur lequel notre serveur local écoute (dans mon cas 3000).

ngrok http 3000

ngrok

Maintenant, utilisez le CLI pour créer une application Vonage et créez un webhook vers votre URL ngrok.

vonage apps:create ✔ Application Name … my_project ✔ Select App Capabilities › Messages ✔ Create messages webhooks? … yes ✔ Inbound Message Webhook - URL … http://3126bbcb.ngrok.io/inbound ✔ Inbound Message Webhook - Method › POST ✔ Status Webhook - URL … https://example.com/webhook_name ✔ Status Webhook - Method › POST ✔ Allow use of data for AI training? Read data collection disclosure - https://help.nexmo.com/hc/en-us/articles/4401914566036 … no Creating Application... done

Vous voudrez sauvegarder l'identifiant qui est imprimé après l'opération. Application created:. Vous en aurez besoin prochainement.

Vous avez maintenant besoin d'un numéro pour pouvoir recevoir des appels. Vous pouvez en louer un en utilisant la commande suivante (en remplaçant le code du pays par votre code). Par exemple, si vous êtes aux États-Unis, remplacez GB par US:

vonage numbers:search US vonage numbers:buy [NUMBER] [COUNTRYCODE]

Reliez maintenant le numéro à votre application :

vonage apps:link --number=VONAGE_NUMBER APP_ID

Enfin, remplissez le fichier .env avec la clé API de Vonage pour apiKey, le secret Vonage pour apiSecretet le numéro que vous venez d'acheter pour from. Ensuite, ajoutez votre TFL app_id et app_key.

apiKey = your_vonage_api_key apiSecret = your_vonage_api_secret from = your_vonage_number app_id = TFL_app_id app_key = TFL_app_key PORT = 3000

Commençons par les choses amusantes

Comme toujours, exigeons toutes les dépendances au début de notre projet. Nous utiliserons le express pour construire notre application. Nous allons utiliser la bibliothèque dotenv pour pouvoir travailler avec les variables d'environnement. Nous allons utiliser body-parser pour pouvoir analyser les requêtes entrantes provenant du serveur de Vonage. Pour les requêtes API vers l'API TFL, j'ai choisi la bibliothèque request bibliothèque car je la trouve assez simple, mais vous pouvez en utiliser d'autres comme axios. Enfin et surtout, 😊 nous avons besoin de la bibliothèque Vonage pour renvoyer l'état de la ligne à l'utilisateur.

Collez le code suivant dans votre fichier nouvellement créé. Nous importons toutes les dépendances installées, et nous avons défini une variable qui contient tous les noms de ligne acceptés fournis par l'API TFL. Nous ne voulons pas envoyer une requête à l'API TFL si l'utilisateur ne fournit pas un nom de ligne valide (je vais expliquer dans un instant pourquoi toutes les valeurs sont en majuscules). La variable appelée status contiendra tout statut pertinent en relation avec le statut de la ligne en question. Ajoutez également les différentes informations d'identification dont vous aurez besoin pour utiliser les API de Vonage et de TFL respectivement. Ces informations seront récupérées dans le fichier .env fichier :

const Vonage = require('@vonage/server-sdk')
const express = require('express');
const bodyParser = require('body-parser');
const port = process.env.PORT || 3000;
const request = require('request');
const dotenv = require('dotenv');

let status = []

dotenv.config();

const lines =['CENTRAL','BAKERLOO', 'DISTRICT', 'VICTORIA', 'NORTHERN', 'CIRCULAR', 'HAMMERSMITH-CITY', 'JUBILEE', 'METROPOLITAN', 'PICCADILLY', 'WATERLOO-CITY' ];

const vonage = new Vonage({
  apiKey: process.env.apiKey,
  apiSecret: process.env.apiSecret
})

Dans les lignes qui suivent, nous lançons notre application et définissons un middleware de base. Notez que nous avons défini le port 3000 pour l'écoute de notre serveur, mais vous pouvez en choisir d'autres. Tenez compte du fait qu'il y a un espace entre les deux (commenté) qui sera rempli avec notre route pour les requêtes entrantes :

const app = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended:true}));

//We will define our route here

app.listen(port, ()=>{console.log('App listening in port ', port)});

Définissons deux fonctions pour mettre un peu d'ordre dans le code. La première fonction sendSms() va prendre deux paramètres : le numéro de téléphone de l'utilisateur et le texte à renvoyer à l'utilisateur. Nous allons réutiliser une partie du code.

function sendMessage(to, message){
  vonage.message.sendSms(process.env.from, to, message, (err, responseData) => {
    if (err) {
        console.log(err);
    } else {
        if(responseData.messages[0]['status'] === "0") {
            console.log("Message sent successfully.");
        } else {
            console.log(`Message failed with error: ${responseData.messages[0]['error-text']}`);
        }
    }
})
}

La deuxième fonction checkLineStatus() prendra deux paramètres : le nom de la ligne et le numéro de téléphone de l'utilisateur, car nous enverrons un message à l'utilisateur avec les informations demandées.

function checkLineStatus(Line, number) {

    var options = {
        json: true,
        url: 'https://api.tfl.gov.uk/Line/' + Line + '/status?app_id=' + app_id + '&app_key=' + app_key,
    }

    request(options, function (err, res, body) {
        if (err) {
            console.log(err)

        }
        else {
            if (body[0].lineStatuses[0].statusSeverityDescription === 'Good Service') {
                sendMessage(number, 'There is a ' + body[0].lineStatuses[0].statusSeverityDescription + ' operating on ' + body[0].name + ' line')

            }
            else {
                for (let i = 0; i < body.length; i++) {
                    for (let j = 0; j < body[i].lineStatuses.length; j++) {
                        status.push(body[i].lineStatuses[j].reason)
                    }
                }
                sendMessage(number, status)
                console.log(status)
            }
        }
    })
}

Si l'état de la ligne donnée est Bon service (notez que l'API TFL renvoie toujours ce résultat lorsque le service est normal), renvoyez-le à l'utilisateur. Dans le cas contraire, il est important de tenir compte du fait qu'en cas d'interruption de la ligne, l'API TFL renverra un message reason dans l'objet lineStatus à l'intérieur de l'objet. C'est ce que nous introduisons dans notre tableau pour chaque perturbation survenue (en espérant qu'il n'y en ait pas pour le bien des navetteurs 😂). N'oubliez pas que dans cette fonction, nous appelons également la fonction sendSms() pour renvoyer l'état de la ligne à l'utilisateur dans les deux scénarios.

Enfin, nous allons remplir notre route entrante pour écouter les messages entrants des utilisateurs. Voyons à quoi ressemble un message entrant de Vonage.

{ "msisdn": "447700900001", "to": "447700900000", "messageId": "0A0000000123ABCD1", "text": "Hello world", "type": "text", "keyword": "Hello", "message-timestamp": "2020-01-01T12:00:00.000+00:00", "timestamp": "1578787200", "nonce": "aaaaaaaa-bbbb-cccc-dddd-0123456789ab", "concat": "true", "concat-ref": "1", "concat-total": "3", "concat-part": "2", "data": "abc123", "udh": "abc123" }

Pour atteindre notre objectif, nous allons devoir stocker deux des paramètres ci-dessus : le texte envoyé par l'utilisateur (nom de la ligne) et le numéro de l'utilisateur. Ces paramètres seront stockés dans nos nouvelles variables (Tube_line et Number_msisdn respectivement) dès que notre /inbound est atteinte.

Il est important de noter que nous mettons une majuscule à la ligne de tube. La raison en est que nous voulons comparer une chaîne spécifiée à une autre chaîne en ignorant les considérations de cas (l'utilisateur peut nous envoyer Central, CENTRAL ou central). En mettant une majuscule à l'entrée de l'utilisateur et en la comparant à notre tableau de lines (déjà en majuscules), nous contournons ce problème. Ajoutez le code suivant dans l'espace que nous avons réservé pour notre route.

app.post('/inbound', (req, res) => {
    let Tube_Line = req.body.text.toUpperCase()
    let Number_msisdn = req.body.msisdn

    if ((lines.indexOf(Tube_Line) > -1)) {
        checkLineStatus(Tube_Line, Number_msisdn)
    }
    else {
        sendMessage(Number_msisdn, 'Valid values are ' + lines)

    }

    res.status(204).send()
})

Le bit (lines.indexOf(Tube_Line) &gt; -1) nous permettra de vérifier si la valeur stockée dans Tube_line correspond à l'une des valeurs du tableau lines tableau. Cette méthode renvoie le premier indice auquel l'élément donné peut être trouvé dans un tableau, ou -1 s'il n'est pas présent dans un tableau. Nous ne voulons vérifier l'état d'une ligne donnée que si l'entrée correspond à l'une des valeurs valides. Sinon, nous recevrons un beau HTTP 404 en retour de l'API TFL. En supposant que nous soyons assez gentils pour faire savoir à l'utilisateur qu'il a introduit une valeur erronée, nous lui renverrons un message lui indiquant les valeurs valides. Cela se fait lorsque la méthode indexOf est égale à -1, comme expliqué ci-dessus.

Très bien, il est temps de tester cela 🙈. Prenons notre téléphone et envoyons un SMS avec n'importe quel nom de ligne qui correspond à notre lines à votre numéro Vonage. A titre d'exemple, je vais demander le nom de la ligne qui me conduit au travail tous les jours.

demo of app performance on phonedemo of app performance on phone

💃💃 Comme vous pouvez le voir, peu de temps après avoir envoyé un message à notre numéro virtuel configuré précédemment, nous recevons un SMS avec l'état de la ligne demandée. Bravo et merci d'être allé jusqu'au bout !

Modélisation des messages entrants

Si, pour une raison quelconque, vous n'avez pas la possibilité d'utiliser votre téléphone portable ou si vous ne souhaitez pas envoyer manuellement des SMS pour tester l'application, nous avons également prévu le nécessaire. Un message entrant est simplement représenté par une requête GET ou POST à votre webhook. Vous pouvez définir la méthode que vous voulez que Vonage utilise pour livrer vos messages entrants dans vos Paramètres du tableau de bord de Vonage. J'utilise POST pour ce tutoriel.

En tenant compte de cela, nous pouvons simuler le comportement d'un message entrant en frappant manuellement notre serveur local exposé avec ngrok pour voir si l'application fonctionne comme elle le devrait. J'utiliserai POSTMAN mais vous pouvez utiliser n'importe quel autre service de votre choix. Nous allons faire une requête POST à notre webhook entrant en définissant un corps JSON brut générique (comme celui que Vonage enverrait pour un message entrant). Cependant, n'oubliez pas de modifier l'élément msisdn afin que notre application sache où répondre. Remplacez également le paramètre text pour jouer avec différentes valeurs de nom de ligne, vous pouvez taper délibérément une valeur invalide afin de recevoir un message contenant les valeurs autorisées. Ma demande d'API ressemble à ceci :

Dans ce cas, le paramètre to n'est pas pertinent, je lui ai donc donné une valeur aléatoire. Il est important d'ajouter l'en-tête Content-Type et de lui attribuer la valeur application/json afin que notre application sache comment traiter ces données. Comme vous pouvez le voir en bas à droite, notre application retourne un HTTP 204 comme défini dans notre /inbound via la commande res.status(204).send()

Qu'est-ce qui suit ? Déployons sur Heroku

Heroku est une plateforme destinée à déployer facilement votre application Web et à mettre à l'échelle vos services en fonction de vos besoins. Ils offrent également quelques add-ons utiles pour simplifier certaines tâches quotidiennes. Nous allons nous appuyer sur Heroku parce qu'il est assez facile à utiliser et que la documentation est excellente sur le site Heroku. En utilisant Heroku, nous pouvons éviter les tracas liés à la location et à la configuration de notre serveur.

Le concept de dynos existe au sein de la plateforme Heroku. Ce n'est rien d'autre qu'un conteneur dans lequel votre application sera déployée. L'utilisation de votre application consommera des heures de dynos (uniquement lorsqu'elle est en cours d'exécution), mais ne vous inquiétez pas car ils offrent 550 heures gratuites par mois out-of-the-box ou 1000 heures dans le cas où vous acceptez de vérifier votre compte en fournissant une carte de crédit. Vous pouvez facilement augmenter ou réduire la taille de votre application en tenant compte de la demande de trafic, mais cela sort du cadre de ce tutoriel.

Si vous n'avez jamais déployé d'application Heroku, il peut être intéressant de parcourir leur documentation, ou au moins de lire la partie où ils expliquent comment déployer une application node.js. Pour déterminer comment démarrer votre application, Heroku recherche d'abord un fichier Procfile. Il s'agit d'un fichier qui spécifie les commandes exécutées par l'application au démarrage. Si aucun Procfile n'existe pour une application Node.js, Heroku tentera de démarrer un processus web par défaut via le script de démarrage dans votre package.json.

Modifions notre package.jsonafin que la partie qui contient les scripts contienne cette partie :

"scripts": {
    "start": "node server.js"
  },

Ensuite, nous allons créer un fichier .gitignore pour s'assurer que les variables d'environnement locales, les sorties liées à la compilation et les modules ne sont pas livrés au dépôt git

/node_modules
npm-debug.log
.DS_Store
/*.env

Le seul inconvénient de l'utilisation du free-tier est qu'une fois que votre application tourne au ralenti après 30 minutes d'inactivité, il peut s'écouler un certain temps avant qu'elle ne se réveille (lors de la réception d'une nouvelle demande). D'un point de vue pragmatique, cela signifie que nous pouvons constater un léger retard lors de la réception du message de Vonage si l'application a été inactive pendant un certain temps. En effet, la demande à l'API TFL sera traitée une fois que l'application sera redémarrée. Ce délai est acceptable, car cette application n'est pas soumise à des contraintes de temps. Cependant, si vous ne trouvez pas cela suffisant, vous pouvez passer au service payant et avoir un dyno dédié à votre application.

Pour déterminer comment démarrer votre application, Heroku recherche d'abord un Procfile. Si aucun Procfile n'existe pour une application Node.js, Heroku tentera de démarrer un processus web par défaut via le script de démarrage dans votre package.json. La commande d'un type de processus web doit se lier au numéro de port spécifié dans la variable d'environnement PORT. Si ce n'est pas le cas, le dyno ne démarrera pas.

Vérifiez que vous avez le Heroku CLI est installé, puis exécutez les commandes suivantes dans le dossier de votre projet, une à la fois :

git init git add . git commit -m "First commit."

À ce stade, nous avons créé un nouveau dépôt git, ajouté toutes les modifications à notre dépôt et soumis notre premier commit. Créons maintenant notre application et déployons-la sur Heroku :

heroku create tubestatus git push heroku master

Dans ces quelques lignes, nous avons créé notre application Heroku et poussé les changements vers Heroku. Si tout s'est passé comme prévu, vous devriez avoir créé votre propre application. Ils vous fourniront également l'URL où vous pourrez trouver votre application une fois qu'elle aura été déployée. C'est très bien !

Enfin, nous devons indiquer à notre application où trouver les variables d'environnement étant donné que nous n'en avons pas fourni .env file. Exécutez cette commande pour définir les variables de configuration requises

heroku config:set apiKey=xxxxx heroku config:set apiSecret=xxxxxx heroku config:set app_key=xxxxxxxxxxxxxxxxxx heroku config:set app_id=xxxxxxx heroku config:set from=xxxxxxxxxxx

Vous pouvez vérifier que ces variables ont été ajoutées correctement en jetant un coup d'œil aux paramètres de votre application sous Tableau de bord Heroku. Voici à quoi ressemble notre application dans le tableau de bord Heroku. Si nous cliquons sur Révéler les variables de configurationnous verrons les variables d'environnement configurées via la CLI Heroku.

En conclusion, ce processus a été relativement simple ! J'ai pu le mettre en place et le faire fonctionner en quelques minutes, ce qui est excellent. Il ne reste plus qu'à mettre à jour notre numéro pour qu'il pointe vers notre nouveau webhook, vous pouvez simplement reproduire les étapes ci-dessus (lorsque nous avons configuré notre numéro via l'API Numbers). Pour rappel, n'oubliez pas d'inclure le caractère /inbound à la fin de l'URL correspondant à la route dans notre script.

Si nous envoyons un SMS une fois que nous avons mis à jour l'URL du crochet Web entrant pour notre numéro, cela fonctionnera comme prévu. Voici à quoi ressemble l'état d'une perturbation. Il semble qu'il aurait été nécessaire de reprogrammer notre voyage si nous nous rendions à Heathrow par la District Line au moment où j'ai fait ce test.

SMS View of final working app

C'est tout pour aujourd'hui, mais si vous souhaitez continuer à jouer avec nos API, les liens suivants peuvent vous être utiles :

Partager:

https://a.storyblok.com/f/270183/384x384/6007824739/javier-molina-sanz.png
Javier Molina Sanz

Javier studied Industrial Engineering back in Madrid where he's from. He is now one of our Solution Engineers, so if you get into trouble using our APIs he may be the one that gives you a hand. Out of work he loves playing football and travelling as much as he can.