Olá, pessoal. Tudo bem?
No final do ano passado (2018), a AWS disponibilizou no serviço de API Gateway, a possibilidade de utilizarmos Websockets. A ideia neste post é apresentarmos alguns conceitos desta tecnologia bem bacana.
Porque usar o API Gateway e Websockets?
Apesar de existirem diversas tecnologias que gerenciam todo o ciclo de vida de websockets, alguns problemas, principalmente relacionados a infraestrutura (como disponibilidade e otimização de recursos), são mais complexos de serem abordados.
O API Gateway, por ser serverless, elimina basicamente toda a preocupação que teríamos com a infraestrutura, e oferece uma forma simples e prática de interação entre cliente e servidor. Além de evitar qualquer ociosidade de hardware, o que implica em redução de custos.
Como funciona?
Diferentemente do API Gateway usando REST, a versão com Websockets introduz um novo conceito chamado route (rota), que tem a responsabilidade de identificar como aquela mensagem será tratada.
Existem três rotas padrões, que são extremamente importantes:
- $connect: Se houver uma nova conexão, está rota será utilizada. Neste processo é gerado um ConnectionId, que deve ser armazenado para podermos identificar o cliente do lado do servidor (geralmente para enviar respostas ou gerir a conexão);
- $disconnect: Sempre que a API identificar que uma conexão foi encerrada, está rota será executada;
- $default: Quando não for possível identificar a rota em uma mensagem, ela será encaminhada para a rota padrão (default).
Para ter uma ideia melhor de como tudo funciona, vamos criar uma Web API.
Criando a WebAPI
Quando uma nova API é criada usando websockets, veremos um campo chamado Route Selection Expression. Neste campo devemos informar a expressão que irá identificar o que será o identificador da rota, dentro das mensagens recebidas.

Como exemplo, poderíamos utilizar o valor $request.body.route no Route Selection Expression. Uma mensagem com o body abaixo estaria no padrão para ser roteada por esta API.
{
"route": "myRoute",
"message": {
"id": 123,
"content": "anything"
}
}
Isso fará com que esta mensagem seja encaminhada para a rota myRoute. No diagrama abaixo, temos uma exemplo de como as rotas são endereçadas.

Ok, mas como definimos uma rota?
Boa pergunta. É bem simples.
Depois de criarmos a api, devemos selecionar o menu Routes, digitar o nome da rota (onde diz New Route Key) e confirmar.

Feito isto, teremos a rota criada e algumas opções de integração. Para este exemplo, iremos selecionar Lambda Function.

Não entrarei nos detalhes da criação da Lambda neste post, mas é possível encontrar uma excelente documentação aqui.
Algumas informações importantes que deveremos considerar ao criar uma rota integrando a AWS Lambda:
- Use Lambda Proxy Integration: Identifica se a mensagem será encaminhada na íntegra à Lambda. Caso não seja utilizado, podemos definir um template de transformação da mensagem, para simplificar e tornar o modelo mais coeso. Idêntico ao disponível no API Gateway com REST;
- Lambda Region: A region onde está a Lambda que será invocada por esta rota;
- Lambda Function: Identifica a Lambda Function;
- Invoke with caller credentials: Se marcado, usará credenciais recebidas na request;
- Execution Role: Permite informar o ARN de uma role para invocar a função Lambda;
- Use default timeout: Indica se será usado o timeout padrão de 29 segundos;
- Custom Timeout: Caso não seja usado o valor padrão, permite informar um valor customizado para o timeout.
Como enviar uma resposta do servidor para o cliente?
Quando a Lambda (ou outro serviço) precisar encaminhar uma resposta para algum dos clientes, é possível enviar um HTTP POST para o endpoint @connections do API Gateway. O @connections, permite interagirmos com os clientes conectados, usando métodos HTTP:
- GET: Obtém o status da conexão;
- POST: Envia uma mensagem para um cliente;
- DELETE: Desconecta um cliente.
Como exemplo podemos enviar a mensagem “Hello WebSockets!” para o endereço abaixo:
https://myapi.execute-api.us-east-1.amazonaws.com/stage/@connections/connectionId
Reforçando o que foi dito sobre o ID da conexão (connectionId) no início deste post, é necessário armazená-lo para usarmos nestas situações. 🙂
Para ilustrar um pouco melhor como funciona essa resposta, abaixo segue mais um diagrama.

Importante: Para utilizar o @connections, precisamos autorizar as requisições através do Signature Version 4.
Por hoje era isso, pessoal! Já utilizou websockets com o API Gateway? Deixe sua experiência nos comentários!
Abraços, e até a próxima.