https://a.storyblok.com/f/270183/94347/a7227ae45d/restaurant-closed_1200x600.png

O restaurante agora oferece entrega: um bot do Facebook em Node.js

Publicado em October 13, 2021

Tempo de leitura: 14 minutos

Introdução

Muitas vezes, quando estou programando, fico com fome. E todo mundo sabe que os melhores desenvolvedores são preguiçosos, então, em vez de ir às compras e cozinhar e limpar, geralmente uso um aplicativo de entrega de comida e simplesmente peço uma refeição saborosa. O problema é que, com muita frequência, meus restaurantes favoritos estão offline. Às vezes, estão fechados; outras vezes, estão lotados e param de aceitar pedidos online. Então, sou obrigado a esperar e me lembrar de verificar se eles voltaram a ficar online, e depois abrir o aplicativo e ver se estão online de novo. E, às vezes, verificar de novo, e de novo, e de novo. É realmente uma grande injustiça 😆.

Deve haver uma maneira melhor e mais inovadora! Felizmente, descobri recentemente meu aplicativo favorito de entrega de comida, o Wolt, que tem uma API que me avisa se um restaurante está online. Então, usando a Messages API do Vonage, criei um bot no Facebook Messenger que vai me alertar quando meu restaurante favorito voltar a ficar online!

(Este exemplo foi desenvolvido com base em um caso de uso de entrega de comida, mas o mesmo código pode ser adaptado para criar um bot no Facebook que alerte os usuários sobre qualquer alteração no valor booleano.)

Pré-requisitos

Este aplicativo requer o seguinte:

Pseudocódigo:

Antes de começar qualquer tarefa de programação, gosto de pensar bem na lógica. Vamos detalhar as etapas necessárias para criar esse aplicativo:

  1. Configurar um servidor Express

  2. Conectar-se ao ambiente de testes da Messages API do Vonage

  3. Chame a API do Wolt para o restaurante solicitado

  4. Verifique se o restaurante em questão está online

  5. Enviar uma mensagem ao usuário com base no status do restaurante

  6. Se o restaurante estiver fora de linha, adicione-o a uma lista de restaurantes fora de linha

  7. Verifique constantemente a lista de restaurantes fora de linha para verificar se houve alguma alteração no status

  8. Se um restaurante passar a estar online, envie uma mensagem ao usuário e remova-o da lista de restaurantes offline

Configurar nosso projeto

Criar um aplicativo Node

Vamos começar criando nosso projeto:

mkdir isItDelivering

Em seguida, acesse o diretório do projeto:

cd isItDelivering

Inicializar o projeto do nó:

npm init

Instale os pacotes necessários para o Node:

npm install -s @vonage/server-sdk@beta express dotenv got lokijs

E, por fim, crie os arquivos onde nosso código ficará:

touch index.js .env

Você vai perceber que estamos usando o Vonage SDK do Node Server da Vonage para acessar a Messages API. Como a Messages API está atualmente em fase Beta, precisamos da versão Beta do nosso SDK.

Para configurar nosso servidor, precisaremos de algumas informações do Painel do Desenvolvedor da Vonage. Primeiro, vamos criar um nova aplicação Vonage. Dê a ela um nome legal, como isItDelivering. Em seguida, clique em “Gerar chave pública e privada”.

Generate Public/Private KeyGenerate Public/Private Key

Isso irá gerar automaticamente uma chave para autenticação, que usaremos mais tarde. Copie a chave gerada para a raiz do seu projeto local.

Neste momento, seu projeto deve conter o arquivo index, os módulos do Node, o package.json e o arquivo ENV. Se você executar o comando ls, seu projeto deverá ficar assim:

Project Should Include index.js, node_modules, pack.json, private.keyProject Should Include index.js, node_modules, pack.json, private.key

