Como construir um aplicativo em tempo real com assinaturas GraphQL no Postgres
Publicados: 2022-03-10Neste artigo, veremos os desafios envolvidos na criação de aplicativos em tempo real e como as ferramentas emergentes estão lidando com eles com soluções elegantes e fáceis de raciocinar. Para fazer isso, construiremos um aplicativo de pesquisa em tempo real (como uma pesquisa do Twitter com estatísticas gerais em tempo real) apenas usando Postgres, GraphQL, React e nenhum código de backend!
O foco principal será a configuração do back-end (implantação de ferramentas prontas para uso, modelagem de esquema) e aspectos de integração de front-end com GraphQL e menos em UI/UX do front-end (algum conhecimento de ReactJS ajudará). A seção do tutorial terá uma abordagem de pintura por números, então vamos apenas clonar um repositório do GitHub para a modelagem do esquema e a interface do usuário e ajustá-lo, em vez de construir o aplicativo inteiro do zero.
Todas as coisas GraphQL
Você sabe tudo o que precisa saber sobre GraphQL? Se você tiver suas dúvidas, Eric Baer o cobre com um guia detalhado sobre suas origens, suas desvantagens e o básico de como trabalhar com ele. Leia um artigo relacionado →
Antes de continuar lendo este artigo, gostaria de mencionar que um conhecimento prático das seguintes tecnologias (ou substitutos) é benéfico:
- ReactJS
Isso pode ser substituído por qualquer estrutura de front-end, Android ou IOS, seguindo a documentação da biblioteca cliente. - Postgres
Você pode trabalhar com outros bancos de dados, mas com ferramentas diferentes, os princípios descritos neste post ainda se aplicam.
Você também pode adaptar este contexto de tutorial para outros aplicativos em tempo real com muita facilidade.

Conforme ilustrado pela carga útil do GraphQL na parte inferior, há três recursos principais que precisamos implementar:
- Busque a pergunta da enquete e uma lista de opções (canto superior esquerdo).
- Permitir que um usuário vote em uma determinada pergunta da enquete (o botão "Votar").
- Busque os resultados da enquete em tempo real e exiba-os em um gráfico de barras (canto superior direito; podemos passar por cima do recurso para buscar uma lista de usuários atualmente online, pois é uma réplica exata deste caso de uso).
Desafios com a criação de aplicativos em tempo real
Construir aplicativos em tempo real (especialmente como desenvolvedor front-end ou alguém que recentemente fez uma transição para se tornar um desenvolvedor fullstack) é um problema de engenharia difícil de resolver. Geralmente é assim que os aplicativos contemporâneos em tempo real funcionam (no contexto do nosso aplicativo de exemplo):
- O frontend atualiza um banco de dados com algumas informações; O voto de um usuário é enviado para o backend, ou seja, pesquisa/opção e informações do usuário (
user_id
,option_id
). - A primeira atualização aciona outro serviço que agrega os dados da enquete para renderizar uma saída que é retransmitida de volta ao aplicativo em tempo real (toda vez que um novo voto é lançado por alguém; se isso for feito com eficiência, apenas os dados da enquete atualizada são processados e apenas os clientes que se inscreveram nesta enquete são atualizados):
- Os dados de votação são processados primeiro por um serviço
register_vote
(suponha que alguma validação aconteça aqui) que aciona um serviçopoll_results
. - Os dados de pesquisa agregados em tempo real são retransmitidos pelo serviço
poll_results
ao frontend para exibir estatísticas gerais.
- Os dados de votação são processados primeiro por um serviço

