Trabalhando com GraphQL em Flutter -GraphQLProvider (Parte 2)

GraphQLProvider na Prática

Igor L Sambo💙🇲🇿
GDG Maputo
7 min readNov 6, 2021

--

Após perceber sobre o que se trata o GraphQL como tecnologia, em especial os problemas que ele vem resolver do REST, é agora hora de colocar a mão na massa e implementar usando o nosso Framework — Flutter. E para isso iremos recorrer ao GraphQL Provider, parte do plugin graphql_flutter.

Para hoje o cardápio é:

  • O que é o grahql_flutter?
  • Prática
  • Resultado Final

É importante ressalvar que este artigo é parte de uma série de dois artigos:

  1. Trabalhando com GraphQL em Flutter — Introdução à GraphQL
  2. Trabalhando com GraphQL em Flutter — GraphQLProvider na prática (este artigo)

Para começar a nossa jornada com o GraphQLProvider é importante notar alguns pontos:

É importante notar aqui que ambas tecnologias, o Flutter e GraphQL aquando de sua aparição “revolucionaram” em suas áreas de foco e com isso, é de esperar que combinadas sejam uma ferramenta super poderosa, como igualmente referenciado acerca do GraphQL no artigo anterior.

O que é o grahql_flutter?

Como antes dito, este é um plugin que nos dá acesso a APIs e widgets que nos permitem aceder e modificar informação vinda de um servidor GraphQL pelo Flutter.
Com o mesmo nós podemos realizar as mais diversas operações do GraphQL, desde uml simples query a subscriptions.
Alguns pontos importantes a considerar quando trabalhar com o mesmo são:

  • HttpLink — permite-nos criar uma URI para aceder ao nosso graphql server.
  • GraphQLProvider — como provider ele é um widget responsável por permitir que as operações sejam possíveis para o cliente.
  • GraphQLClient — responsável por pegar/manipular as requisições feitas por meio de uma query ou mutation.
  • GraphQLCache — incorpora a funcionalidade de cache, guardando o resultado das queries e mutations efectuadas.

Sabendo isto, já estamos prontos para seguir adiante!

Vamos a prática

Vou assumir aqui que o projecto em si já foi criado e seguiremos com a implementação directa do GraphQLProvider.

Preparando o ambiente — GraphQLProvider

  1. Adicionar o plugin ao projecto

O primeiro passo para trabalhar com qualquer plugin, seguir para o nosso yaml file e adicionar a dependência, ou uma melhor alternativa, correr um comando que adiciona automaticamente a mais nova versão do nosso plugin, abaixo encontre as duas opções.

a. Directo no pubspec.yaml

dependencies:
graphql_flutter: ^ultima_versao

b. Pela linha de comando

$ flutter pub add graphql_flutter

E poderá ver o graphql_flutter adiconado em seu pubspec.yaml.

2. Adicionar o GraphQLProvider em nossa aplicação

a. Importar o plugin em nosso main.dart

import 'package:graphql_flutter/graphql_flutter.dart';

b. De seguida, em nossa classe de entrada, usar o GraphQLProvider widget antes mesmo do MaterialApp, assim

Como podemos notar em vez de retornar o MaterialApp a nossa State class retorna o GraphQLProvider.

c. Devemos igualmente (devia ser o b.) incluir a inicialização do Hive que é uma dependência do graphql_flutter para persistir dados aquando da execução das demais operações.

void main() async {
await initHiveForFlutter();
runApp(MyApp());
}

3. Mas o que é o client?

Para os menos distraídos foi possível notar a presença de um elemento desconhecido, o client como parâmetro do nosso Widget. Esta é uma instância do ValueNotifier, responsável por escutar as operações e resultados respectivos dos serviços do nosso GraphQL Server e os usar para dar a conhecer a nossa aplicação, e por isso que o GraphQLProvider encontra-se colocado antes do MaterialApp, assim, qualquer operação que nós fizermos será reflectida de qualquer ponto da aplicação para outro, assim como directo do GraphQL Server.

E por fim, teremos o nosso projecto pronto para trabalhar com o GraphQL por meio do GraphQLProvider.

Efectuando Operações — GraphQLClient

Para efectuar as nossas operações vamos trabalhar directamente com o nosso GraphQLClient, por onde iremos passar os pedidos e recolher a informação, para o nosso exemplo como já podemos ter notado iremos trabalhar com um simples endpoint que nos trás continentes e dos mesmos iremos efectuar uma query simples para receber os dados e igualmente duas operações de mutations.

  1. Query

