
Compartir:
Lorna es ingeniera de software con un incurable hábito bloguero. Intenta domar las palabras y el código a partes iguales.
SMS sin servidor con Nexmo e IBM
Tiempo de lectura: 9 minutos
Comunicarse con los usuarios a través de SMS es una forma excelente de interactuar con la gente de manera informal. Tanto si quieres automatizar la respuesta a tus preguntas más frecuentes, como si quieres organizar un concurso o conectar con tus usuarios para algo completamente diferente, los SMS son una excelente opción. En este post, veremos un ejemplo divertido y trivial mientras analizamos en detalle cómo lograr estas tareas. Construiremos un sistema que responda a un SMS entrante con una "galleta de la fortuna". Estos son los saludos utilizados en la función "mensaje del día" en las antiguas estaciones de trabajo *nix, piensa en ello como una versión más geek de los adorables mensajes de carga que ves en Slack.
Serverless es una opción ideal para una tarea como esta, en la que cada mensaje entrante es independiente de todos los demás. Las plataformas sin servidor como IBM Cloud Functions (utilizadas en este ejemplo), Amazon Lambda o Azure Functions todas escalan horizontalmente cuando están bajo carga. La gran ventaja reside en el modelo de precios: las plataformas sin servidor solo cobran por el tiempo que la función está en ejecución, por lo que no es necesario pagar una cuota fija por un servidor en funcionamiento. Además, la implementación de una función requiere menos pasos que la configuración de un servidor, lo que agiliza la puesta en marcha.
Antes de empezar
Hay algunos requisitos previos que necesitarás antes de seguir este tutorial:
Una cuenta de IBM Cloud Account para que podamos desplegar nuestra función sin servidor (es gratis)
La herramienta de línea de comandos
bxherramienta de línea de comandos para IBM Cloud ywskCloud Functions plugin - utilice las instrucciones de instalación. Inicie sesión y configure su espacio de trabajo de destino antes de continuar.
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.
Paso 1: Crear y desplegar una función sin servidor
Una función sin servidor es una función (esta es JavaScript; IBM Cloud admite muchos otros lenguajes de programación) desplegada en la nube. La función se ejecuta en respuesta a un evento, y uno de los eventos comunes es una solicitud web. Al crear una única función y desplegarla, podemos estar preparados rápidamente para recibir un SMS de un usuario.
Obtenga la función desde este enlace a una versión específica en GitHub. Deberías tener un contenido parecido a esta versión abreviada:
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. "
];
}Guarde el contenido en index.js y echa un vistazo a la función main() en la parte superior. Son unas pocas líneas de código para agarrar ese gran array de galletas de la fortuna (de Ubuntu fortune-mod paquetenada menos) y elegir una al azar, antes de registrarla y devolverla. Si quieres editar la función getCookies() para ofrecer galletas de la suerte alternativas, ¡adelante!
En la programación sin servidor, las "funciones" suelen denominarse "acciones".
Para llevar esa acción a la nube, primero crearemos un paquete en el que colocarla. Un paquete ayuda a mantener las acciones juntas y les permite compartir parámetros.
Utilizando el comando bx que configuró anteriormente, cree el paquete utilizando este comando:
bx wsk package create sms-fortuneUsted debe ver algunos "OK" feliz de salida, y con el paquete en su lugar, podemos seguir adelante y desplegar la función también. Aquí está el comando para eso:
bx wsk action update sms-fortune/incoming --kind nodejs:8 --web raw index.jsDe nuevo, mira a ver el "OK" que indica que el comando se ha completado con éxito. Hemos desplegado una función. Se llama incoming (ya que gestiona los SMS entrantes) y existe dentro del paquete sms-fortune paquete. Los otros argumentos aquí son --kind para decir qué versión de JS utilizar y --web raw para permitirnos inmediatamente hacer una petición web a esta acción.
Si se llama a
updateen una acción que no existe activacreatepor lo que este comando funciona independientemente del estado actual. Aún mejor: sigue funcionando si desea editarindex.jsy desplegar de nuevo.
Entonces, ¿a qué estamos esperando? Averigüemos la URL de nuestra acción y solicitémosla. Aquí está el comando para descubrir qué URL tiene la acción:
bx wsk action get --url sms-fortune/incomingCopie la URL de la respuesta al comando anterior. Puede seguir adelante y utilizar cURL, tu navegador o cualquier otro cliente HTTP para hacer una petición a esa URL. Si todo ha ido según lo previsto, la respuesta debería incluir un comentario ingenioso. Si lo desea, repita la petición varias veces para obtener más ocurrencias.
Paso 2: Gestionar un SMS entrante
Ya tenemos configurado el punto final al que debe apuntar nuestro webhook, así que vamos a conectarlo. También puedes consultar nuestro bloque de construcción para la recepción de SMS como referencia.
En primer lugar, necesitamos una manera de ver cuando Nexmo llama a nuestra función. Hasta ahora la hemos solicitado directamente, pero al recibir un SMS, no habrá una respuesta que podamos ver. En su lugar, abre una nueva ventana de terminal y empieza a ver los registros de tus acciones con el siguiente comando:
bx wsk activation pollDeja esto ejecutándose (me gusta ponerlo en mi segundo monitor si tengo uno) y usa la misma petición curl/browser de antes para que puedas ver lo que ocurre cuando se ejecuta la función. Como puedes notar, no es tiempo real, y a veces necesitamos esperar unos segundos para que aparezcan los logs.
Ahora que podemos saber si la función se está ejecutando correctamente, vamos a intentar convertirla en nuestro endpoint para SMS. Visita tu Numbers en el panel de control de Nexmo y haga clic en "Editar" en el número a utilizar, y en "SMS" pegue la URL de la acción en el campo "Webhook URL". No olvide hacer clic en "Actualizar".
Ya está todo listo: envíe un SMS a su número entrante y observe los registros para ver cómo se ejecuta la acción.
Paso 3: Descubrir el número al que hay que responder
En este punto, hemos desplegado una acción sin servidor y la hemos configurado como el punto final para el webhook de SMS entrante. Para poder responder al usuario que envió el SMS, necesitamos inspeccionar los datos que llegan con el webhook para ver quién lo envió.
Las acciones de IBM Cloud Functions (y de hecho de Apache OpenWhisk en general) aceptan un único parámetro, que en este ejemplo se llama params. Si añades console.log(params) a tu código, podrás ver todo lo que recibimos cuando se ejecuta la función. Comprobación de la documentación de la API para SMS entrantespodemos ver que el número de teléfono al que queremos responder llega como un parámetro de consulta llamado msisdn.
Para capturar el número de teléfono, podemos añadir una sección a la función main() (justo antes de retornar) para recoger las variables entrantes en un array llamado query_data para poder utilizarlas:
// 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"]);
El código anterior no es bonito, y debes tener mucho cuidado con lo que ocurre si estas variables no están presentes, pero si añades esta sección a index.js y luego volver a implementar utilizando el mismo comando que antes:
bx wsk action update sms-fortune/incoming --kind nodejs:8 --web raw index.jsMientras sigues viendo esos registros, vuelve a enviar un SMS a tu número entrante. Esta vez, deberías ver la línea Destination: y el número de teléfono desde el que enviaste el mensaje. Ya tenemos la información necesaria para poder responder al mensaje.
Paso 4: Establecer algunos secretos
Podemos recibir los SMS entrantes por webhook porque hemos tenido que configurar la URL a la que se envían los datos accediendo a nuestra Account. Sin embargo, antes de poder enviar el SMS de respuesta, necesitamos poder autenticarnos.
Para esta sección, necesita tener a mano la clave y el secreto de la API, que aparecen en la parte superior del panel de control de Nexmo. panel de Nexmo. Para seguir las mejores prácticas para el manejo de secretos como estos, vamos a evitar escribir estos valores a los archivos en absoluto y en su lugar vamos a utilizar variables de entorno. La idea es que establezcamos las variables para el entorno actual; si abres una nueva ventana de terminal o reinicias tu ordenador, no persistirán, y tendrás que establecerlas de nuevo.
Las variables a establecer son NEXMO_API_KEY y NEXMO_API_SECRETy los comandos tienen el siguiente aspecto (sustituya los valores después de los signos = signos);
export NEXMO_API_KEY=awesomeKey
export NEXMO_API_SECRET=awesomeSecretAhora que nuestro entorno actual conoce los secretos, podemos utilizarlos en nuestros comandos.
A continuación, vamos a enseñar estos secretos al paquete que hemos creado antes. Lo haremos actualizándolo y configurando los parámetros a medida que lo hacemos. Aquí está el comando:
bx wsk package update sms-fortune -p apikey $NEXMO_API_KEY -p apisecret $NEXMO_API_SECRETEstos parámetros no están en nuestro código, pero están en el paquete, por lo que están disponibles para nuestra acción ya que está en el mismo paquete. Si añades el comando console.log(params) a tu acción ahora, luego la despliegas y observas los registros mientras la ejecutas, verás estos valores.
Ya tenemos toda la información que necesitamos para enviar el SMS de respuesta: la cookie, el número de teléfono y nuestras credenciales de la API.
Paso 5: Enviar galleta de la suerte por SMS
Para devolver un SMS al mismo número que nos envió un mensaje en primer lugar, tendremos que hacer una llamada a la API; esta sección se ocupa de esta última pieza del rompecabezas. También puedes encontrar nuestro módulo de envío de SMS como referencia.
Una cosa a tener en cuenta con JavaScript sin servidor es que no tiene un bucle de eventos de la misma forma a la que estamos acostumbrados. Como resultado, todas las operaciones asíncronas como las consultas a la base de datos o la petición a la API que estamos a punto de hacer en nuestro código necesitan ser prometidas o manejadas usando async/await. Este ejemplo utiliza la librería request-promise para habilitar esta llamada a la API.
La adición de bibliotecas crea un poco más de complejidad que la que hemos tenido hasta ahora con todo en un archivo, pero no es nada que podamos manejar. index.js archivo, pero no es nada que no podamos manejar.
Para empezar, necesitaremos un package.json archivo. El mío tiene este aspecto:
{
"name": "sms-fortunes",
"description": "Simple demo for getting a fortune cookie by SMS",
"dependencies": {
"request": "^2.85.0",
"request-promise": "^4.2.2"
}
}También puede copiar este archivo de GitHub. Edítelo si lo desea (probablemente no lo necesite) y luego instale estas dependencias con npm:
npm installCuando desplegamos nuestra acción, necesitamos incluir las librerías así como el archivo index.js archivo. Para lograr esto, podemos comprimir todo lo que necesitamos en un archivo y desplegarlo. Dado que este es un proceso de varios pasos (de acuerdo, dos pasos, pero aún así) me gusta crear un script para manejarlo. ¡De esta manera, nunca me olvido de volver a crear el archivo zip, o se olvide de empujarlo a la nube, o cualquier otra cosa que hay que olvidar!
Aquí está mi deploy.sh archivo (y de nuevo se puede encontrar el original en 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.zipEste script elimina el archivo zip antiguo, añade nuestro archivo y los requisitos a uno nuevo y, a continuación, ejecuta el mismo código de actualización de acciones que estábamos utilizando antes, pero suministrando el archivo zip en su lugar. Actualicemos index.js para usar nuestras nuevas bibliotecas y luego usar este script o los comandos mostrados arriba para desplegar la acción.
Para utilizarlo
deploy.shnecesitas hacerlo ejecutable para tu usuario para que puedas ejecutarlo
Consigue la versión actualizada de index.js de este recurso en GitHub y ponla en tu proyecto. He incluido una versión abreviada de este código a continuación:
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. "
];
}
Junta todo esto, ciérralo, despliégalo, sigue vigilando los registros -por si surge algún imprevisto- y envía un SMS a tu número entrante. Y ¡listo! Una galleta de la fortuna en respuesta :)
Conclusión
Los SMS son fáciles para los usuarios, y espero que, con este ejemplo, hayas visto que para los desarrolladores también es bastante factible. El código aquí recibe SMS e identifica al usuario, luego envía un SMS de vuelta al mismo usuario. Utiliza un backend sin servidor porque es barato de ejecutar y fácil de empezar. Este ejemplo devolvió un contenido trivial, pero seguro que te da ideas para tus aplicaciones. Por ejemplo, se podría analizar el mensaje entrante y dar diferentes respuestas basadas en él, o hacer una llamada a una API para obtener contenido en lugar de tenerlo hardcoded como lo hicimos en este post para mantener las cosas simples. El cielo es el límite, ¡y nos encantaría saber lo que haces!
Próximos pasos
Si esto ha despertado tu interés por hacer algo más con los SMS, aquí tienes algunas ideas que puedes probar:
Un debate sobre diferentes tipos de mensajería y bots: https://developer.vonage.com/en/blog/ai-bot-messaging-push-notifications-sms-dr/
Esta excelente introducción a las llamadas por SMS y Voice https://developer.vonage.com/en/blog/sms-voice-programmable-communications-dr/
Una aplicación de ejemplo de chat de grupo SMS (en PHP) https://developer.vonage.com/en/blog/sms-voice-programmable-communications-dr/
Un post de alto nivel sobre cómo los SMS pueden ayudarte a interactuar con tus usuarios: https://developer.vonage.com/en/blog/top-5-ways-to-use-sms-to-increase-mobile-user-acquisition-and-engagement/
