https://a.storyblok.com/f/270183/31012/bc56090b38/ably_vonage_1200x600.png

Exibir notificações de SMS no navegador com Next.JS, Ably e Vercel

Publicado em April 26, 2021

Tempo de leitura: 12 minutos

A SMS API de Vonage permite que você envie e receba mensagens de texto em todo o mundo usando um número virtual que você pode alugar da Vonage.

Neste tutorial, você utilizará a SMS API da Vonage, a plataforma de mensagens em tempo real Ably, o Next.js e o Vercel para receber mensagens SMS no navegador em tempo real, assim que forem recebidas.

Acompanhe este guia para aprender a:

Dependências

Para criar esse aplicativo, você também precisará de:

Pré-requisitos para o desenvolvimento local

Você precisará de uma chave de API da Ably para se autenticar no serviço da Ably. Para obter uma chave de API, depois de criado uma conta na Ably:

  1. Acesse o painel do aplicativo e clique em “Criar novo aplicativo”.

  2. Dê um nome ao novo aplicativo

  3. Copie a chave API privada assim que o aplicativo for criado. Guarde-a em um local seguro, pois é com ela que você fará a autenticação no serviço Ably.

O Vercel oferece algumas ferramentas de linha de comando do Next.js para nos ajudar. Elas não precisam ser instaladas no seu sistema, pois são executadas usando npx.

WebSockets no Vercel com o Ably

Vercel and Websockets

O Vercel é uma plataforma de hospedagem desenvolvida desde o início para hospedar aplicativos Next.js e funções sem servidor. Ela permite que os usuários implantem funções sem servidor, que são, essencialmente, apenas blocos de código que respondem a uma solicitação HTTP.
No entanto, essas funções têm um tempo limite máximo de execução, o que significa que é impossível manter uma conexão WebSocket dessa forma.

É aí que entra o Ably. O cliente pode se conectar a um canal do Ably e enviar e receber mensagens nele para adicionar a funcionalidade em tempo real ao seu aplicativo, gerenciando suas conexões WebSocket para você. Vamos ver como criar um aplicativo que use a funcionalidade em tempo real neste passo a passo. Se quiser saber mais sobre WebSockets no Next.js e no Vercel, confira “Criando um aplicativo de bate-papo em tempo real com Next.js e Vercel".

Criação do aplicativo de SMS em tempo real

Para criar o aplicativo inicial:

  1. No seu terminal, digite npx create-next-app para criar um aplicativo Next.js vazio.

  2. Crie um arquivo chamado .env na raiz do diretório; é aqui que colocaremos as variáveis de ambiente do projeto.

  3. Adicione sua chave da API do Ably ao arquivo .env:

ABLY_API_KEY=your-ably-api-key:goes-here
  1. Acesse o diretório do seu aplicativo Next.js e digite no console:

npm run dev

O servidor de desenvolvimento do Next.js será iniciado, e você verá um aplicativo inicial vazio do Next.js. Você vai desenvolver nosso aplicativo de SMS no navegador com base nele.

Mensagens Pub/Sub em tempo real com o Ably

Este aplicativo utiliza o Ably para mensagens do tipo pub/sub entre os usuários. Pub/Sub significa “Publicar e Assinar” (Publish and Subscribe) e é um padrão popular usado para entrega de dados em tempo real. O aplicativo enviará, ou publish, mensagens por meio de um canal do Ably. Os clientes que utilizam o aplicativo estarão subscribed no canal e poderão receber as mensagens.

Autenticação no serviço Ably

