
Compartilhar:
Hui Jing é Developer Advocate na Nexmo. Ela tem um amor imenso por CSS e tipografia e, de modo geral, é apaixonada por tudo que diz respeito à web.
SMS no navegador: uma aventura com WebSockets
Tempo de leitura: 19 minutos
Grande parte do trabalho pesado realizado pela Messages API ocorre no lado do servidor. As mensagens são enviadas, recebidas, processadas e assim por diante, mas, geralmente, toda essa atividade fica oculta aos usuários finais de muitos dos aplicativos que utilizam a API.
Na maioria dos casos, a exibição dessas mensagens ao usuário final é feita pelos respectivos aplicativos. Também existe a opção de exibir essas mensagens em um navegador, mas, para isso, precisaremos de alguma forma de enviar as mensagens do servidor para o navegador. E podemos fazer isso com a ajuda da API WebSockets.
Este é um tutorial bastante extenso que não pressupõe nenhum conhecimento prévio, além de uma compreensão básica de HTML, CSS, JavaScript e Node.js. Fique à vontade para pular qualquer uma das seções se você já souber do que se trata.
Vamos percorrer o processo de criação de um celular “virtual” no navegador, capaz de enviar e receber SMS. Usaremos Glitch para hospedar o aplicativo; portanto, algumas das instruções de configuração são específicas para o Glitch.
O Glitch é um ambiente de desenvolvimento online que permite que os desenvolvedores comecem a criar e implantar seus aplicativos sem o trabalho de configurar um servidor. Todos os aplicativos da plataforma podem ser adaptados e personalizados, tornando-a o lugar perfeito para compartilhar código e entender como as coisas funcionam.
Você também pode usar qualquer ambiente que tenha o Node.js instalado, se preferir. Todas as dependências deste projeto são gerenciadas por meio do npm.
Instalação inicial e configuração
Iniciando um aplicativo Koa.js no Glitch
O Glitch está sempre aprimorando sua interface e seus recursos; portanto, no momento da redação deste artigo, você pode criar uma nova Account no Glitch clicando no botão “Entrar” no canto superior direito da página e fazer login pelo GitHub ou Facebook, ou se cadastrar com seu endereço de e-mail.
Glitch sign in
Depois disso, você pode clicar no Novo Projeto para começar. Há três opções: hello-webpage, hello-express e hello-sqlite. Para os fins deste tutorial, escolha hello-express , pois isso lhe proporcionará um ambiente com o Node.js e o npm já instalados.
Glitch hello-express
Para instalar pacotes adicionais do Node, você pode acessar a linha de comando clicando no botão Console na janela de logs.
Console
Você pode ativar ou desativar a janela de registros clicando no botão “Logs” , localizado na parte superior da barra lateral. A partir daí, você pode usar todos os comandos padrão da CLI em um ambiente bash. A única diferença é que, no Glitch, você usaria pnpm em vez de npm.
Usos do Glitch o Express como seu framework padrão do Node.js, mas a conversão do aplicativo para Koa.js não é muito complicada. Observe que o Koa requer o Node v7.6.0 ou superior para oferecer suporte ao ES2015 e às funções assíncronas.
Dependencies
Remover express e body-parser do projeto com o seguinte comando:
Instale o Koa.js e o koa-bodyparser com o seguinte comando:
O console e o editor não se sincronizam automaticamente; portanto, execute o refresh comando para atualizar o package.json arquivo no editor.
Koa
Você também notará que o status da sua solicitação apresenta um erro. Isso é esperado, pois o arquivo padrão server.js ainda faz referência a express.
Para corrigir isso, substitua o conteúdo de server.js pelo seguinte código:
const Koa = require('koa');
const app = new Koa();
app.use(async ctx => {
ctx.body = 'Hello Dinosaur';
});
app.listen(3000);
Agora, quando você tentar acessar seu aplicativo, ele deve exibir uma página em branco com as palavras Olá, Dinossauro.
Servindo arquivos estáticos com o Koa.js
Precisaríamos disponibilizar uma página HTML básica com campos de entrada para que os usuários possam inserir as informações necessárias para enviar um SMS, como o número de telefone do destinatário e o próprio texto da mensagem.
koa-static é um middleware de serviço de arquivos estáticos para o Koa. Instale-o em seu projeto pelo console com o seguinte comando:
Para simplificar, coloque todos os arquivos necessários para a página de destino na public pasta. Você pode mover o index.html arquivo da views pasta para a public pasta, renomeando o caminho do arquivo na barra lateral.
Rename file
Você também pode fazer isso pela linha de comando, usando o console.
Depois de fazer isso, modifique o server.js arquivo para usar o koa-static e servir os arquivos a partir da public pasta da seguinte maneira:
const serve = require('koa-static');
const Koa = require('koa');
const app = new Koa();
app.use(serve('./public'));
app.listen(3000);
console.log('listening on port 3000');Agora, em vez de “hello world”, seu aplicativo deve estar exibindo o arquivo padrão do Glitch index.html . Modificaremos esse arquivo para imitar a interface de um celular mais adiante neste tutorial.
Introdução às APIs da Nexmo
Dashboard
Volte ao aplicativo Glitch e instale o cliente da API REST da Nexmo para Node.js com o seguinte comando:
Estamos usando a versão beta, pois a Messages API ainda está em fase beta. E se você atualizar seu projeto, seu package.json deverá ficar assim:
Nexmo node
E agora já concluímos a configuração básica. Isso pode servir como ponto de partida para inúmeras Applications Koa que utilizam as APIs da Nexmo; portanto, você pode manter esse projeto como um kit inicial no Glitch e usá-lo como base para suas próprias criações.
O que são WebSockets?
O protocolo WebSocket foi desenvolvido pela Internet Engineering Task Force (IETF) para permitir a comunicação bidirecional entre um cliente e um host remoto.
É um tipo de protocolo de comunicação, como HTTP (Protocolo de Transferência de Hipertexto), FTP (Protocolo de Transferência de Arquivos) ou SMTP (Protocolo Simples de Transferência de Correio). Os protocolos de comunicação permitem que os computadores se comuniquem entre si. A maioria dos protocolos de comunicação mantém uma conexão aberta entre dois computadores pela internet.
O HTTP, que é a base de funcionamento da web, é diferente. É conhecido como um protocolo sem conexão, pois se baseia em um modo de operação de solicitação/resposta. Os navegadores da web enviam solicitações ao servidor para obter imagens, fontes, conteúdo etc., mas, assim que a solicitação é atendida, a conexão entre o navegador e o servidor é encerrada.
É possível atualizar uma conexão HTTP existente para um novo protocolo incompatível usando o cabeçalho HTTP “upgrade”. As solicitações de conexão são sempre iniciadas pelo cliente, embora o servidor possa impor uma atualização respondendo com uma 426 Upgrade Required resposta HTTP ao cliente.
Uma conexão HTTP/1.1 pode ser atualizada para uma conexão TLS (abordagem não recomendada), uma conexão HTTP/2 ou uma conexão WebSocket, sendo esta última o caso de uso mais comum para uma atualização. O estabelecimento de uma conexão WebSocket entre o cliente e o servidor envolve uma solicitação inicial HTTP/1.1 que inclui os cabeçalhos de atualização.
Uma versão simplificada do cabeçalho inicial fica mais ou menos assim:
GET /chat HTTP/1.1
Host: server.example.com
Origin: http://example.com
Upgrade: websocket
Connection: UpgradeSe o servidor for compatível com o protocolo WebSocket, ele aceitaria a solicitação de atualização e responderia ao handshake com um 101 código de status:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: UpgradeQualquer coisa que não seja um 101 indica que o handshake do WebSocket não foi concluído. Assim que o handshake for concluído, a conexão HTTP/1.1 inicial é convertida em uma conexão WebSocket e os dados já podem ser trocados entre as duas máquinas.
A API WebSockets é uma interface que permite que aplicativos da web utilizar o protocolo WebSocket para manter comunicações bidirecionais com processos do lado do servidor. A maioria dos navegadores lançados após 2012 oferece suporte à API WebSockets, portanto, a compatibilidade é razoavelmente boa.
O objeto WebSocket fornece a API para criar e gerenciar uma conexão WebSocket com um servidor, bem como para enviar e receber dados por meio dessa conexão. Podemos criar um novo objeto WebSocket com o construtor WebSocket, WebSocket(url[, protocols]). A URL passada ao construtor WebSocket deve estar no formato ws ou wss para que tudo funcione.
const socket = new WebSocket('ws://localhost:8080')O objeto WebSocket dispara quatro eventos, que podemos monitorar e tratar adequadamente:
openerrormessageclose
Assim que uma conexão WebSocket for estabelecida, o open evento é disparado. Com referência ao objeto WebSocket criado no bloco de código anterior, o manipulador de eventos correspondente ficaria mais ou menos assim:
socket.onopen = function(evt) {
// do something
}Podemos usar o error evento para registrar quaisquer erros no console para fins de depuração e, talvez, adicionar também um manipulador de eventos de erro:
socket.onerror = function(evt) {
console.log('WebSocket error: ', evt)
// include an error event handler here
}Normalmente, utilizaríamos o message evento, que é disparado quando mensagens do servidor são recebidas. Por exemplo, se você recebesse uma mensagem de texto enviada pelo servidor, poderia registrá-la no console da seguinte maneira:
socket.onmessage = function(evt) {
console.log('Message: ', evt.data)
}Por fim, o close evento é disparado quando a conexão WebSocket é encerrada. Quando isso ocorre, o cliente e o servidor não podem mais enviar mensagens um ao outro até que uma nova conexão seja estabelecida.
socket.onclose = function(evt) {
console.log('WebSocket connection closed. ', evt)
}Existem também dois métodos associados ao objeto WebSocket, send() para enviar dados ao servidor e close() para encerrar uma conexão WebSocket existente.
O send() método só funciona enquanto a conexão estiver aberta, o que parece óbvio, mas, se o código estiver estruturado incorretamente, ele pode acabar sendo acionado antes que a conexão seja aberta ou depois que ela for fechada.
// Listen for the open event before triggering the sendMsg() function
socket.onopen = function(evt) {
console.log('Connection established')
sendMsg('Hello Nexmo!')
}
// Send a message through the WebSocket connection
function sendMsg(data) {
socket.send(data)
}Agora que entendemos melhor o que são WebSockets e como funciona a API do WebSocket, estamos prontos para utilizar esse conhecimento para criar um aplicativo básico para enviar e receber SMS diretamente pelo navegador com a Messages API Nexmo.
Recebendo SMS no navegador com o Nexmo
Como obter um número de telefone virtual
Para enviar e receber SMS por meio da Messages API, você precisará de um número de telefone virtual, que é como qualquer número de telefone padrão, exceto que não está vinculado a nenhuma linha telefônica física ou aparelho.
Você pode comprar um número virtual na Numbers na barra lateral, selecionando Comprar números. Você pode escolher um número local de um país de sua preferência, os recursos disponíveis e o tipo de número, seja celular, fixo ou ligação gratuita.
Buy numbers
Assim que você tiver seu número, ele aparecerá no seção “Numbers” . Clique no ícone de lápis abaixo da coluna mais à direita Gerenciar , para configurar a URL do seu webhook de entrada. Isso é necessário para receber SMS. Quando um SMS é enviado para o seu número, uma POST solicitação é enviada para essa URL com o conteúdo da mensagem.
Inbound webhook URL
Se você estiver usando o Glitch, a URL do seu webhook seria algo como https://boom-meal.glitch.me/inbound-SMS. Sugiro usar inbound-sms como rota, mas você pode usar o que quiser, desde que essa rota seja válida no seu aplicativo. Ajuste a URL do webhook de acordo com o local onde seu aplicativo está hospedado.
Outra coisa a verificar é se a configuração padrão de SMS na sua conta está definida para POST no método HTTP.
Settings
Recebimento de um SMS recebido
Para receber uma mensagem SMS, você precisará adicionar uma rota em seu aplicativo para lidar com a solicitação de entrada POST que é acionado quando alguém envia um SMS para o seu número virtual. Ao contrário de outras estruturas populares do Node.js, como Express ou Hapi.js, o roteamento é gerenciado por um módulo separado; portanto, precisaremos instalá-lo primeiro.
Adicione o seguinte ao seu server.js arquivo:
const bodyParser = require('koa-bodyparser');
const Router = require('koa-router');
const router = new Router();
app.use(bodyParser());
// Make sure this is the route you configured for your virtual number
router.post('/inbound-sms', async (ctx, next) => {
const payload = ctx.request.body;
console.log(payload);
ctx.status = 200;
});
app.use(router.routes()).use(router.allowedMethods());
Se você seguiu as instruções de configuração apresentadas anteriormente neste tutorial, koa-bodyparser já deve estar instalado. É necessário um analisador de corpo de solicitação para processar o corpo da solicitação. Para verificar se tudo está conectado corretamente, envie um SMS para o seu número virtual. O conteúdo da mensagem deve ser registrado no console.
SMS payload
Criação de um servidor WebSocket
Agora que Verifyamos que tudo está funcionando, em vez de registrar o conteúdo da mensagem no console, vamos usar WebSockets para enviar as informações relevantes ao navegador.
Mas, primeiro, vamos instalar uma biblioteca auxiliar do Node.js para WebSocket chamada ws.
Depois de fazer isso, podemos usar ws em nosso server.js arquivo da seguinte maneira para criar um servidor WebSocket:
const http = require('http');
const WebSocket = require('ws');
// Create a web socket server on top of a regular http server
const server = http.createServer(app.callback());
const wsserver = new WebSocket.Server({ server: server });Substitua o original app.listen(3000) por server.listen(3000).
Vamos também adicionar uma função para processar o conteúdo da mensagem recebida e, em seguida, enviar esses dados para o navegador.
function receiveSms(payload) {
const phone = payload.msisdn;
const msg = payload.text;
const timestamp = payload['message-timestamp'];
const smsData = JSON.stringify({
phone: phone,
msg: msg,
timestamp: timestamp
});
// Broadcast the message to all open clients
wsserver.clients.forEach(client => {
if (client.readyState === WebSocket.OPEN) {
client.send(smsData);
}
});
}
Seu arquivo server.js arquivo até este ponto do tutorial deve estar mais ou menos assim:
const Koa = require('koa');
const bodyParser = require('koa-bodyparser');
const Router = require('koa-router');
const serve = require('koa-static');
const http = require('http');
const WebSocket = require('ws');
const app = new Koa();
const router = new Router();
const server = http.createServer(app.callback());
const wsserver = new WebSocket.Server({ server: server });
app.use(serve('./public'));
app.use(bodyParser());
router.post('/inbound-sms', async (ctx, next) => {
const payload = ctx.request.body;
receiveSms(payload);
ctx.status = 200;
});
app.use(router.routes()).use(router.allowedMethods());
server.listen(3000);
console.log('listening on port 3000');
function receiveSms(payload) {
const phone = payload.msisdn;
const msg = payload.text;
const timestamp = payload['message-timestamp'];
const smsData = JSON.stringify({
phone: phone,
msg: msg,
timestamp: timestamp
});
// Broadcast the message to all open clients
wsserver.clients.forEach(client => {
if (client.readyState === WebSocket.OPEN) {
client.send(smsData);
}
});
}
Exibição de SMS recebidas no navegador
O próximo passo é garantir que o navegador esteja pronto para receber esses dados do servidor; portanto, é hora de configurar a parte do front-end.
Apague o conteúdo padrão do client.js arquivo fornecido pelo Glitch e substitua seu conteúdo pelo seguinte:
document.addEventListener("DOMContentLoaded", function() {
let socket = null;
let connected = false;
function start() {
socket = new WebSocket('wss://' + location.host);
socket.onopen = function(evt) {
connected = true;
console.log('open')
}
socket.onmessage = function(evt) {
const reply = JSON.parse(evt.data);
console.log(reply);
addMsg(reply.phone, reply.msg, reply.timestamp, 'messages');
}
socket.onclose = function(evt) {
connected = false;
console.log('closed')
check();
}
}
function check() {
if(!socket || socket.readyState == 3) start();
}
start();
setInterval(check, 5000);
});Existem duas funções aqui, start() para estabelecer uma nova conexão WebSocket e os manipuladores de eventos correspondentes, e check() verificar se a conexão está ativa e se reconectar caso seja desconectada.
Agora, se você abrir o console do navegador no seu aplicativo e deixá-lo aberto por um tempo, deverá ver uma série de open e close sendo registrados no console.
Check
Substitua a marcação padrão do elemento no index.html arquivo pela seguinte, em vez disso:
<main>
<h1>V-mobile</h1>
<ul id="messages"></ul>
</main>Mais tarde, podemos adicionar mais elementos e estilos para que ele se pareça mais com um celular. Por enquanto, vamos primeiro fazer com que todos os dados sejam exibidos no lugar correto. Vamos adicionar mais duas funções ao client.js arquivo que analisarão os dados enviados pelo servidor e os anexarão ao DOM.
function addMsg(sender, content, time, parent) {
const messages = document.getElementById(parent);
const newMsg = document.createElement('li');
messages.appendChild(newMsg);
appendData(newMsg, sender);
appendData(newMsg, content);
appendData(newMsg, time);
}
function appendData(newMsg, data) {
const textSpan = document.createElement('span');
const textContent = document.createTextNode(data);
textSpan.appendChild(textContent);
newMsg.appendChild(textSpan);
}Adicione essa nova função ao onmessage manipulador de eventos e, quando você enviar um SMS para o seu número virtual, esse SMS deverá ser exibido na sua página, embora com um estilo um pouco rudimentar e sem uma aparência muito bonita.
socket.onmessage = function(evt) {
const reply = JSON.parse(evt.data);
console.log(reply);
addMsg(reply.phone, reply.msg, reply.timestamp, 'messages');
}
First Inbound
Envio de SMS pelo navegador com a Messages API da Nexmo
Criação de um aplicativo de mensagens
Em seguida, volte ao seu painel do Nexmo e acesse a página “Criar um aplicativo” , na seção seção “Mensagens e Envio” na barra lateral. Preencha o nome do seu aplicativo e as URLs de webhook com a URL do seu aplicativo Glitch como host. Você também precisará gerar um par de chaves pública/privada, o que solicitará que você baixe o private.key arquivo.
Generate key
É importante que ambas as URLs de webhook estejam configuradas e que seu aplicativo tenha rotas definidas para esses dois endpoints, a fim de aceitar POST solicitações, a fim de evitar um acúmulo indesejado na fila de mensagens.
Em seguida, clique no botão laranja Criar inscrição . A próxima tela permitirá que você vincule seu número virtual ao seu aplicativo clicando no Botão “Vincular” , localizado na seção Gerenciar .
Create a message application
Por fim, será perguntado se você deseja vincular algum account externo, mas você pode deixar isso para depois.
External accounts
Para enviar o private.key arquivo no Glitch e mantê-lo em segredo, você pode criar o arquivo em uma .data pasta. O conteúdo dessa pasta só ficará visível para você e para quaisquer colaboradores de confiança que você adicionar ao projeto. Copie o conteúdo do private.key que você baixou anteriormente para esse novo arquivo.
Private key
Configuração de credenciais
O Glitch oferece suporte a variáveis de ambiente por meio do .env arquivo, que é uma maneira segura de armazenar suas credenciais de API e outros dados privados do seu projeto. Configure sua chave de API, seu segredo, seu número virtual da Nexmo, o ID do aplicativo do Messages e o caminho da chave privada no .env arquivo.
Certifique-se de colocá-los entre aspas, pois cada valor precisa ser uma string. Vamos utilizá-los para inicializar uma nova instância do Nexmo, que usaremos para enviar mensagens SMS.
env file
Adicione suas credenciais de API ao server.js arquivo e inicialize uma nova instância do Nexmo.
const NEXMO_API_KEY = process.env.NEXMO_API_KEY;
const NEXMO_API_SECRET = process.env.NEXMO_API_SECRET;
const NEXMO_APPLICATION_ID = process.env.NEXMO_APPLICATION_ID;
const NEXMO_APPLICATION_PRIVATE_KEY_PATH = process.env.NEXMO_APPLICATION_PRIVATE_KEY_PATH;
const NEXMO_NUMBER = process.env.NEXMO_NUMBER;
const Nexmo = require('nexmo');
const nexmo = new Nexmo({
apiKey: NEXMO_API_KEY,
apiSecret: NEXMO_API_SECRET,
applicationId: NEXMO_APPLICATION_ID,
privateKey: NEXMO_APPLICATION_PRIVATE_KEY_PATH
}); Como enviar um SMS pelo navegador
Precisaremos de alguma forma para que os usuários insiram o número de telefone do destinatário e a mensagem que desejam enviar; portanto, vamos adicionar alguns campos de entrada para que eles possam fazer isso.
<input type="tel" name="phone" placeholder="Send SMS to…?" required>
<input type="text" name="msg">
<button id="send" type="button">Send</button>
Inputs
Para processar as entradas do usuário, adicione o seguinte ao seu client.js arquivo:
const msgField = document.querySelector('input[name="msg"]');
const phoneField = document.querySelector('input[name="phone"]');
const sendBtn = document.getElementById('send');
msgField.addEventListener('keypress', (evt) => {
if (evt.keyCode === 13) {
const passed = phoneCheck(phoneField);
if (passed) {
send(socket, phoneField, msgField);
} else {
console.log('Phone field was not filled. To do: add error handling UI here.');
}
}
}, false);
sendBtn.addEventListener('click', (evt) => {
const passed = phoneCheck(phoneField);
if (passed) {
send(socket, phoneField, msgField);
} else {
console.log('Phone field was not filled. To do: add error handling UI here.');
}
}, false);
function phoneCheck(phoneField) {
return phoneField.value !== '' && /^\d+$/.test(phoneField.value);
}
function send(socket, phoneField, msgField) {
const phone = phoneField.value.replace(/\D/g,'');
const msg = msgField.value;
const payload = JSON.stringify({
phone: phone,
message: msg
});
socket.send(payload);
const date = new Date();
const time = date.toLocaleTimeString();
addMsg('YOUR_APP_NAME', msg, time, 'messages');
msgField.value= '';
}
O que estamos fazendo aqui é acionar a send() função quando o usuário clica no botão ou no Enter . Há também uma verificação bem básica no campo do número de telefone, para garantir que apenas dígitos sejam inseridos. A mensagem também será exibida no navegador, como em um aplicativo de mensagens comum.
Há um muito mais a ser feito em relação à validação de campos do ponto de vista da segurança e da experiência do usuário, o que está fora do escopo deste tutorial, mas a validação é importante e é sempre uma boa prática dedicar esforços e testes para garantir que ela seja feita da maneira correta.
No lado do servidor, precisamos receber os dados enviados pelo navegador e encaminhar a mensagem para o número de telefone do destinatário.
Adicione as seguintes rotas ao seu server.js arquivo:
router.post('/webhooks/inbound-message', async (ctx, next) => {
ctx.status = 200;
});
router.post('/webhooks/message-status', async (ctx, next) => {
ctx.status = 200;
});
O objetivo é garantir que POST as solicitações da Nexmo tenham endpoints adequados para onde serem enviadas e de onde receber 200 respostas após a entrega bem-sucedida.
Vamos adicionar um manipulador de mensagens e uma forwardSMS() função que utilizará a Messages API da Nexmo para enviar um SMS ao destinatário assim que os dados forem recebidos do navegador.
wsserver.on('connection', function connection(socket) {
socket.on('message', data => {
forwardSms(JSON.parse(data));
});
});
function forwardSms(payload) {
const phone = payload.phone;
const msg = payload.message;
nexmo.channel.send(
{ "type": "sms", "number": phone },
{ "type": "sms", "number": NEXMO_NUMBER },
{
"content": {
"type": "text",
"text": msg
}
},
(err, data) => {
if (err) { console.log(err) }
if (data) { console.log('Outbound message successful: ', data.message_uuid) }
}
)
}
Para verificar se tudo funciona conforme o esperado, digite o número de um celular ao qual você tenha acesso e envie uma mensagem de teste. O destinatário deve receber o SMS em poucos segundos.
Forward SMS
Se o destinatário responder à conversa por SMS, a mensagem será reenviada para o navegador.
Reply
Agora que o sistema subjacente está em funcionamento, há várias coisas que você pode fazer se quiser dar continuidade a este projeto, como deixar a interface mais bonita, adicionar verificações de validação mais rigorosas tanto no cliente quanto no servidor, lidar com casos extremos, etc.
Minha versão desse projeto se chama V-mobile e você pode conferi-la no Glitch. Se você gostar do visual, fique à vontade para remixar meu projeto e adaptá-lo ao seu gosto.
End result
E agora, para onde vamos?
Se você quiser explorar mais essas APIs, aqui estão alguns links que podem ser úteis:
Documentação da Messages API no portal do desenvolvedor
Série de tutoriais para várias APIs da Nexmo
Se precisar de nós, acesse o canal da Comunidade Nexmo no Slack
Compartilhe sua opinião conosco enviando um tweet para @NexmoDev