Esse modelo é derivado de uma abordagem tradicional de construção de API e, consequentemente, apresenta problemas semelhantes:
- Qualquer uma das etapas sequenciais pode dar errado, deixando o UX suspenso e afetando outras operações independentes.
- Requer muito esforço na camada da API, pois é um único ponto de contato para o aplicativo front-end, que interage com vários serviços. Ele também precisa implementar uma API em tempo real baseada em websockets – não há um padrão universal para isso e, portanto, vê suporte limitado para automação em ferramentas.
- O aplicativo front-end é obrigado a adicionar o encanamento necessário para consumir a API em tempo real e também pode ter que resolver o problema de consistência de dados normalmente visto em aplicativos em tempo real (menos importante em nosso exemplo escolhido, mas crítico na ordenação de mensagens em um ambiente real). -time aplicativo de bate-papo).
- Muitas implementações recorrem ao uso de bancos de dados não relacionais adicionais no lado do servidor (Firebase, etc.) para facilitar o suporte à API em tempo real.
Vamos dar uma olhada em como o GraphQL e as ferramentas associadas abordam esses desafios.
O que é GraphQL?
GraphQL é uma especificação para uma linguagem de consulta para APIs e um runtime do lado do servidor para executar consultas. Essa especificação foi desenvolvida pelo Facebook para acelerar o desenvolvimento de aplicativos e fornecer um formato de acesso a dados padronizado e independente de banco de dados. Qualquer servidor GraphQL compatível com a especificação deve suportar o seguinte:
- Consultas para leituras
Um tipo de solicitação para solicitar dados aninhados de uma fonte de dados (que pode ser um ou uma combinação de um banco de dados, uma API REST ou outro esquema/servidor GraphQL). - Mutações para gravações
Um tipo de solicitação para gravação/retransmissão de dados nas fontes de dados acima mencionadas. - Assinaturas para consultas ao vivo
Um tipo de solicitação para que os clientes assinem atualizações em tempo real.
O GraphQL também usa um esquema tipado. O ecossistema tem muitas ferramentas que ajudam a identificar erros em tempo de desenvolvimento/compilação, o que resulta em menos bugs de tempo de execução.
Veja por que o GraphQL é ótimo para aplicativos em tempo real:
- As consultas ao vivo (assinaturas) são uma parte implícita da especificação do GraphQL. Qualquer sistema GraphQL precisa ter recursos de API em tempo real nativos.
- Uma especificação padrão para consultas em tempo real consolidou os esforços da comunidade em torno das ferramentas do lado do cliente, resultando em uma maneira muito intuitiva de integração com as APIs do GraphQL.
O GraphQL e uma combinação de ferramentas de código aberto para eventos de banco de dados e funções sem servidor/nuvem oferecem um ótimo substrato para a criação de aplicativos nativos da nuvem com lógica de negócios assíncrona e recursos em tempo real fáceis de criar e gerenciar. Esse novo paradigma também resulta em uma ótima experiência do usuário e do desenvolvedor.
No restante deste artigo, usarei ferramentas de código aberto para criar um aplicativo com base neste diagrama de arquitetura:

Criando um aplicativo de pesquisa/votação em tempo real
Com essa introdução ao GraphQL, vamos voltar à construção do aplicativo de pesquisa conforme descrito na primeira seção.
Os três recursos (ou histórias destacadas) foram escolhidos para demonstrar os diferentes tipos de solicitações do GraphQL que nosso aplicativo fará:
- Consulta
Busque a pergunta da enquete e suas opções. - Mutação
Deixe um usuário votar. - Inscrição
Exiba um painel em tempo real para os resultados da pesquisa.

Pré-requisitos
- Uma conta Heroku (use o nível gratuito, sem necessidade de cartão de crédito)
Para implantar um back-end do GraphQL (veja o próximo ponto abaixo) e uma instância do Postgres. - Hasura GraphQL Engine (gratuito, de código aberto) Um servidor GraphQL pronto para uso no Postgres.
- Cliente Apollo (SDK gratuito e de código aberto)
Para integrar facilmente aplicativos clientes com um servidor GraphQL. - npm (gerenciador de pacotes gratuito e de código aberto)
Para executar nosso aplicativo React.
Implantando o banco de dados e um back-end GraphQL
Implementaremos uma instância do Postgres e do GraphQL Engine no nível gratuito do Heroku. Podemos usar um botão bacana do Heroku para fazer isso com um único clique.