Como você pode ver, nosso aplicativo da Vonage nos permite ativar ou desativar vários recursos por meio das diferentes APIs da Vonage. Queremos ativar os recursos do Messages. Agora, nos serão solicitadas duas URLs correspondentes aos webhooks que a Messages API usará para interagir com nosso aplicativo de bot.

Conecte-se ao mundo exterior

Configuração do ngrok

Existem várias maneiras de tornar nosso servidor de desenvolvimento local acessível externamente, mas uma das mais simples é usando o ngrok. Você pode ler este artigo para obter uma explicação mais detalhada sobre como o ngrok funciona.

Para o que nos interessa, basta colocá-lo em funcionamento e copiar a URL que ele nos fornece.

Depois de instalar o ngrok no seu computador, precisaremos iniciá-lo. Para iniciar o ngrok, abra uma nova janela do terminal e execute o seguinte na linha de comando:

$ ngrok http 3000

Agora você verá uma interface de registro do ngrok na janela do seu terminal. Na parte superior da interface, há uma linha que começa com Forwarding e contém duas URLs. A primeira é a URL do ngrok acessível externamente, que termina com ngrok.io seguida por http://localhost:3000, que é o seu servidor de desenvolvimento local. Agora, quando você ou a Vonage acessarem a ngrok.io URL, ela será redirecionada para o seu servidor local.

Agora, no nosso Painel da Vonage, vamos adicionar nossas URLs do ngrok e definir as rotas de URL apropriadas. Quando suas URLs estiverem assim, você poderá clicar no botão “Gerar novo aplicativo”.

Webook URLsWebhook URLs

Conecte-se com a Vonage

Conecte seu Account da Vonage

No arquivo ENV do seu projeto, você precisará adicionar três variáveis de ambiente; API_KEY , API_SECRET, e APP_ID.

Você pode encontrar o seu API_KEY e API_SECRET na página inicial do seu Painel de Controle da Vonage:

Dashboard ENV VariablesDashboard ENV Variables

Seu APP_ID está na página de configuração do aplicativo que você gerou. Você encontrará seu aplicativo em Your Applications na barra de navegação à esquerda. Seu APP_ID terá o seguinte formato:

APP_ID in DashboardAPP_ID in Dashboard

Depois de copiar e colar essas linhas no seu projeto, seu arquivo ENV deverá ficar mais ou menos assim:

API_KEY="XXXXXXXXX"
API_SECRET="XXXXXXXXX"
APP_ID="XXXXXXXXX"

Introdução ao Sandbox da Messages API

Adicionando usuários à sua área de testes

Vamos utilizar o Sandbox do Facebook da Vonage. Você pode encontrar o Sandbox no seu Painel da Vonage, na aba “Mensagens e Envio”, no lado esquerdo, ou clicar aqui. Depois de clicar Add to Sandbox na aba “Facebook Messenger”, sua tela deverá ficar assim:

Set up your sandboxSet up your sandbox

O Sandbox da Messages API permite testar rapidamente aplicativos sem precisar aguardar a aprovação do Account. O Sandbox utiliza uma abordagem de lista de permissões para autorizar usuários de teste. Você pode convidar usuários adicionais para a lista de permissões por meio do Send invite email button ou enviando a eles o link click this link. O link abrirá uma sessão do Facebook Messenger. O usuário precisará então enviar a senha para ser adicionado à lista de permissões. Detalhes completos podem ser encontrados aqui.

Conectando seu aplicativo ao seu ambiente de teste

Agora precisaremos configurar nosso Sandbox para receber as solicitações do nosso aplicativo e encaminhá-las ao Facebook Messenger. Isso é feito por meio das nossas URLs do ngrok. Precisaremos adicionar as mesmas URLs do ngrok de antes, desta forma:

Messages API Sandbox ngrok URLSMessages API Sandbox ngrok URLS

Assim que clicarmos no Save webhooks botão, nossa configuração está concluída e já podemos começar a programar!

Todo o código a seguir será colocado em nosso index.js arquivo.

Configurando um servidor Express

Criar um servidor modelo com dependências