Os aplicativos Next.js no Vercel não executam o tradicional “código do lado do servidor”. No entanto, você pode adicionar arquivos JavaScript a /pages/api/*, e o mecanismo de implantação do Vercel tratará cada um deles como um endpoint de API e os gerenciará como funções sem servidor para você.

Para o desenvolvimento local, as ferramentas do Next.js executam essas funções em um servidor Node, de modo que elas funcionam como você esperaria em seu ambiente de desenvolvimento local. Você vai adicionar uma função sem servidor do Next.js/Vercel ao código inicial que criou anteriormente para autenticar seu aplicativo no Ably e possibilitar o envio e o recebimento de mensagens pelo serviço Ably.

Criação da função sem servidor para se conectar ao Ably

Você precisará instalar o pacote npm do Ably (é essencial que você esteja executando o Ably 1.2.5 ou superior para este aplicativo, por motivos de compatibilidade com o Vercel).

No terminal, na raiz do seu novo aplicativo, execute:

npm install ably@1.2.5-beta.1

Em seguida, crie um arquivo chamado ./pages/api/createTokenRequest.js e adicione o seguinte código a ele:

import Ably from "ably/promises";

export default async function handler(req, res) {
    const client = new Ably.Realtime(process.env.ABLY_API_KEY);
    const tokenRequestData = await client.auth.createTokenRequest({ clientId: 'ably-nextjs-demo' });
    res.status(200).json(tokenRequestData);
};

Essa função sem servidor usa o SDK do Ably para criar um tokenRequest com sua chave de API. Você usará esse token mais tarde — ele permite que você mantenha sua chave de API “real” em segurança enquanto a utiliza no aplicativo Next.js.
Por padrão, essa API está configurada para estar disponível em http://localhost:3000/api/createTokenRequest. Você fornecerá essa URL ao SDK do Ably no seu cliente para se autenticar no Ably.

Como receber um SMS usando o Vonage e o Vercel

A Vonage permite que você configure números de celular no painel da API. Quando uma mensagem SMS for recebida, ela acionará sua API.

Para fazer isso, você precisa adicionar uma Vercel Serverless function ao nosso aplicativo Next.js. Essa função sem servidor será chamada pela Vonage sempre que um SMS for recebido (assim que você configurar um número de telefone!). Você precisa inserir um código nessa função para extrair o conteúdo da mensagem SMS e, em seguida, enviá-la ao seu aplicativo React usando um Ably channel.

Esse processo é bastante semelhante à configuração do seu Ably createTokenRequest.

Crie um arquivo chamado ./pages/api/acceptWebhook.js e adicione o seguinte código nele:

import Ably from "ably/promises";

export default async function handler(req, res) {

    // Unpack the SMS details from the request query string
    const incomingData = getSmsDetails(req, res);

    // If the request was invalid, return status 400.
    if (!incomingData.success) {
        res.status(400).end();
        return;
    }

    // Create an Ably client, get your `sms-notifications` channel
    const client = new Ably.Realtime(process.env.ABLY_API_KEY);
    const channel = client.channels.get("sms-notifications");

    // Publish your SMS contents as an Ably message for the browser
    await channel.publish({ name: "smsEvent", data: incomingData });

    // Return the received data as a 200 OK for debugging.
    res.send(incomingData);
    res.status(200).end();
};

function getSmsDetails(req, res) {

    const params = req.query;

    if (!params.to || !params.msisdn) {
        console.log('This is not a valid inbound SMS message!');
        return { success: false };
    }

    return {
        success: true,
        messageId: params.messageId,
        from: params.msisdn,
        text: params.text,
        type: params.type,
        timestamp: params['message-timestamp']
    };
}

Vamos voltar ao aplicativo por enquanto, mas voltaremos a essa função no final, assim que o aplicativo for implantado no Vercel e sua função tiver um public url.

Respondendo a mensagens SMS com o SmsComponent

As páginas em Next.js são componentes React; portanto, a pages/index.js página inicial é o componente React que contém o layout da página.

Esta é a página padrão gerada por create-next-app; você adicionará seu componente a ela — a lógica do aplicativo está contida dentro de SmsComponent.jsx.

Comece incluindo as importações necessárias no início do arquivo:

import React, { useEffect, useState } from 'react';
import { useChannel } from "./AblyReactEffect";
import styles from './SmsComponent.module.css';

Em seguida, defina a função que será exportada como um componente React.

const SmsComponent = () => {
    
  let messageEnd = null;

  const [receivedMessages, setMessages] = useState([]);

e use o seu primeiro react hook:

  const [channel, ably] = useChannel("sms-notifications", (message) => {
    const history = receivedMessages.slice(-199);
    setMessages([...history, message]);
  });

useChannel é um API do tipo react-hook para assinar mensagens de um canal do Ably. Você fornece a ela um nome de canal e uma função de retorno a ser chamada sempre que uma mensagem for recebida.

Em seguida, você vai formatar os dados para a tela, de modo que cada mensagem possa ser exibida, juntamente com a hora em que chegou e o número de telefone do remetente.

   const messages = receivedMessages.map((message, index) => {
    console.log(message);
    let from = [message.data.from.slice(0, 2) + " " + message.data.from.slice(2, 6) +  " " + message.data.from.slice(6, 9) + " "+ message.data.from.slice(9)];
    let date = new Date(message.data.timestamp);
    let day = date.toDateString().replace(/^\S+\s/,'');
    let time = date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });

    return (
      <div key={index} className={styles.message}>
        <span className={styles.from}>{from}</span>
        <span className={styles.when}>{day}, {time}</span>
        <span className={styles.text}>{message.data.text}</span>
      </div>
    );
  });

Por fim, crie seu componente e retorne-o:

  return (
    <div className={styles.chatHolder}>
      <h1 className={styles.title}>Text Messages</h1>
      <div className={styles.chatText}>
        {messages}
        <div ref={(element) => { messageEnd = element; }}></div>
      </div>
    </div>
  )
}

Bem no final do arquivo, a função é exportada como SmsComponent para que possa ser referenciada na página de índice do Next.js.

Como usar o Ably corretamente em componentes do React

Uma das partes mais complicadas ao usar o Ably com os Componentes Funcionais do React é saber quando e onde criar a instância do SDK e quando e onde se conectar ao(s) seu(s) canal(is). É recomendável evitar criar a instância do SDK quando o componente for renderizado, pois isso poderia gerar várias conexões e esgotar os limites da sua conta do Ably.

Para garantir que o aplicativo lide corretamente com a atualização, a montagem e a desmontagem dos componentes — AblyReactEffect exporte um Hook do React para interagir com o SDK do Ably.

Os hooks do React podem parecer um pouco incomuns na primeira vez que você os usa. Um hook é uma função que:

  • Executa a funcionalidade que você esperaria componentDidMount ser executada

  • Devoluções outra função que será executada pelo framework, onde componentDidUnmount seria chamada

  • Executa qualquer outra ação que seja necessária

Este React Hook é baseado em useEffect. Quando chamado, ele cria uma instância do SDK do Ably (isso ocorre apenas uma vez), que é configurada para usar a URL da sua função Serverless para createTokenRequest para autenticação:

import Ably from "ably/promises";
import { useEffect } from 'react'

const ably = new Ably.Realtime.Promise({ authUrl: '/api/createTokenRequest' });

Criar uma instância da biblioteca Ably fora do escopo do componente significa que ela será criada apenas uma vez, o que ajudará a manter baixo o uso do limite.

Em seguida, você precisa criar a função que vai exportar — o seu hook — para usá-la no seu componente. Vamos chamá-la de useChannel; ela exigirá o nome do canal e um callback como argumentos. Cada vez que useChannel for chamada, você get o canal solicitado do SDK do Ably-JS e preparar as funções do hook.

  • onMount é o código executado sempre que seu componente é renderizado. Dentro de onMount, você se inscreverá no canal especificado, acionando callbackOnMessage sempre que uma mensagem for recebida.

  • onUnmount é o código executado sempre que o componente é desmontado, antes de ser renderizado novamente. Aqui, você cancelará a assinatura do canal, o que impedirá conexões múltiplas acidentais, poupando, mais uma vez, os limites da nossa conta.

  • useEffectHook é uma função que chama essas funções corretamente, retornando onUnmount para que o React a utilize.

O Hook exportado AblyReactEffect.js ficará assim:

export function useChannel(channelName, callbackOnMessage) {
    const channel = ably.channels.get(channelName);

    const onMount = () => {
        channel.subscribe(msg => { callbackOnMessage(msg); });
    }

    const onUnmount = () => {
        channel.unsubscribe();
    }

    const useEffectHook = () => {
        onMount();
        return () => { onUnmount(); };
    };

    useEffect(useEffectHook);

    return [channel, ably];
}

O useChannel Hook retorna tanto o canal Ably atual quanto o SDK do Ably para que o código chamador possa usá-los para enviar mensagens. Esse hook encapsula o pub/sub do Ably para componentes funcionais do React em um único lugar, de modo que você não precisa se preocupar com isso em nenhum outro lugar, e o código que o utiliza pode processar as mensagens que recebe.

Deixando tudo bonito com o CSS de módulos - SmsComponent.module.css

Ao escrever o componente de bate-papo, você deve ter percebido que Next.js tem algumas convenções impostas pelo compilador que determinam onde você deve manter seu CSS e como importá-lo.

Para este aplicativo, crie um arquivo CSS com o mesmo nome do .jsx arquivo, só que com as extensões .module.css; isso facilita o gerenciamento do componente. Se você quiser excluir esse componente no futuro, será bem simples remover o arquivo CSS também.

Depois de criado, ele pode ser importado para o componente:

import styles from './SmsComponent.module.css';

Ao criar uma classe CSS em um elemento JSX, use a seguinte sintaxe no elemento:

className={styles.yourClassName}

e o CSS correspondente ficaria assim:

.yourClassName {
  styles: gohere;
}

Hospedagem no Vercel

Estamos usando Vercel como nosso servidor de desenvolvimento e pipeline de compilação.

A maneira mais fácil de implantar o Next.js em produção é usar a plataforma Vercel, dos criadores do Next.js. O Vercel é uma plataforma completa com CDN global que oferece suporte à implantação de conteúdo estático e Jamstack, além de funções sem servidor. -- A documentação do Next.js

Para implantar seu novo aplicativo de SMS no navegador no Vercel, você precisará:

  1. Crie uma Account no GitHub (caso ainda não tenha uma)

  2. Envie seu aplicativo para um repositório do GitHub

  3. Crie um account no Vercel

  4. Crie um novo aplicativo no Vercel e importe seu aplicativo do seu repositório do GitHub. (Para isso, será necessário autorizar o Vercel a usar sua conta do GitHub)

  5. Adicione sua ABLY_API_KEY como variável de ambiente

  6. Acompanhe a implantação do seu aplicativo

  7. Acesse a URL recém-criada no seu navegador!

Como configurar um número de SMS para seu aplicativo

Para receber mensagens SMS, você precisará alugar um número de telefone virtual da Vonage e configurá-lo.

Primeiro, faça login no seu Account da Vonage acessando o painel de controle. Depois de criar e confirmar sua Account, você pode comprar um número acessando Numbers => Comprar números. Procure um número que seja adequado para você e adicione créditos para pagar pelo número.

Depois de adquirir seu número, você precisa configurar o SMS Inbound Webhook URL.

Para fazer isso, vá em Numbers => Seus números => Clique no ícone da caneta.

Você verá uma caixa de diálogo modal e precisará inserir sua acceptWebhook URL da API na caixa.

Se o seu aplicativo Vercel se chamar your-vercel-app, a URL do webhook seria https://your-vercel-app.vercel.app/api/acceptWebhook.

Personalize!

Esta demonstração é de código aberto; faça um fork e adapte-a ao seu gosto. Não se esqueça de nos mostrar o que você criou @ablyRealtime.

Se você estiver procurando maneiras de ampliar este projeto, poderia considerar:

  • Criação de um aplicativo de votação por telefone

  • Adicionando um banco de dados para armazenar mensagens

  • Adicionar a funcionalidade de enviar uma mensagem de resposta.

Entre em contato conosco

Se este tutorial foi útil, ou se você está usando o Next.js e o Ably no seu projeto, adoraríamos saber mais sobre isso. Mande-nos uma mensagem no Twitter ou envie um e-mail para devrel@ably.io.

Compartilhar:

https://a.storyblok.com/f/270183/400x533/e7cf7a7926/jo-frank.png
Jo Franchetti

Jo is a developer advocate at Ably. She is passionate about Realtime Data, PWAs and great CSS. She has 10 years of experience as a front end developer and has worked in various parts of the tech industry from startups, agencies, charities to large organisations. She is also an instructor/mentor at codebar.io and Front End Foxes where she is able to act on her goals of not only teaching good use of the web but also improving the diversity and inclusivity of the tech industry.