
Partager:
Alex Lakatos est un défenseur des développeurs JavaScript pour Nexmo. Pendant son temps libre, il est bénévole chez Mozilla en tant que Tech Speaker et Reps Mentor. Développeur JavaScript travaillant sur le web ouvert, il en repousse les limites tous les jours. Lorsqu'il ne programme pas à Londres, il aime parcourir le monde, il est donc probable que vous le croisiez dans un salon d'aéroport.
Comment envoyer et recevoir des SMS avec Nuxt.js et l'API SMS de Nexmo
Temps de lecture : 12 minutes
Vue.js est l'un des nouveaux frameworks JavaScript progressifs qui font le tour du monde des applications frontales. C'est l'un des frameworks les plus accessibles, les plus polyvalents et les plus performants qui existent, et ici, chez Nexmo, nous avons récemment changé notre Nexmo Developer Portal pour utiliser Vue.js.
En 2018, nous avons nous avons (em)motorisé EMF Camp en utilisant des applications Vue.js en conjonction avec les Nexmo Client SDKs.
Je voulais explorer un peu plus l'écosystème Vue.js, et je suis tombé sur Nuxt.js. C'est un framework Vue.js modulaire qui facilite la mise en place d'une application de production. Avec Vue.js, vous avez généralement besoin d'un composant back-end pour gérer le mode historique dans les URL, et Nuxt.js s'en charge dès le départ. Il ajoute également une couche d'abstractions sur votre URL en fournissant un Middleware dès le départ. Les intergiciels sont des méthodes qui s'exécutent avant votre code de gestion des routes, et ils fonctionnent à la fois sur votre code Vue.js et sur le serveur.
J'ai donc pensé que cela ferait un excellent substitut pour gérer les appels API sur le serveur, au lieu d'avoir à mettre en place une deuxième application back-end. Dans ce billet de blog, je vais utiliser le middleware serveur Nuxt.js pour envoyer et recevoir des SMS.
Pour les SMS, je vais utiliser l'API Nexmo SMS APIqui vous permet d'envoyer et de recevoir un grand nombre de SMS partout dans le monde. Une fois que vous avez obtenu votre numéro de téléphone virtuel, vous pouvez utiliser l'API pour gérer les messages sortants ("envoi") et les messages entrants ("réception").
Voici un aperçu de ce que nous sommes en train de construire :

Le code de ce tutoriel se trouve sur GitHub.
Conditions préalables
Avant de commencer, assurez-vous d'avoir
Node.js installé sur votre machine
ngrok pour rendre le code de notre machine locale accessible au monde extérieur
La version bêta de la Nexmo CLI:
npm install -g nexmo-cli@beta
Générer une nouvelle application Nuxt.js
Pour faciliter le démarrage, l'équipe de Nuxt.js a créé un outil CLI appelé create-nuxt-appqui permet de créer un nouveau projet et de sélectionner tous les modules qu'il est possible d'intégrer dans une application Nuxt.js. J'ai utilisé cet outil pour générer un nouveau projet, appelé nexmo-nuxt-sms.
$ npx create-nuxt-app nexmo-nuxt-smsJ'ai choisi npm comme gestionnaire de paquets. J'ai trouvé un bon Tailwind CSS de Tailwind que je voulais utiliser, j'ai donc choisi Tailwind comme framework d'interface utilisateur. Pour un framework serveur personnalisé, j'ai choisi d'utiliser none, la recommandation de Nuxt.js. Pour les modules, j'ai choisi axios pour les requêtes HTTP, et dotenv ainsi je peux utiliser un fichier .env pour mes variables de construction. Je suis un fan de ESlintet je l'ai donc choisi comme outil de linting. Je n'écrirai pas de tests pour ce billet de blog, j'ai donc choisi de ne pas ajouter de cadre de test. J'ai choisi Universal comme mode de rendu parce que cela me permet d'avoir un rendu côté serveur dès le départ. Comme mon éditeur de choix pour Vue.js est VS Code, j'ai choisi jsconfig.json comme outil de développement supplémentaire pour la dernière étape du processus d'échafaudage.