Observação: você também pode seguir este link ou pesquisar a documentação de implantação do Hasura GraphQL para Heroku (ou outras plataformas).

Você não precisará de nenhuma configuração adicional, basta clicar no botão “Implantar aplicativo”. Quando a implantação estiver concluída, anote o URL do aplicativo:
<app-name>.herokuapp.com
Por exemplo, na captura de tela acima, seria:
hge-realtime-app-tutorial.herokuapp.com
O que fizemos até agora foi implantar uma instância do Postgres (como um complemento na linguagem Heroku) e uma instância do GraphQL Engine que está configurada para usar esta instância do Postgres. Como resultado disso, agora temos uma API GraphQL pronta para uso, mas, como não temos tabelas ou dados em nosso banco de dados, isso ainda não é útil. Então, vamos resolver isso imediatamente.
Modelando o esquema do banco de dados
O diagrama de esquema a seguir captura um esquema de banco de dados relacional simples para nosso aplicativo de pesquisa:


Como você pode ver, o esquema é simples e normalizado que aproveita as restrições de chave estrangeira. São essas restrições que são interpretadas pelo GraphQL Engine como relacionamentos 1:1 ou 1:muitos (por exemplo poll:options
é um relacionamento 1:muitos, pois cada poll terá mais de 1 opção vinculada pela restrição de chave estrangeira entre o id
da tabela de poll_id
poll
tabela de option
). Os dados relacionados podem ser modelados como um gráfico e, portanto, podem alimentar uma API GraphQL. Isso é precisamente o que o GraphQL Engine faz.
Com base no exposto, teremos que criar as seguintes tabelas e restrições para modelar nosso esquema:
-
Poll
Uma tabela para capturar a pergunta da enquete. -
Option
Opções para cada enquete. -
Vote
Para registrar o voto de um usuário. - Restrição de chave estrangeira entre os seguintes campos (
table : column
):-
option : poll_id → poll : id
-
vote : poll_id → poll : id
-
vote : created_by_user_id → user : id
-
Agora que temos nosso projeto de esquema, vamos implementá-lo em nosso banco de dados Postgres. Para trazer esse esquema instantaneamente, eis o que faremos:
- Faça download da CLI do mecanismo GraphQL.
- Clone este repositório:
$ git clone clone https://github.com/hasura/graphql-engine $ cd graphql-engine/community/examples/realtime-poll
- Vá para
hasura/
e editeconfig.yaml
:endpoint: https://<app-name>.herokuapp.com
- Aplique as migrações usando a CLI, de dentro do diretório do projeto (que você acabou de baixar por clonagem):
$ hasura migrate apply
Isso é tudo para o back-end. Agora você pode abrir o console do GraphQL Engine e verificar se todas as tabelas estão presentes (o console está disponível em https://<app-name>.herokuapp.com/console
).
Observação: você também pode ter usado o console para implementar o esquema criando tabelas individuais e adicionando restrições usando uma interface do usuário. Usar o suporte integrado para migrações no GraphQL Engine é apenas uma opção conveniente que estava disponível porque nosso repositório de exemplo tem migrações para trazer as tabelas necessárias e configurar relacionamentos/restrições (isso também é altamente recomendado independentemente de você estar criando um hobby projeto ou um aplicativo pronto para produção).
Integrando o aplicativo Frontend React com o backend GraphQL
O frontend neste tutorial é um aplicativo simples que mostra a pergunta da enquete, a opção de votar e os resultados agregados da enquete em um só lugar. Como mencionei anteriormente, primeiro vamos nos concentrar na execução deste aplicativo para que você obtenha a gratificação instantânea de usar nossa API GraphQL implantada recentemente. Veja como os conceitos do GraphQL que analisamos anteriormente neste artigo potencializam os diferentes casos de uso de tal aplicativo e, em seguida, explore como a integração do GraphQL funciona nos bastidores.
NOTA: Se você é novo no ReactJS, você pode querer conferir alguns desses artigos. Não entraremos nos detalhes da parte React do aplicativo e, em vez disso, focaremos mais nos aspectos do GraphQL do aplicativo. Você pode consultar o código-fonte no repositório para obter detalhes de como o aplicativo React foi construído .
Configurando o aplicativo front-end
- No repositório clonado na seção anterior, edite
HASURA_GRAPHQL_ENGINE_HOSTNAME
no arquivo src/apollo.js (dentro da pasta/community/examples/realtime-poll
) e defina-o para o URL do aplicativo Heroku acima:export const HASURA_GRAPHQL_ENGINE_HOSTNAME = 'random-string-123.herokuapp.com';
- Vá para a raiz do repositório/pasta do aplicativo (
/realtime-poll/
) e use npm para instalar os módulos de pré-requisito e execute o aplicativo:$ npm install $ npm start

