
Compartilhar:
Lorna é engenheira de software e tem um vício incurável por escrever em blogs. Ela tenta domar as palavras e o código na mesma medida.
Mensagens SMS “Fortune Cookies” sem servidor com a Nexmo e a IBM
Tempo de leitura: 10 minutos
A comunicação com os usuários por SMS é uma excelente maneira de interagir com as pessoas de forma informal. Seja para automatizar respostas às perguntas mais frequentes, realizar um concurso ou interagir com seus usuários sobre algo completamente diferente, o SMS é uma excelente opção. Nesta postagem, vamos analisar um exemplo divertido e simples enquanto examinamos em detalhes como realizar essas tarefas. Vamos criar um sistema que responda a um SMS recebido com um “biscoito da sorte”. Essas são as saudações usadas no recurso “mensagem do dia” em estações de trabalho *nix antigas; pense nisso como uma versão mais geek das adoráveis mensagens de carregamento que você vê no Slack.
A arquitetura sem servidor é a escolha ideal para uma tarefa como essa, em que cada mensagem recebida é independente de todas as outras. Plataformas sem servidor como IBM Cloud Functions (usada neste exemplo), Amazon Lambda ou Azure Functions todos escalam horizontalmente quando sob carga. A grande vantagem está no modelo de preços; as plataformas sem servidor cobram apenas pelo tempo em que sua função está em execução, portanto, não há necessidade de pagar uma taxa fixa por um servidor em funcionamento. Como bônus, há menos etapas envolvidas na implantação de uma função do que na configuração de um servidor, o que agiliza o início do trabalho.
Antes de começar
Existem alguns pré-requisitos que você precisará cumprir antes de seguir este tutorial:
Uma Account no IBM Cloud para que possamos implantar nossa função sem servidor (é grátis)
A
bxferramenta de linha de comando para o IBM Cloud ewskplug-in do Cloud Functions — use as instruções de configuração. Faça login e defina seu espaço de trabalho de destino antes de prosseguir.
Etapa 1: Criar e implantar uma função sem servidor
Uma função sem servidor é uma função (esta é em JavaScript; o IBM Cloud oferece suporte a várias outras linguagens de programação) implantada na nuvem. A função é executada em resposta a um evento, e um dos eventos mais comuns é uma solicitação da web. Ao criar uma única função e implantá-la, podemos nos preparar rapidamente para receber um SMS de um usuário.
Acesse a função a partir de este link para uma versão específica no GitHub. Você deve ter um conteúdo parecido com esta versão resumida:
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. "
];
}Salve o conteúdo em index.js e dê uma olhadinha na main() função na parte superior. São algumas linhas de código para pegar aquele grande array de biscoitos da sorte (do pacote do Ubuntu fortune-mod pacote, nada menos) e escolher uma aleatoriamente, antes de registrar e retorná-la. Se você quiser editar a getCookies() função para oferecer biscoitos da sorte alternativos, fique à vontade!
Na programação sem servidor, as “funções” costumam ser chamadas de “ações”.
Para migrar essa ação para a nuvem, vamos primeiro criar um pacote para colocá-la nele. Um pacote ajuda a manter as ações agrupadas e permite que elas compartilhem parâmetros.
Usando o bx comando que você configurou anteriormente, crie o pacote usando este comando:
bx wsk package create sms-fortuneVocê deve ver uma mensagem de sucesso com “OK” e, com o pacote instalado, podemos prosseguir e implantar a função também. Aqui está o comando para isso:
bx wsk action update sms-fortune/incoming --kind nodejs:8 --web raw index.jsMais uma vez, verifique se aparece o “OK”, que indica que o comando foi executado com sucesso. Nós implantamos uma função. Ela se chama incoming (já que ela lida com SMS recebidas) e está localizada no sms-fortune pacote. Os outros argumentos aqui servem --kind para indicar qual versão do JS usar e --web raw para nos permitir fazer imediatamente uma solicitação web para essa ação.
Chamar
updateuma ação que não existe acionacreate, portanto, esse comando funciona independentemente do estado atual. Melhor ainda: ele continua funcionando se você quiser editarindex.jse fazer a implantação novamente.
Então, o que estamos esperando? Vamos descobrir a URL da nossa ação e, em seguida, fazer a solicitação. Aqui está o comando para descobrir qual é a URL da ação:
bx wsk action get --url sms-fortune/incomingCopie a URL da resposta ao comando acima. Você pode usar o cURL, seu navegador ou qualquer outro cliente HTTP para fazer uma solicitação a essa URL. Se tudo tiver corrido conforme o planejado, a resposta deve incluir uma observação espirituosa. Repita a solicitação algumas vezes para obter mais observações espirituosas, se desejar.
Etapa 2: Processar uma mensagem SMS recebida
Já estamos com tudo configurado para o endpoint para o qual nosso webhook deve apontar, então vamos em frente e fazer essa conexão. Você também pode conferir nosso bloco de construção para receber SMS como referência.
Em primeiro lugar, precisamos de uma maneira de saber quando o Nexmo chama nossa função. Até agora, temos feito a chamada diretamente, mas, ao receber um SMS, não haverá uma resposta que possamos ver. Em vez disso, abra uma nova janela do terminal e comece a visualizar os logs de suas ações com o seguinte comando:
bx wsk activation pollDeixe isso rodando (eu gosto de exibi-lo no meu segundo monitor, se tiver um) e use a mesma solicitação do `curl` ou do navegador de antes para que você possa ver o que acontece quando a função é executada. Como você deve ter notado, não é em tempo real, e às vezes precisamos esperar alguns segundos até que os logs apareçam.
Agora que sabemos quando a função está sendo executada com sucesso, vamos tentar transformá-la em nosso endpoint para SMS. Acesse seu Numbers no painel do Nexmo, clique em “Editar” no número que deseja usar e, na seção “SMS”, cole a URL da ação no campo “URL do webhook”. Não se esqueça de clicar em “Atualizar”.
Está tudo pronto: envie um SMS para o seu número de destino e acompanhe os registros para ver a ação sendo executada!
Etapa 3: Descubra o número para o qual deve responder
Neste momento, já implantamos uma ação sem servidor e a configuramos como o endpoint a ser usado pelo webhook de SMS recebidas. Para podermos responder ao usuário que enviou a mensagem SMS, precisamos analisar os dados que chegam pelo webhook para identificar quem a enviou.
As ações do IBM Cloud Functions (e, na verdade, do Apache OpenWhisk em geral) aceitam um único parâmetro, que neste exemplo é chamado de params. Se você adicionar console.log(params) ao seu código, você poderá ver tudo o que recebemos quando a função é executada. Verifique a documentação da SMS API sobre SMS recebidas, podemos ver que o número de telefone para o qual queremos responder chega como um parâmetro de consulta chamado msisdn.
Para capturar o número de telefone, podemos adicionar uma seção à main() função (logo antes de retornar) para armazenar as variáveis recebidas em um array chamado query_data para que possamos usá-las:
// 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"]);
O código acima não é muito elegante, e você deve tomar muito cuidado com o que acontece caso essas variáveis não estejam presentes, mas se você adicionar esta seção a index.js e, em seguida, refizer a implantação usando o mesmo comando de antes:
bx wsk action update sms-fortune/incoming --kind nodejs:8 --web raw index.jsEnquanto ainda estiver verificando esses registros, envie um SMS para o seu número de destino novamente. Desta vez, você deverá ver a linha Destination: e o número de telefone de onde você enviou a mensagem aparecerem nos registros. Já temos as informações necessárias para poder responder à mensagem.
Etapa 4: Configurar alguns segredos
Podemos receber o SMS recebido por meio de um webhook, pois tivemos que configurar a URL para a qual os dados são enviados ao fazer login em nosso Account. No entanto, antes de podermos enviar o SMS de resposta, precisamos conseguir nos autenticar.
Para esta seção, você precisará ter sua chave de API e seu segredo de API à mão — eles estão visíveis na parte superior do seu painel do Nexmo. Para seguir as melhores práticas no manuseio de segredos como esses, evitaremos gravar esses valores em arquivos e, em vez disso, usaremos variáveis de ambiente. A ideia é definir as variáveis para o ambiente atual; se você abrir uma nova janela de terminal ou reiniciar o computador, elas não serão mantidas, e você terá que defini-las novamente.
As variáveis a serem definidas são NEXMO_API_KEY e NEXMO_API_SECRET, e os comandos ficam assim (substitua seus valores após os = sinais);
export NEXMO_API_KEY=awesomeKey
export NEXMO_API_SECRET=awesomeSecretAgora que nosso ambiente atual conhece os segredos, podemos usá-los em nossos comandos.
A seguir, vamos aplicar esses segredos ao pacote que criamos anteriormente. Para isso, vamos atualizá-lo e definir os parâmetros à medida que avançamos. Aqui está o comando:
bx wsk package update sms-fortune -p apikey $NEXMO_API_KEY -p apisecret $NEXMO_API_SECRETEsses parâmetros não estão em nosso código, mas estão no pacote; portanto, estão disponíveis para nossa ação, já que ela está no mesmo pacote. Se você adicionar o console.log(params) comando à sua ação agora, depois fizer a implantação e observar os logs enquanto a executa, você verá esses valores.
Agora temos todas as informações necessárias para enviar a mensagem de resposta: o cookie, o número de telefone e nossas credenciais da API.
Etapa 5: Enviar o biscoito da sorte por SMS
Para responder com uma mensagem SMS ao mesmo número que nos enviou a mensagem inicialmente, precisaremos fazer uma chamada à API; esta seção aborda essa última peça do quebra-cabeça. Você também pode conferir nosso módulo para envio de SMS útil como referência.
Um aspecto a se levar em conta no JavaScript sem servidor é que ele não possui um ciclo de eventos da mesma forma que estamos acostumados. Por isso, todas as operações assíncronas, como consultas a bancos de dados ou a solicitação de API que estamos prestes a fazer em nosso código, precisam ser transformadas em promissas ou tratadas usando async/await. Este exemplo usa a request-promise biblioteca para habilitar essa chamada de API com promisificação.
Adicionar bibliotecas traz um pouco mais de complexidade do que tivemos até agora, com tudo em um único index.js arquivo, mas não é nada que não possamos resolver.
Para começar, vamos precisar de um package.json arquivo. O meu tem a seguinte aparência:
{
"name": "sms-fortunes",
"description": "Simple demo for getting a fortune cookie by SMS",
"dependencies": {
"request": "^2.85.0",
"request-promise": "^4.2.2"
}
}Você também pode copiar este arquivo do GitHub. Edite-o se desejar (provavelmente não será necessário) e, em seguida, instale essas dependências com npm:
npm installAo implantar nossa ação, precisamos incluir as bibliotecas, bem como o index.js arquivo. Para isso, podemos compactar tudo o que precisamos em um único arquivo e implantar esse arquivo. Como esse é um processo de várias etapas (tudo bem, são duas etapas, mas mesmo assim), gosto de criar um script para cuidar disso. Dessa forma, nunca esqueço de recriar o arquivo zip, nem de enviá-lo para a nuvem, nem de qualquer outra coisa que possa esquecer!
Aqui está o meu deploy.sh arquivo (e, mais uma vez, você pode encontrar o original no 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 exclui o arquivo zip antigo, adiciona nosso arquivo e os requisitos a um novo e, em seguida, executa o mesmo código de atualização da ação que estávamos usando anteriormente, mas fornecendo o arquivo zip em vez disso. Vamos atualizar index.js para usar nossas novas e maravilhosas bibliotecas e, em seguida, usar este script ou os comandos mostrados acima para implantar a ação.
Para usar
deploy.sh, você precisa torná-lo executável para o seu usuário, para que possa executá-lo
Baixe a versão atualizada do index.js este este recurso no GitHub e coloque-o no seu projeto. Incluí uma versão resumida desse código abaixo:
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. "
];
}
Junte tudo isso, compile, implante, fique de olho nos logs — caso aconteça algo inesperado — e envie um SMS para o seu número de destino. Tada! Um biscoito da sorte engraçadinho como resposta :)
Conclusão
O SMS é fácil para os usuários e, espero que, com este exemplo, você tenha percebido que, para os desenvolvedores, também é bastante viável. O código aqui recebe uma mensagem SMS e identifica o usuário, em seguida, envia uma resposta por SMS para o mesmo usuário. Ele usa um backend sem servidor, pois é barato de operar e fácil de começar a usar. Este exemplo retornou um conteúdo simples, mas tenho certeza de que vai inspirar ideias para suas Applications. Por exemplo, você poderia analisar a mensagem recebida e dar respostas diferentes com base nela, ou fazer uma chamada a uma API para obter o conteúdo, em vez de tê-lo codificado diretamente, como fizemos neste post para manter as coisas simples. O céu é o limite, e adoraríamos saber o que você vai criar!
Próximos passos
Se isso despertou seu interesse em explorar mais as possibilidades do SMS, aqui estão algumas ideias do que você pode experimentar a seguir:
Uma discussão sobre os diferentes tipos de mensagens e bots: https://developer.vonage.com/en/blog/ai-bot-messaging-push-notifications-SMS-dr/
Esta excelente introdução tanto às mensagens SMS quanto às chamadas de Voice https://developer.vonage.com/en/blog/sms-voice-programmable-communications-dr/
Um exemplo de aplicativo de bate-papo em grupo por SMS (em PHP) https://developer.vonage.com/en/blog/sms-voice-programmable-communications-dr/
Um artigo mais aprofundado sobre como o SMS pode ajudar você a interagir com seus usuários: https://developer.vonage.com/en/blog/top-5-ways-to-use-SMS-to-increase-mobile-user-acquisition-and-engagement/