Une fois l'échafaudage terminé, j'ai changé de répertoire vers mon nouveau projet, et j'ai exécuté le projet en utilisant npm run dev. Cela démarrera les processus client et serveur et les rendra disponibles à l'adresse http://localhost:3000. Il les rechargera également à chaud à chaque fois que j'apporterai un changement, de sorte que je puisse le voir en direct sans avoir à redémarrer les processus.
$ cd nexmo-nuxt-sms
$ npm run devLa commande a généré toute une structure de répertoires, qui est la pierre angulaire de Nuxt.js. Dans le dossier racine, il y a nuxt.config.jsqui est le fichier de configuration de Nuxt.js. Nous allons le mettre à jour pour ajouter serverMiddleware. L'intergiciel serveur fonctionne en spécifiant des routes et des fichiers JavaScript associés à exécuter lorsque l'on accède à ces routes. Nous allons créer deux routes, /api/send et /api/receivepour gérer l'envoi et la réception de SMS par leur intermédiaire. Au bas de la page, ajoutez une propriété pour serverMiddleware:
export default {
...
},
serverMiddleware: [
{ path: '/api/send', handler: '~/api/send-sms.js' },
{ path: '/api/receive', handler: '~/api/receive-sms.js' }
]
} Envoi d'un message SMS
Nous avons demandé à Nuxt.js d'utiliser l'option ~/api/send-sms.js lorsqu'une requête sur /api/send est faite, mais nous n'avons pas encore créé le fichier. Nous allons donc créer un dossier api et un fichier send-sms.js à l'intérieur.
$ mkdir api
$ touch send-sms.jsPour envoyer des messages SMS avec l'API SMS Nexmo, nous utiliserons l'API nexmo Node.js SDK. Nous devons d'abord l'installer :
$ npm install nexmoNous allons l'utiliser dans le fichier, et nous devons l'exiger, puis l'instancier avec votre clé d'API Nexmo et votre secret. Vous pouvez les trouver dans votre tableau de bord Nexmo. Mettre à jour send-sms.js pour ressembler à ceci :
require('dotenv').config()
const Nexmo = require('nexmo')
const nexmo = new Nexmo({
apiKey: process.env.NEXMO_API_KEY,
apiSecret: process.env.NEXMO_API_SECRET
})
export default function (req, res) {
console.log(req.method, req.url)
}Nous utilisons dotenv pour récupérer la clé et le secret de l'API dans le fichier .env au lieu de les ajouter directement dans le code. Nous devrons donc mettre à jour le fichier .env à la racine de votre projet généré avec les valeurs de NEXMO_API_KEY et NEXMO_API_SECRET.
NEXMO_API_KEY=aabbcc0
NEXMO_API_SECRET=s3cRet$tuffLe fichier exporte une fonction par défaut qui contient les objets Node.js de requête et de réponse par défaut. Parce qu'ils sont là, et que je n'ai pas voulu ajouter la dépendance supplémentaire de expressnous allons les utiliser pour créer un serveur HTTP Node.js classique. Mettons à jour l'objet export dans le fichier send-sms.js pour qu'il ressemble à ceci :
export default function (req, res, next) {
console.log(req.method, req.url)
if (req.method === 'GET') {
const url = new URL(req.url, `http://${req.headers.host}`)
nexmo.message.sendSms(
process.env.FROM_NUMBER,
url.searchParams.get('number'),
url.searchParams.get('text'),
(err, responseData) => {
let message
if (err) {
message = JSON.stringify(err)
} else if (responseData.messages[0].status === '0') {
message = 'Message sent successfully.'
} else {
message = `Message failed with error: ${responseData.messages[0]['error-text']}`
}
res
.writeHead(200, {
'Content-Length': Buffer.byteLength(message),
'Content-Type': 'text/plain'
})
.end(message)
}
)
} else {
res.statusCode = 200
res.end()
}
}
Je vérifie si la demande est un GET ici, puis j'utilise la fonction "Envoyer un SMS" pour envoyer un SMS. La méthode nexmo.message.sendSms prend un élément from, to et text pour déterminer le destinataire, l'expéditeur et le contenu du SMS. Elle prend également une méthode callback qui sera exécutée une fois l'appel API terminé. Je prends le paramètre from du fichier .env qui sera un numéro de téléphone Numbers. Les champs to et text proviennent des paramètres de la requête HTTP entrante.
Ma fonction callback est une fonction anonyme, et je vérifie d'abord s'il y a une erreur dans la requête. Si c'est le cas, je transforme l'objet error en String et je le passe au message de réponse. S'il n'y a pas d'erreur, je vais regarder le statut du message dans les données de la réponse. Un statut de 0 signifie que le SMS a été envoyé avec succès, et je mets donc à jour le message de réponse. Si le statut n'est pas 0cela signifie qu'il y a eu une erreur dans l'acheminement du SMS depuis l'API Nexmo vers un téléphone, via les réseaux des opérateurs de télécommunications. Je mettrai à jour le message avec le texte d'erreur approprié.
Comme il s'agit d'un serveur Node.js, je dois écrire explicitement l'en-tête de la requête avec un 200 le statut Content-Length et Content-Type du message, avant de pouvoir envoyer le message sur la requête.
Il existe également une solution de repli pour toutes les demandes autres que GET, qui renvoie une réponse vide. 200 OK vide.
Acheter un Numbers Nexmo
Vous avez probablement remarqué que j'ai utilisé process.env.FROM_NUMBER comme identifiant de l'expéditeur, ce qui signifie que Nuxt.js va le chercher dans le fichier .env dans le fichier Avant de pouvoir l'ajouter, nous devons acheter un numéro de téléphone compatible avec les SMS dans le Nexmo Dashboard.
Nous pouvons également acheter un numéro par l'intermédiaire de l'interface de commande Nexmo, et c'est ce que je vais faire. Si vous n'avez jamais utilisé la CLI Nexmo, vous devez la configurer avec votre clé API Nexmo et votre secret avant de pouvoir l'utiliser.
$ nexmo setup NEXMO_API_KEY NEXMO_API_SECRETNous utiliserons la commande number:search pour rechercher un numéro disponible avant de l'acheter. La commande accepte en entrée un code de pays à deux lettres (j'ai utilisé GB pour les numéros britanniques), et nous pouvons spécifier quelques indicateurs pour réduire la liste des numéros de téléphone disponibles. J'utilise --sms pour marquer les numéros qui acceptent les SMS, --size=5 pour limiter la taille de la liste retournée, et --verbose pour renvoyer un tableau joliment formaté contenant des informations supplémentaires sur les numéros de téléphone disponibles.
$ nexmo number:search GB --sms --size=5 --verboseLa réponse que j'ai reçue ressemblait un peu à ceci :
Item 1-5 of 7633
msisdn | country | cost | type | features
------------------------------------------------------
447451272708 | GB | 1.25 | mobile-lvn | VOICE,SMS
447451272710 | GB | 1.25 | mobile-lvn | VOICE,SMS
447451272713 | GB | 1.25 | mobile-lvn | VOICE,SMS
447451272714 | GB | 1.25 | mobile-lvn | VOICE,SMS
447451272719 | GB | 1.25 | mobile-lvn | VOICE,SMSJ'ai choisi le premier numéro de la réponse, alors allons-y et achetons ce numéro sur la plateforme Nexmo.
$ nexmo number:buy 447451272708 --confirmMaintenant que vous possédez ce numéro de téléphone, ajoutons-le au fichier .env fichier.
NEXMO_API_KEY=aabbcc0
NEXMO_API_SECRET=s3cRet$tuff
FROM_NUMBER=447451272708Nous pouvons tester le point d'accès que nous avons créé, pour nous assurer qu'il fonctionne. Comme il s'agit d'une GET nous n'avons pas besoin d'un outil supplémentaire comme Postman, nous pouvons utiliser l'URL directement dans le navigateur. Si vous chargez une URL avec une requête comme http://localhost:3000/api/send?text=hello&number=YOUR_PHONE_NUMBERen remplaçant YOUR_PHONE_NUMBER par votre numéro de téléphone portable, vous devriez recevoir un SMS avec le texte hello sur votre téléphone.

