
Compartilhar:
Michael é um engenheiro de software poliglota, empenhado em reduzir a complexidade dos sistemas e torná-los mais previsíveis. Trabalhando com diversas linguagens e ferramentas, ele compartilha seus conhecimentos técnicos com públicos de todo o mundo em grupos de usuários e conferências. No dia a dia, Michael é ex-representante de desenvolvedores da Vonage, onde dedicava seu tempo a aprender, ensinar e escrever sobre todos os tipos de tecnologia.
Criando um temporizador para o peru com Laravel, Facebook Messenger e Vonage
Tempo de leitura: 6 minutos
Este ano, minha sogra me pediu para ajudá-la a preparar o jantar de Natal para a família. Estou muito animada com isso, mas, com um filhote de cachorro novo em casa e um sobrinho pequeno, já posso imaginar que vou me distrair e esquecer de colocar as batatas no forno na hora certa!
Para ajudar nisso, decidi criar um pequeno aplicativo em Laravel que mantém uma coleção de receitas. Você envia uma mensagem com o nome de uma receita pelo WhatsApp, Facebook ou Viber. Ele busca a lista de etapas necessárias para cada receita e envia a próxima etapa quando chegar a hora de realizá-la. Você pode ficar tranquilo, sabendo que tudo na cozinha está sob controle e que, quando for hora de você intervir, receberá uma notificação!
Veja o aplicativo em ação:
Turkey Timer Demo
Nesta postagem, vou trabalhar com o Facebook, mas é fácil adaptar isso também para o WhatsApp e o Viber, já que vamos usar o pacote laravel-notification da Vonage.
Configuração do projeto Laravel e Vonage
Esse projeto exige bastante configuração; por isso, para evitar que você demore até o Ano Novo para ler este post, fui direto para o código específico do Vonage. Se você estiver interessado, eis o processo que segui para configurar o aplicativo (cada item tem um link para um commit que contém uma descrição mais detalhada do trabalho realizado):
Crie um modelo e uma migração para
Timingsdentro de umRecipeAdicionar dados iniciais ao banco de dados para fins de teste
É um aplicativo bem simples que conta com gerenciamento de usuários e a capacidade de exibir uma receita e os tempos associados a ela. É um aplicativo independente, sem dependência do Vonage no momento. No entanto, queremos poder receber mensagens em nossa página do Facebook, então preciso fazer mais algumas configurações. Para que o aplicativo funcione, preciso vincular minha página do Facebook a um Account da Vonage, criar e configurar um aplicativo para que o Vonage saiba para onde enviar as solicitações de webhook e expor meu aplicativo à internet usando o ngrok para que a Vonage possa acessá-la.
Se você quiser tentar criar isso por conta própria, participe da Slack da Comunidade Vonage e podemos seguir juntos as etapas necessárias
No restante deste post, vamos adicionar a funcionalidade para que os usuários possam nos enviar uma mensagem com o nome de uma receita e fazer com que o aplicativo responda indicando as ações que precisam ser realizadas no momento certo.
Como lidar com mensagens recebidas no Facebook
Quando criei meu aplicativo Vonage, tive que fornecer dois URLs: um que será chamado quando eu receber uma mensagem de um usuário e outro que recebe atualizações de status da Vonage. Escolhi /webhooks/inbound-message para receber mensagens e /webhooks/message-status para as atualizações de status. Como o Vonage enviará uma solicitação de fora do aplicativo, tive que desativar a verificação de no app/Http/Middleware/VerifyCsrfToken.php:
protected $except = [
'/webhooks/*'
];Agora que a Vonage consegue acessar meu webhook, é hora de processar essas solicitações recebidas. Usei make:controller para gerar um novo WebhooksController e atualizei routes/web.php para direcionar as URLs acima para este controlador:
Route::post('/webhooks/inbound-message', 'WebhooksController@inboundMessage')->name('webhooks.inbound');
Route::post('/webhooks/message-status', 'WebhooksController@messageStatus')->name('webhooks.status');
A última coisa a fazer é implementar o WebhooksController. Por enquanto, estou registrando a solicitação recebida para poder ver o formato da solicitação que a Vonage envia:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class WebhooksController extends Controller
{
public function inboundMessage(Request $request) {
\Log::debug('Inbound Message', $request->all());
}
public function messageStatus(Request $request) {
\Log::debug('Message Status', $request->all());
}
}
Depois de fazer essas alterações, enviei uma mensagem da minha conta pessoal para a minha página do Facebook e a seguinte entrada apareceu no arquivo de log do Laravel:
{
"message_uuid": "f4fcc665-7b71-4291-a079-505154e28c36",
"to": {
"id": "987654210987654",
"type": "messenger"
},
"from": {
"id": "123456789012345",
"type": "messenger"
},
"timestamp": "2018-12-12T11:36:44.663Z",
"direction": "inbound",
"message": {
"content": {
"type": "text",
"text": "Christmas Dinner"
}
}
}Ótimo! O usuário me enviou uma mensagem e meu aplicativo a recebeu como esperado. Agora que já conseguimos receber mensagens, é hora de começar a enviar respostas.
As alterações feitas nesta seção estão descritas em este commit
Criação de uma notificação no Laravel
Para enviar atualizações de volta ao usuário no momento certo, vamos usar a delay . Antes disso, precisamos habilitar a queue essa funcionalidade no Laravel. Vamos usar o database driver, já que a taxa de processamento não será particularmente alta e o uso do banco de dados elimina a necessidade de dependências adicionais, como o Redis. Podemos definir essa configuração no .env arquivo:
QUEUE_CONNECTION=databaseDepois de fazer isso, criei a tabela para armazenar os trabalhos executando php artisan queue:table && php artisan migrate.
Agora que toda a parte administrativa já está resolvida, é hora de começar a criar nossas notificações. Precisarei enviar uma frase simples sempre que uma condição for acionada. Eu poderia ter criado uma notificação para cada mensagem, mas, para agilizar o processo, criei uma única notificação que aceita uma string em app/Notifications/FreeText.php com o seguinte conteúdo:
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
class FreeText extends Notification implements ShouldQueue
{
use Queueable, ShouldQueue;
protected $text;
protected $channel;
public function __construct($text, $channel)
{
$this->text = $text;
$this->channel = $channel;
}
public function via($notifiable)
{
return [];
}
}
Isso define uma notificação, mas nosso aplicativo ainda não sabe como enviá-la. Precisamos preencher o via método e implementar quaisquer to* métodos da notificação. Para enviar essas notificações, vamos usar o nexmo/laravel-notification , que nos permite implementar os seguintes métodos em nossa notificação:
toNexmoWhatsApptoNexmoFacebooktoNexmoViberServiceMessagetoNexmoSms
Vamos implementar e toNexmoFacebook adicionando o seguinte à notificação:
public function toNexmoFacebook($notifiable)
{
return (new \Nexmo\Notifications\Message\Text)
->content($this->text);
}
Além de implementar esses métodos, precisamos informar ao Laravel como encaminhar a mensagem. Normalmente, você usaria a $notifiable entidade passada para o método para determinar como o usuário deseja ser contatado. Neste caso, vamos responder no canal pelo qual recebemos a mensagem. Esse canal é passado para o construtor da notificação. É assim que meu via método fica com essas alterações:
public function via($notifiable)
{
return [$this->channel];
}
Há uma última coisa a fazer antes que tudo isso comece a funcionar, que é fornecer algumas credenciais de autenticação da Vonage e a configuração para o envio pelo Messenger. Se você quiser fazer o mesmo, crie um aplicativo no painel do Vonage e adicione o seguinte ao seu .env arquivo:
NEXMO_APPLICATION_ID="YOUR_APPLICATION_ID"
NEXMO_PRIVATE_KEY=./private.key
NEXMO_FROM_MESSENGER="FACEBOOK_PAGE_ID"As alterações feitas nesta seção estão descritas em este commit
Envio de atualizações para o Facebook
Agora que já fizemos todo o trabalho pesado, a última coisa a fazer é enviar as ações que precisam ser realizadas para preparar a receita.
Ao receber uma mensagem de um usuário, precisamos extrair o canal pelo qual a mensagem foi enviada e o ID do usuário que nos enviou a mensagem. Assim que tivermos essas informações, podemos criar uma nova Notificação sob demanda usando essas informações:
// The incoming message contains the platform + contact details that
// we need to reply with, so configure a notification route with those
// details
$from = $request->input('from');
// The Vonage Messages API returns messenger, but our channel names are all prefixed with nexmo-
$channel = 'nexmo-' . $from['type'];
$sender = Notification::route($channel, $from['id']);
Nesse momento, podemos enviar qualquer texto que quisermos ao usuário. A primeira coisa que precisamos verificar é se a mensagem que ele nos enviou contém o nome de uma receita. Se não contiver, enviamos uma mensagem informando que não foi possível encontrar essa receita.
// Try and find the recipe name that was sent to us
$recipeName = $request->input('message.content.text');
$recipe = \App\Recipe::where('name', $recipeName)->first();
if (!$recipe) {
$sender->notify(new FreeText(
"I couldn't find that recipe",
$channel
));
return;
}
Se passarmos por esse bloco de código, significa que temos uma receita válida, e é hora de programar algumas notificações! Cada conjunto de horários em uma receita tem um action e um start_time em segundos, começando em zero. Felizmente, o Laravel nos permite adiar uma notificação por um determinado número de segundos a partir de agora, o que o torna a opção perfeita para o nosso caso de uso.
A parte final do nosso inboundMessage método precisa percorrer cada um timing e agendar uma nova notificação:
foreach ($recipe->timings()->get() as $t) {
$sender->notify((new FreeText(
$t->action,
$channel
))->delay($t->start_time));
}
Resumindo, nosso inboundMessage método fica assim:
public function inboundMessage(Request $request) {
\Log::debug('Inbound Message', $request->all());
$from = $request->input('from');
// The Vonage API returns messenger, but our channel names are all prefixed with nexmo-
$channel = 'nexmo-' . $from['type'];
$sender = Notification::route($channel, $from['id']);
// Try and find the recipe name that was sent to us
$recipeName = $request->input('message.content.text');
$recipe = \App\Recipe::where('name', $recipeName)->first();
if (!$recipe) {
$sender->notify(new FreeText(
"I couldn't find that recipe",
$channel
));
return;
}
// If we get this far, we have a recipe! Time to schedule some notifications
foreach ($recipe->timings()->get() as $t) {
$sender->notify((new FreeText(
$t->action,
$channel
))->delay($t->start_time));
}
}
As alterações feitas nesta seção estão descritas em este commit
Executando o aplicativo
Agora que tudo já está pronto, é hora de rodar a aplicação final! Aqui está uma lista rápida de tudo o que precisei fazer para que tudo funcionasse:
Correr
php artisan serveCertifique-se de que
ngrok http 8000de que ele esteja em execução para que a Vonage possa fazer chamadas para meu aplicativoExecute
php artisan queue:workpara monitorar as tarefas que estão sendo inseridas no banco de dadosVisite minha página no Facebook e envie uma receita (nesse caso,
Christmas Dinner!)Sente-se e relaxe, sabendo que receberei uma mensagem quando houver algo que eu precise fazer
Se você quiser ver o projeto completo desta postagem, pode encontrá-lo no GitHub. Se quiser executá-lo por conta própria, você precisará:
Vincular uma página do Facebook ao Vonage
Crie uma nova aplicação da Vonage e associe sua página a essa aplicação
Configure seus webhooks
Clone o repositório
Atualizar
.envcom suas credenciais da VonageCorrer
composer installCorrer
php artisan migrate && php artisan db:seedExecutar
php artisan serveephp artisan queue:workem terminais separadosEnvie uma mensagem para a sua página do Facebook
E agora, para onde vamos?
Bem, foi divertido! Não só pude experimentar a Messages API da Vonage , como também aprendi muito sobre notificações no Laravel (incluindo como criar novos canais). Como bônus extra, vou até ter um pequeno auxiliar para me lembrar quando as coisas precisam acontecer no dia de Natal!
Compartilhar:
Michael é um engenheiro de software poliglota, empenhado em reduzir a complexidade dos sistemas e torná-los mais previsíveis. Trabalhando com diversas linguagens e ferramentas, ele compartilha seus conhecimentos técnicos com públicos de todo o mundo em grupos de usuários e conferências. No dia a dia, Michael é ex-representante de desenvolvedores da Vonage, onde dedicava seu tempo a aprender, ensinar e escrever sobre todos os tipos de tecnologia.