Primeiro, vamos configurar um servidor Express padrão em nosso index.js arquivo, que importará as bibliotecas necessárias e simplesmente será executado na porta 3000:

// access our environment variables
require('dotenv').config();
// access the Vonage SDK so we can use the Voange object and API
const Vonage = require('@vonage/server-sdk');
// access Got library which allows us to make HTTP request to WOLT API
const got = require('got');

// boilerplate Express setup
const express = require('express');
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: false }));

app.listen(3000);

Como enviar uma mensagem básica no Facebook

Como enviar uma mensagem no Facebook a partir do nosso aplicativo

Precisamos inicializar uma instância do Vonage, passando nossas variáveis de ambiente, e, em seguida, instruí-la a usar o Vonage Sandbox como o servidor para realizar as solicitações HTTP. Podemos copiar o código a seguir em nosso

// initialize a new Vonage instance, with ENV variables/keys
const vonage = new Vonage(
  {
    apiKey: process.env.API_KEY,
    apiSecret: process.env.API_SECRET,
    applicationId: process.env.APP_ID,
    privateKey: './private.key'
  },
  {
    apiHost: 'https://messages-sandbox.nexmo.com/',
  }
 );

Em seguida, usamos esse objeto Vonage para enviar uma solicitação POST em nossa /inbound rota e precisamos fornecer dois parâmetros mínimos: type e text.

// Basic Sandbox Messaging
app.post('/inbound', (req, res) => {
  vonage.channel.send(
    req.body.from,
    req.body.to,
    {
      content: {
        type: 'text',
        text: 'You must be hungry! 🍕'
      },
    },
    (err, data) => {
      if(err){
        console.log(err);
      } else{
          console.log(data.message_uuid);
      }
    }
  );
  res.send('ok');
});

app.post('/status', (req, res) => {
  res.send('ok');
});

Então, agora, em uma segunda janela do terminal, separada do nosso servidor ngrok, precisamos iniciar nosso servidor Express:

$ node index.js

E podemos interagir com nosso bot do Facebook!

Basic Facebook SandBox MessageBasic Facebook SandBox Message

Recebendo informações sobre restaurantes pela API do Wolt

Fazendo a solicitação HTTP

Ao usar o https://restaurant-api.wolt.com/v3/venues/slug/{restaurant} endpoint, sabemos que podemos receber todo tipo de informação sobre o restaurante. O JSON retornado tem a seguinte aparência:

Wolt Returned JSONWolt Returned JSON

Podemos ver que, no índice zero, há uma propriedade chamada name do tipo array. No índice zero de name há um valor booleano chamado online, que indica o status atual da entrega do restaurante. Assim, podemos criar uma função que receba o nome de um restaurante e retorne o objeto do restaurante do Wolt:

// call Wolt API for restaurant info
const getRestaurant = async (reqRestaurant) => {
  const response = await got.get(`https://restaurant-api.wolt.com/v3/venues/slug/${reqRestaurant}`)
      .json();
  return response.results[0];
}

Verifique se o restaurante em questão está online

Usando a propriedade online dentro do restaurant objeto, queremos criar uma lógica que determine qual mensagem enviaremos ao usuário. Podemos escrever a seguinte função:

const firstStatusCheck = (restaurant, recipient) => {
  if (restaurant.online) {
    sendFacebookMessage(`Hey, ${restaurant.name[0].value} is now accepting orders!!`, recipient);
  } else {
	  sendFacebookMessage(`Sorry, ${restaurant.name[0].value} is currently offline. I'll ping you when it's open again!`, recipient);
    }
}

A firstStatusCheck função abstraiu nosso código da Vonage para enviar a mensagem do Facebook em uma função chamada sendFacebookMessage. Essa função agora pode enviar qualquer mensagem a partir da nossa conta Sandbox, desde que passemos a ela dois parâmetros text e recipient.

Podemos usar uma variável constante SENDER para passar as informações de identificação do remetente da conta Sandbox. Primeiro, vamos declará-la.