Réception d'un SMS
Lorsqu'un numéro de téléphone Nexmo reçoit un SMS, Nexmo transmet ce message à un Webhook que vous avez spécifié dans le tableau de bord Nexmo. Nous allons devoir créer le point de terminaison /api/receive l'exposer publiquement à Nexmo via ngrok, puis le lier dans le Nexmo Dashboard.
Nous avons déjà enregistré le point de terminaison /api/receive avec le middleware serveur Nuxt.js, allons-y et créons le fichier pour le gérer. Dans le répertoire api créez un fichier receive-sms.js dans le répertoire.
$ cd api
$ touch receive-sms.jsCe fichier fonctionne de la même manière que le fichier send-sms.js que nous avons créé plus tôt, il a la même syntaxe export default function et reçoit une requête Node.js et un objet de réponse. Allons-y et remplissons le fichier receive-sms.js avec un gestionnaire de requête POST, qui construit le corps de la requête à partir de morceaux, puis l'enregistre dans la console.
export default function (req, res) {
console.log(req.method, req.url)
if (req.method === 'POST') {
const body = []
req.on('data', (chunk) => {
body.push(chunk)
})
req.on('end', () => {
const sms = JSON.parse(body)
console.log(sms)
})
}
res.statusCode = 200
res.end()
}
Je vérifie si la requête entrante est une requête POST puis j'écoute les morceaux de données de la requête, en les ajoutant à un body tableau de données. Lorsque la requête se termine, j'analyse le fichier body en JSON, et l'enregistre dans la console. Ce sera en fait les données SMS provenant de Nexmo. Nexmo attend un 200 OK sur la requête, donc je réponds avec ça.
Notre point de terminaison Webhook se trouve maintenant sur localhost, mais nous devons l'exposer à l'internet, afin que Nexmo puisse y accéder. Nous allons utiliser ngrok pour cela.
Exécuter ngrok
Si vous n'avez pas encore utilisé ngrok, il y a un article de blog qui explique comment l'utiliser. Si vous êtes familier avec ngrok, lancez-le avec http sur le port 3000.
$ ngrok http 3000Une fois que ngrok s'est exécuté, il vous donnera une URL aléatoire, que nous utiliserons comme base pour notre Webhook plus tard. La mienne ressemble à ceci : http://3dea3250.ngrok.io.
Lier le Webhook à Nexmo
Pour configurer l'URL du webhook, allez sur la petite icône en forme d'engrenage à côté de vos numéros de téléphone dans le tableau de bord Nexmo et remplissez le champ "Inbound Webhook URL" avec YOUR_NGROK_URL/api/receive.
Ou nous pouvons utiliser le CLI de Numbers pour relier le numéro de téléphone Nexmo que vous avez acheté plus tôt avec l'URL Webhook de ngrok :
nexmo link:sms 447451272708 http://YOUR_NGROK_URL.ngrok.io/api/receiveVous pouvez maintenant envoyer un SMS depuis votre téléphone vers votre numéro Nexmo, et vous devriez le voir enregistré dans le terminal où tourne votre application Nuxt.js.