Do lado do flutter não apenas representa uma operação, mas também um widget que funciona como um StreamBuilder, fazendo o build de um widget por baixo do mesmo. Mas além deste comportamento apresenta alguns elementos extra:

a. QueryOptions — representa todas as configurações para a query que nós pretendemos fazer, desde a instrução em si até gestão de falha, entre outras. Algumas propriedades a destacar são:

  • o document que permite passar a consulta como String pelo objecto gql, é por isso importante que tenhamos uma noção sobre o GraphQL para escrever estas consultas;
  • variables que no caso de existir alguma variável adicional, suponhamos que para o nosso exemplo de continentes, queremos apenas que iniciam com uma certa sequência de Strings, é por este atributo que nós passamos;
  • pollInterval que é por onde passamos o tempo que nós queremos que o nosso cliente faça o refetch dos dados do server.

b. Builder — é onde toda a ciência do Flutter e a (re)construção de widgets acontece, similar ao que acontece com o StreamBuilder, como antes apontado.

Podemos notar aqui alguns elementos desconhecidos do StreamBuilder, falaremos dos mesmos:

  • QueryResult como o nome sugere, este carrega o resultado da nossa query, assim como em um request em REST nós teríamos o nosso resultado após fazer o pedido (aqui no caso é pelo nosso queryOptions) e dependendo da situação da resposta nos trará os dados requeridos ou então uma excepção. E como um QuerySnapshots também podemos observar o seu estado, podendo validar se tem alguma exceção ou se ainda a carregar, e por sinal não temos hasData, mas podemos validar pelos próprios dados através do queryResult.data;
  • FetchMoreOptions e ReFetch dão-nos a possibilidade de pegar mais dados sem fazer override dos dados já existentes em cache e em caso de enfrentarmos alguma dificuldade podemos implementar o refetch para recarregar os dados do server, respectivamente.

2. Mutations

Como widget o Mutation não foge muito daquilo que é o Query (widget), possuindo alguns dos mesmos elementos, e variando mais na sua implementação. Vamos perceber agora, especificando:

a. MutationOptions — igual ao QueryOptions carrega também alguns atributos que ajudam a executar as mutations, e para além do document destacam-se:

  • update se recordamos o GraphQLProvider faz uso do cache e ValueNotifier para popular a nossa aplicação, quando uma mutation ocorre, é necessário que a cache seja actualizada, isso apenas se houver alguma alteração nos dados, e essa tarefa está a cargo do update(onMutationUpdate);
  • onCompleted informar ao utilizador da finalização da operação.

b. Builder — para além do que acontece na Query aqui nós temos a chance de correr uma Mutation através da acção do utilizador, visto que estas dependem mais da mutação dos dados, seja uma actualização ou remoção.

A forma como nós usamos o runMutation seria a mesma implementação para o variables do Query. E o document da Mutation incluirá atributos e argumentos para ser populados com dados específicos para cada operação,(afinal de contas não queremos um delete sem where), e ficamos com algo assim:

Após montar o cenário para pegar os dados, no caso a lista de continentes da nossa base de dados e implementar duas mutations, uma para apagar um continente específico e outra para adicionar um continente, nós temos algo como:

Resultado Final

Conclusão

Após escrever esta aplicação simples pude notar que não fiz uso de uma estrutura do meu código que costuma ser muito necessário quando trabalho com requisições externas, os serviços, é onde eu escrevo o código necessário para tratar as requisições e passar apenas a resposta para o Widget, podia também fazer aqui, mas geralmente esta segregação é feita para evitar um códigos super desorganizado, cheio de URI e verificações a voarem de um lado para o outro e se compararmos, os widgets acabam por ser similares, pois devemos também validar seja com o FutureBuilder ou StreamBuilder após segregar os serviços por si.

Isto, para dizer que o GraphQL elimina um certo nível de complexidade, para realizar todas as operações, usamos um único endpoint, bastando apenas saber que dados precisamos e que operação pretendemos fazer está tudo pronto para correr, não há que falhar a url de um serviço , pois este é o mesmo.

Notas adicionais

  • O serviço externo é gerenciado pelo hasura, junto com um schema simples com a base de dados de continentes pública.
  • Não vai ser possível este exemplo em particular sem ter a chave hash para o meu graphQL server. Podendo pedir acesso a mesma pelo meu twitter.
  • O projecto completo pode ser clonado pelo github.

Espero que tenha aprendido com este artigo e que se tenha divertido enquanto lia.

Obrigado por acompanhar até ao fim e espero por você no próximo artigo.

Para questões e sugestões esteja a vontade para tal nos comentários, email igorlsambo1999@gmail.com ou twitter @lsambo02.

Obrigado e até ao próximo artigo!!!

--

--