let SENDER;

E então atribuímos esse valor quando recebemos o req do /inbound ponto de extremidade:

app.post('/inbound', async(req, res) => {
  SENDER = req.body.from;

Agora, o sendFacebookMessage deve ficar assim:

const sendFacebookMessage = async (text, recipient) => {
  vonage.channel.send(
    SENDER,
    recipient,
    {
      content: {
        type: 'text',
        text: text,
      },
    },
    (err, data) => {
      if (err) {
        console.log(err);
      } else {
        console.log(data.message_uuid);
      }
     }
   );
 }

Enviar uma mensagem ao usuário com base no status do restaurante

Combinando nossa nova funcionalidade, podemos atualizar nosso sistema simples de mensagens do Sandbox para informar ao usuário se o restaurante solicitado está online no momento ou não.

// Enhanced Sandbox Messaging
app.post('/inbound', async(req, res) => {
	SENDER = req.body.from;
	const recipient = await req.body.to;
	const requestedRestaurant = await req.body.message.content.text.split('/').pop();
	const restaurant = await getRestaurant(requestedRestaurant);
	firstStatusCheck(restaurant, recipient);
	res.send('ok');
});

Repetir se o restaurante estiver offline

Agora que criamos a lógica com base no status do restaurante, queremos continuar verificando esse status até que o restaurante volte a ficar online. Portanto, precisamos desenvolver as três últimas etapas do nosso pseudocódigo:

  1. Se o restaurante estiver fora de linha, adicione-o a uma lista de restaurantes fora de linha

  2. Verifique constantemente a lista de restaurantes fora de linha para verificar se houve alguma alteração no status

  3. Se um restaurante passar a estar online, envie uma mensagem ao usuário e remova-o da lista de restaurantes offline

Criação de um banco de dados em memória de restaurantes que não estão abertos

Neste ponto, vamos usar nossa LokiJS biblioteca. O LokiJS é um banco de dados em memória que nos permitirá acompanhar cada restaurante solicitado de maneira simples e em tempo de execução. Se você já usou o MongoDB, o LokiJS vai lhe parecer bem familiar.

Primeiro, precisamos incluir o Loki junto com nossas outras dependências:

const loki = require('lokijs');

Em seguida, precisaremos instanciar nosso banco de dados:

let db = new loki("restaurants.db");
let restaurants = db.addCollection("restaurants");

Cada registro de restaurante conterá 4 campos: nome, status online, destinatário e slug. Name é o nome do restaurante. Online status é um valor booleano que indica se o restaurante está online no momento. Recipient é a informação do usuário proveniente da Messages API, que nos permitirá rastrear quem precisa ser notificado. E, finalmente, slug é a extensão da URL que a API do Wolt usa para localizar um restaurante.

Agora que temos um banco de dados, podemos começar a adicionar nossos restaurantes offline a ele! Podemos usar a seguinte função para adicionar restaurantes à nossa lista offline:

 const addRestaurantToDb = (restaurant, recipient) => {
  restaurants.insert({name: restaurant.name[0].value, online: restaurant.online, recipient: recipient, slug: restaurant.slug});
 }

Agora precisaremos atualizar nossa firstStatusCheck para adicionar restaurantes à lista offline.

// Check initially whether restaurant is online or should it be added to list of offline restaurants to check
const firstStatusCheck = (restaurant, recipient) => {
  if (restaurant.online) {
    sendFacebookMessage(`Hey, ${restaurant.name[0].value} is now accepting orders!!`, recipient);
  } else {
      sendFacebookMessage(`Sorry, ${restaurant.name[0].value} is currently offline. I'll ping you when it's open again!`, recipient);
      addRestaurantToDb(restaurant, recipient);
    }
}

Verifique continuamente se há alterações no status

Agora que temos uma lista de restaurantes fora de operação, queremos verificar se eles voltam a funcionar. Como queremos fazer isso regularmente e de forma contínua, vamos usar a função integrada setInterval :

setInterval(function(){offlineRestaurantLookup(req)} , INTERVAL);

A INTERVAL constante indica ao setInterval com que frequência ele deve executar a offlineRestaurantLookup função. Definimos isso no início do arquivo, ao lado de SENDER. Por padrão, vamos verificar a cada 60 segundos:

const INTERVAL = 60000;

O offlineRestaurantLookup vai recuperar todos os restaurantes do banco de dados offline e, em seguida, para cada restaurante, vai verificar se ele ainda está offline.

const offlineRestaurantLookup = async () => {
  let offlineRestaurants = restaurants.data;
  offlineRestaurants.forEach(await checkIsStill0ffline);
}

A checkIsStill0ffline função, por sua vez, verifica se um restaurante está online no momento. Se o restaurante tiver ficado online, ela enviará uma mensagem ao usuário correto e, em seguida, excluirá esse restaurante da lista de restaurantes offline.

const checkIsStill0ffline = async (restaurant) => {
  const checkedRestaurant = await getRestaurant(restaurant.slug);
  if (checkedRestaurant.online) {
    sendFacebookMessage(`Hey, ${restaurant.name} is now accepting orders!!`, restaurant.recipient);
    restaurants.chain().find({'name': restaurant.name}).remove();
  }
}

Agora podemos adicionar a setInterval funcionalidade abaixo da nossa lógica de mensagens do Sandbox:

// Enhanced Sandbox Messaging
app.post('/inbound', async(req, res) => {
  SENDER = req.body.from;
  const recipient = await req.body.to;
  const requestedRestaurant = await req.body.message.content.text.split('/').pop();
  const restaurant = await getRestaurant(requestedRestaurant);
  firstStatusCheck(restaurant, recipient);
  res.send('ok');
});

app.post('/status', (req, res) => {
  res.send('ok');
});

setInterval(function(){offlineRestaurantLookup()} , INTERVAL);

app.listen(3000);

E agora podemos executar o programa e ver que, quando um restaurante está offline, recebemos uma mensagem avisando sobre isso, e quando os restaurantes ficam online, somos atualizados sobre o novo status. Sugiro experimentar o aplicativo pela manhã e ver como os restaurantes abrem de repente para o almoço. É divertido receber as notificações push do Facebook Messenger no seu celular!

Enhanced Facebook SandBox MessageEnhanced Facebook SandBox Message

O que vem a seguir

  • Neste tutorial, utilizamos a funcionalidade do Facebook Messenger da Messages API, mas poderíamos ampliar essa aplicação para oferecer recursos omnicanal com o WhatsApp e o SMS. Imagine um caso de uso muito urgente (tenho em mente uma determinada padaria de bagels nas manhãs de sábado) em que você gostaria de ser notificado imediatamente sobre uma mudança de status; alertas omnicanal seriam úteis.

  • Poderíamos ampliar esse código para tornar os alertas mais inteligentes com base nos horários de entrega, na proximidade do usuário aos restaurantes e em outros fatores. Também poderíamos manter várias tarefas em andamento.

  • Poderíamos tirar o aplicativo do Sandbox e conectá-lo a um Account comercial do Facebook.

O código final do tutorial pode ser encontrado no GitHub. Adoraria saber o que você criou usando a Messages API do Vonage! Participe da conversa em nosso Slack da Comunidade e compartilhe sua história!

Compartilhar:

https://a.storyblok.com/f/270183/384x384/e4e7d1452e/benjamin-aronov.png
Benjamin AronovDeveloper Advocate

Benjamin Aronov is a developer advocate at Vonage. He is a proven community builder with a background in Ruby on Rails. Benjamin enjoys the beaches of Tel Aviv which he calls home. His Tel Aviv base allows him to meet and learn from some of the world's best startup founders. Outside of tech, Benjamin loves traveling the world in search of the perfect pain au chocolat.