Créer une interface utilisateur Vue.js
Nous avons créé la fonctionnalité serveur pour envoyer et recevoir des SMS, il est temps de créer une interface utilisateur pour interagir avec cette fonctionnalité depuis le navigateur.
Tout d'abord, nettoyons l'interface utilisateur existante que Nuxt.js a créée pour nous. Remplacez le contenu du fichier /layouts/default.vue par :
<template>
<div>
<nuxt />
</div>
</template>
<style>
html {
background-color: #4299e1;
}
</style>
J'utilise un modèle de terminal Mac provenant de tailwindcomponents.comNous allons donc remplacer le contenu de la balise <template> dans le fichier /pages/index.vue par la nouvelle interface utilisateur :
<template>
<div class="w-1/2 mx-auto py-20">
<div class="w-full shadow-2xl subpixel-antialiased rounded h-64 bg-black border-black mx-auto">
<div
id="headerTerminal"
class="flex items-center h-6 rounded-t bg-gray-100 border-b border-gray-500 text-center text-black"
>
<div
id="closebtn"
class="flex ml-2 items-center text-center border-red-900 bg-red-500 shadow-inner rounded-full w-3 h-3"
/>
<div
id="minbtn"
class="ml-2 border-yellow-900 bg-yellow-500 shadow-inner rounded-full w-3 h-3"
/>
<div
id="maxbtn"
class="ml-2 border-green-900 bg-green-500 shadow-inner rounded-full w-3 h-3"
/>
<div id="terminaltitle" class="mx-auto pr-16">
<p class="text-center text-sm">
<logo />Terminal
<logo />
</p>
</div>
</div>
<div id="console" class="pl-1 pt-1 h-auto text-green-500 font-mono text-xs bg-black">
<p class="pb-1">
Last login: {{ new Date().toUTCString() }} on ttys002
</p>
<p v-for="counter in counters" :key="counter.id" class="pb-1">
<span class="text-red-600">@lakatos88</span>
<span class="text-yellow-600 mx-1">></span>
<span class="text-blue-600">~/nexmo/nexmo-nuxt-sms</span>
<span class="text-red-600 mx-1">$</span>
<span v-if="!counter.message" class="blink" contenteditable="true" @click.once="stopBlinking" @keydown.enter.once="runCommand">_</span>
<span v-if="counter.message">{{ counter.message }}</span>
</p>
</div>
</div>
</div>
</template>J'ai légèrement modifié le modèle pour que les couleurs correspondent à ma configuration de terminal et j'ai mis à jour les informations sur l'utilisateur pour qu'elles correspondent également à mon terminal.
Les modifications que j'ai effectuées se sont produites dans la console alors jetons-y un coup d'œil. J'utilise {{ new Date().toUTCString() }} pour obtenir la date actuelle et l'afficher à l'écran.
J'utilise ensuite la directive Vue.js v-for pour parcourir en boucle un tableau counters et afficher soit un underscore clignotant, soit un message dans la fenêtre du terminal, pour chaque entrée du tableau de compteurs. L'underscore clignotant est doté d'un drapeau contenteditable, ce qui signifie que vous pouvez en modifier le contenu dans le navigateur. J'utilise la directive @click pour exécuter une fonction JavaScript stopBlinking la première fois qu'un utilisateur clique dessus, et l'empêcher de clignoter. La même balise HTML contient également une directive @keydown.enter pour exécuter une fonction runCommand la première fois qu'un utilisateur appuie sur la touche Entrée, envoyant ainsi la commande au terminal.
Nous devons créer le tableau initial counters dans la structure de données Vue.js, et créer les méthodes pour stopBlinking et runCommand. Remplaçons la balise <script> dans le même fichier :
<script>
import Logo from '~/components/Logo.vue'
export default {
components: {
Logo
},
data () {
return {
counters: [{ id: 0 }]
}
},
mounted () {
},
methods: {
stopBlinking (event) {
event.target.classList.remove('blink')
event.target.textContent = '\u00A0'
},
async runCommand (event) {
const splitCommand = event.target.textContent.trim().split(' ')
event.target.contentEditable = false
if (splitCommand.length > 3 && splitCommand[0] === 'nexmo' && splitCommand[1] === 'sms') {
const sms = await this.$axios.$get(`/api/send?text=${splitCommand.slice(3).join(' ')}&number=${splitCommand[2]}`)
this.counters.push({ id: this.counters.length, message: sms })
} else {
this.counters.push({ id: this.counters.length, message: `Unrecognized command "${splitCommand[0]}".` })
}
this.counters.push({ id: this.counters.length })
}
}
}
</script>La méthode runCommand est asynchrone, et elle empêche l'élément HTML de devenir contentEditable. Elle divise également la commande du terminal en 4 parties, le nom de la commande, l'argument, le numéro de téléphone et le message texte. La méthode vérifie s'il y a plus de 3 parties dans la commande et si la première est nexmo et que la seconde est sms. Si c'est le cas, elle envoie une requête HTTP GET en utilisant axios au point d'accès /api/send que nous avons créé plus tôt, en transmettant le texte et le numéro de la commande. Il utilise ensuite le message qu'il reçoit en retour pour l'afficher sur l'interface utilisateur.
Si la commande n'est pas nexmo sms number textil affiche une erreur générique dans l'interface utilisateur. Une fois que c'est fait, il ajoute une nouvelle ligne avec un trait de soulignement clignotant dans l'interface utilisateur, en attendant la prochaine commande.
J'ai également remplacé le contenu de la balise <style> pour positionner les logos Nuxt.js en haut de la fenêtre du terminal, et créer l'animation clignotante pour le trait de soulignement.
<style>
.NuxtLogo {
width: 10px;
height: 10px;
position: relative;
margin: 0 10px;
bottom: 2px;
display: inline-block;
}
.blink {
animation-duration: 1s;
animation-name: blink;
animation-iteration-count: infinite;
}
@keyframes blink {
from {
opacity: 1;
}
50% {
opacity: 0;
}
to {
opacity: 1;
}
}
</style>Cela vous permettra d'envoyer des SMS à partir de l'interface utilisateur Vue.js, mais pas encore de recevoir des SMS. Parce que le Webhook de réception de SMS est déclenché par Nexmo, nous ne pouvons pas savoir à partir du code de l'interface utilisateur quand il y a un nouveau SMS pour le demander. Nous devrons ajouter une sorte de mécanisme de sondage.
Ajouter les WebSockets
Je ne suis pas fan des longues interrogations, donc j'ai décidé de construire une paire client/serveur WebSocket pour cela. Pour le serveur, j'utilise le paquetage ws npm packageNous allons donc devoir l'installer :
$ npm install wsPour construire le serveur WebSocket, éditons le fichier /api/receive-sms.js pour y créer un serveur WebSocket. Je remplace également la partie qui enregistre le SMS dans la console, pour l'envoyer sur la WebSocket à la place.
const WebSocket = require('ws')
let websocket = {}
const wss = new WebSocket.Server({ port: 3001 })
wss.on('connection', (ws) => {
websocket = ws
})
export default function (req, res, next) {
console.log(req.method, req.url)
if (req.method === 'POST') {
const body = []
req.on('data', (chunk) => {
body.push(chunk)
})
req.on('end', () => {
const sms = JSON.parse(body)
websocket.send(`Message from ${sms.msisdn}: ${sms.text}`)
})
}
res.statusCode = 200
res.end()
}
Le serveur démarre sur le port 3001et envoie le SMS dès qu'il a fini de construire à partir de la requête. Nous devrons également ajouter un client WebSocket à l'interface utilisateur pour recevoir le message et l'afficher dans l'interface. Mettons à jour le fichier /pages/index.vue et plus particulièrement la méthode mounted() pour créer un client WebSocket dès que le composant Vue.js a terminé son montage.
mounted () {
console.log(process.env.WS_URL)
const ws = new WebSocket(process.env.WS_URL)
ws.onmessage = (event) => {
this.counters[this.counters.length - 1].message = event.data
this.counters.push({ id: this.counters.length })
}
},
Le client WebSocket se connecte au serveur process.env.WS_URLet se met à l'écoute des messages. Lorsqu'il y a un nouveau message sur la WebSocket, il met à jour la dernière commande à l'écran avec les données d'événement reçues du serveur, c'est-à-dire le message SMS. Il ajoute également une nouvelle ligne dans l'interface utilisateur, avec un trait de soulignement clignotant.
Vous avez remarqué que nous utilisons l'élément process.env.WS_URLnous devons donc l'ajouter à notre fichier .env à notre fichier.
WS_URL=ws://localhost:3001Comme l'interface utilisateur Vue.js a besoin de connaître le fichier d'environnement, nous devons ajouter une entrée à ce sujet dans le fichier de configuration de Nuxt.js, nuxt.config.js.
env: {
wsUrl: process.env.WS_URL || 'ws://localhost:3001'
}, Essayez-le
Vous pouvez charger http://localhost:3000/ dans votre navigateur, cliquez sur le trait de soulignement clignotant et tapez nexmo sms YOUR_PHONE_NUMBER hello. Après avoir appuyé sur la touche Entrée du clavier, le SMS devrait être envoyé à votre téléphone. Si vous répondez à ce SMS, vous le verrez également apparaître dans votre navigateur.

J'espère que cela a fonctionné et que vous venez d'apprendre comment envoyer et recevoir des SMS avec les API Nexmo et Nuxt.js.
Partager:
Alex Lakatos est un défenseur des développeurs JavaScript pour Nexmo. Pendant son temps libre, il est bénévole chez Mozilla en tant que Tech Speaker et Reps Mentor. Développeur JavaScript travaillant sur le web ouvert, il en repousse les limites tous les jours. Lorsqu'il ne programme pas à Londres, il aime parcourir le monde, il est donc probable que vous le croisiez dans un salon d'aéroport.