Você deve ser capaz de brincar com o aplicativo agora. Vá em frente e vote quantas vezes quiser, você notará os resultados mudando em tempo real. Na verdade, se você configurar outra instância dessa interface do usuário e apontá-la para o mesmo back-end, poderá ver os resultados agregados em todas as instâncias.
Então, como este aplicativo usa o GraphQL? Leia.
Nos bastidores: GraphQL
Nesta seção, exploraremos os recursos do GraphQL que alimentam o aplicativo, seguidos por uma demonstração da facilidade de integração no próximo.
O componente de pesquisa e o gráfico de resultados agregados
O componente de enquete no canto superior esquerdo que busca uma enquete com todas as suas opções e captura o voto de um usuário no banco de dados. Ambas as operações são feitas usando a API GraphQL. Para buscar os detalhes de uma enquete, fazemos uma consulta (lembra disso da introdução do GraphQL?):
query { poll { id question options { id text } } }
Usando o componente Mutation do react-apollo
, podemos conectar a mutação a um formulário HTML de forma que a mutação seja executada usando as variáveis optionId
e userId
quando o formulário for enviado:
mutation vote($optionId: uuid!, $userId: uuid!) { insert_vote(objects: [{option_id: $optionId, created_by_user_id: $userId}]) { returning { id } } }
Para mostrar os resultados da pesquisa, precisamos derivar a contagem de votos por opção dos dados na tabela de votos. Podemos criar um Postgres View e rastreá-lo usando o GraphQL Engine para disponibilizar esses dados derivados no GraphQL.
CREATE VIEW poll_results AS SELECT poll.id AS poll_id, o.option_id, count(*) AS votes FROM (( SELECT vote.option_id, option.poll_id, option.text FROM ( vote LEFT JOIN public.option ON ((option.id = vote.option_id)))) o LEFT JOIN poll ON ((poll.id = o.poll_id))) GROUP BY poll.question, o.option_id, poll.id;
A visualização poll_results
une os dados das tabelas de vote
e poll
para fornecer uma contagem agregada do número de votos por cada opção.
Usando as assinaturas do GraphQL sobre essa visualização, react-google-charts e o componente de assinatura de react-apollo
, podemos conectar um gráfico reativo que é atualizado em tempo real quando ocorre uma nova votação de qualquer cliente.
subscription getResult($pollId: uuid!) { poll_results(where: {poll_id: {_eq: $pollId}}) { option { id text } votes } }
Integração da API GraphQL
Como mencionei anteriormente, usei o Apollo Client, um SDK de código aberto para integrar um aplicativo ReactJS ao back-end do GraphQL. O Apollo Client é análogo a qualquer biblioteca de cliente HTTP, como solicitações para python, o módulo http padrão para JavaScript e assim por diante. Ele encapsula os detalhes de como fazer uma solicitação HTTP (neste caso, solicitações POST). Ele usa a configuração (especificada em src/apollo.js
) para fazer solicitações de consulta/mutação/assinatura (especificada em src/GraphQL.jsx com a opção de usar variáveis que podem ser substituídas dinamicamente no código JavaScript do seu aplicativo REACT) para um ponto final do GraphQL. Ele também aproveita o esquema tipado por trás do endpoint GraphQL para fornecer validação de tempo de compilação/desenvolvimento para as solicitações mencionadas. Vamos ver como é fácil para um aplicativo cliente fazer uma solicitação de consulta ao vivo (assinatura) para a API GraphQL.
Configurando o SDK
O Apollo Client SDK precisa ser apontado para um servidor GraphQL, para que possa lidar automaticamente com o código clichê normalmente necessário para essa integração. Então, foi exatamente isso que fizemos quando modificamos src/apollo.js ao configurar o aplicativo front-end.
Fazendo uma solicitação de assinatura do GraphQL (consulta ao vivo)
Defina a assinatura que analisamos na seção anterior no arquivo src/GraphQL.jsx :
const SUBSCRIPTION_RESULT = ` subscription getResult($pollId: uuid!) { poll_results ( order_by: option_id_desc, where: { poll_id: {_eq: $pollId} } ) { option_id option { id text } votes } }`;
Usaremos esta definição para conectar nosso componente React:
export const Result = (pollId) => ( <Subscription subscription={gql`${SUBSCRIPTION_RESULT}`} variables={pollId}> {({ loading, error, data }) => { if (loading) return
Carregando...</p>; se (erro) retornar
Erro:</p>; Retorna ( <div> <div> {renderChart(dados)} </div> </div> ); }} </Assinatura> )
Uma coisa a notar aqui é que a assinatura acima também pode ter sido uma consulta. A simples substituição de uma palavra-chave por outra nos dá uma “consulta ao vivo”, e isso é tudo o que é necessário para o Apollo Client SDK conectar essa API em tempo real ao seu aplicativo. Sempre que há um novo conjunto de dados de nossa consulta ao vivo, o SDK aciona uma nova renderização de nosso gráfico com esses dados atualizados (usando a renderChart(data)
). É isso. É realmente muito simples!
Pensamentos finais
Em três etapas simples (criando um back-end GraphQL, modelando o esquema do aplicativo e integrando o frontend com a API GraphQL), você pode conectar rapidamente um aplicativo em tempo real totalmente funcional, sem se prender a detalhes desnecessários, como configurar uma conexão websocket. Esse aí é o poder das ferramentas da comunidade apoiando uma abstração como o GraphQL.
Se você achou isso interessante e deseja explorar mais o GraphQL para seu próximo projeto paralelo ou aplicativo de produção, aqui estão alguns fatores que você pode usar para criar sua cadeia de ferramentas do GraphQL:
- Desempenho e escalabilidade
O GraphQL deve ser consumido diretamente por aplicativos front-end (não é melhor do que um ORM no back-end; benefícios reais de produtividade vêm disso). Portanto, suas ferramentas precisam ser inteligentes sobre o uso eficiente de conexões de banco de dados e devem ser dimensionadas sem esforço. - Segurança
Segue acima que um sistema de controle de acesso baseado em função maduro é necessário para autorizar o acesso aos dados. - Automação
Se você é novo no ecossistema GraphQL, escrever à mão um esquema GraphQL e implementar um servidor GraphQL pode parecer tarefas assustadoras. Maximize a automação de suas ferramentas para que você possa se concentrar nas coisas importantes, como criar recursos de front-end centrados no usuário. - Arquitetura Por mais triviais que pareçam os esforços acima, a arquitetura de back-end de um aplicativo de nível de produção pode envolver conceitos avançados do GraphQL, como costura de esquema, etc. Além disso, a capacidade de gerar/consumir facilmente APIs em tempo real abre a possibilidade de construir aplicativos resilientes e inerentemente escaláveis. Portanto, é fundamental avaliar como as ferramentas do GraphQL podem otimizar sua arquitetura.
Recursos Relacionados
- Você pode conferir uma versão ao vivo do aplicativo aqui.
- O código-fonte completo está disponível no GitHub.
- Se você quiser explorar o esquema do banco de dados e executar consultas de teste do GraphQL, faça isso aqui.