Pressione enter para ver os resultados ou esc para cancelar.

GraphQL hoje usando Apollo em aplicações que utilizam APIs REST

Apesar do entusiamo das pessoas que já usam GraphQL, a popularidade da ferramenta está crescendo a passos curtos. Desenvolvedores trabalhando no client-side das aplicações são os que mais rapidamente têm a ganhar com o GraphQL, mas poucos ainda conseguem justificar o investimento financeiro na migração de um backend em pleno funcionamento servindo uma API REST. O que poucos percebem, porém, é que não é preciso fazer a migração simultaneamente no servidor antes de começar a usar a tecnologia no client-side. A implementação de referência para servidores GraphQL é escrita em JavaScript, roda muito bem em navegadores, e é ainda mais fácil de usar quando combinada com as ferramentas fornecidas pelo Apollo.

Se você prefere Relay, pode ler esse post no blog oficial do GraphQL.

O que é Apollo?

O GraphQL é, fundamentalmente, apenas um protocolo de comunicação, e portanto existem dezenas de projetos em várias linguagens, tanto pra client-side quanto pra server-side. Já o Apollo é um conjunto de ferramentas e produtos criados pelo time de desenvolvimento do Meteor para trabalhar com GraphQl.

Dentre esses projetos, há o graphql-tools, que visa facilitar a criação de schemas executáveis, e o apollo-client, que se auto-determina “O cliente GraphQL totalmente preparado para produção e para qualquer servidor ou framework UI“. Ousado, não?

Resolvendo GraphQL queries no navegador

O primeiro problema a ser resolvido é como executar GraphQL resolvers no client-side. Sinceramente, não é muito difícil. Como mencionei anteriormente, o graphql-js funciona muito bem no ambiente de um navegador, e basta usá-la como faríamos num servidor Node.

Instalação

Vamos precisar inicialmente de duas ferramentas para construir nosso schema:

Sentindo falta do NPM no comando acima? Sugiro que você dê uma olhada no Yarn 😉

Construindo o GraphQL Schema

Vamos começar pelo início (!). Construir um schema é simples, usando o graphql-tools. Começamos por definir um schema usando a linguagem de schema do GraphQL, como segue:

O que estamos dizendo aqui é que nosso schema tem um único typo, chamado Query, e que esse tipo é o “tipo raiz”. Isso significa que os campos desse tipo são pesquisáveis no primeiro nível do schema – neste caso, o campo helloWorld, que é resolvido a uma string.

Em seguida definimos os resolvers através de um objeto que serve de mapa de resolução (resolver map) para os campos de cada tipo declarado no schema:

Veja mais informações sobre resolver maps neste guia.

Por fim, combinamos a definição do schema com os resolvers usando o método makeExecutableSchema, criando assim um schema executável:

Para manter a simplicidade, por hora vamos manter todo o código num mesmo arquivo chamado schema.js que, portanto, conterá o seguinte:

Há uma menção extensa sobre modularização do schema na documentação do Apollo. Eu mesmo tenho um projeto sobre este assunto, apesar de ele ser ainda bastante inicial: graphql-modules. Durante esse tutorial, porém, vamos manter apenas um arquivo para o schema a fim de simplificar as coisas.

Executing queries

Agora que temos um schema executável, podemos resolver queries usando o graphql-js da seguinte forma:

Perfeito! Conseguimos resolver queries de GraphQL. O código até aqui pode ser empacotado usando webpack ou qualquer outra ferramenta de empacotamento, e então executado no navegador, imprimindo o resultado no console.

Criei um repositório para servir de código de referência para este post. Ele está disponível no GitHub, e já conta com um sistema de empacotamento pré-configurado para facilitar seus testes. Baixe o projeto usando git e acesse a tag 1-hello-world para ver o código até este momento.

Usando REST nos resolvers

Agora que temos uma forma de executar queries de GraphQL no navegador, podemos seguir adiante e adicionar um schema mais realista, com resolvers que realizarão requisições REST.

Para fins de simplificar as coisas, vamos usar uma API REST para testes chamada JSONPlaceholder. Não é preciso instalá-la, está (quase) sempre disponível, e tem um schema básico de um blog, com posts, usuários, comentários, etc; exatamente o que precisamos pra fazer alguns testes com GraphQL.

Primeiro, vamos atualizar nosso schema pra adicionar os novos tipos:

Agora, atualizaremos os resolvers da seguinte forma:

Note que utilizamos a Fetch API, já disponível nos principais navegadores. Se for preciso, você pode instalar o polyfill whatwg-fetch para navegadores antigos.

Agora podemos consultar posts:

Checkpoint: 2-rest-resolvers

Ok, isso parece legal. E se quiséssemos retornar apenas um post dessa API? Fácil. Segue uma query pelo post de id igual a 1:

Agora, analisando o endpoint de posts na API de testes vemos que ela retorna um quarto campo em cada post: o userId. é chegada a hora para…

Resolvendo relacionamentos

Relacionamentos são a beleza do GraphQL mas, apesar da sua importância, fundamentalmente são apenas campos comuns. Vamos seguir adiante e adicionar o campo author no tipo Post e o campo posts no tipo User, junto dos seus resolvers:

Refrescando a memória: de uma olhada na documentação das
resolver functions para entender os argumentos que estamos usando no código acima.

Agora as coisas estão ficando interessantes. Agora podemos deixar que o GraphQL faça sua mágica, fazendo coisas como “pegar todos os posts cujo autor é o autor do post 1

Ah, isso é fantástico! Uma pausa para o café…

Enquanto isso, outro checkpoint pra você testar: 3-relationship-resolvers.

E agora, mutações!

Mutações no GraphQL são apenas mais resolvers de campos, somente com alguns comportamentos divergentes, como o fato de serem resolvidos em série, e não em paralelo, como as queries. Criar uma mutação addPost, por exemplo, será nada mais do que criar um resolver que realiza uma requisição POST, como vemos a seguir:

Um parêntese sobre o código acima: a nossa API de testes até aceita requisições POST, mas retorna como resultado apenas o id supostamente gerado. Na verdade, nenhum dado é persistido.

Uma query de mutação, então, deve ser identificada da seguinte forma:

Mais um checkpoint: 4-mutation-resolvers.

Apollo Client

Ok, entendo que executar queries estáticas se provou fácil, mas nossa aplicação precisará de mais. O próximo passo é integrar o que temos ao Apollo Client.

Instalação

Criando o client

Para criar um cliente Apollo, precisamos instanciar a classe ApolloClient. Ela recebe como argumento um objeto que contenha, pelo menos, um network interface – interface de rede – que será utilizado pelo cliente para efetuar as requisições GraphQL. Normalmente, quando numa aplicação com GraphQL em ambos client-side e server-side, criamos um network interface usando o helper createNetworkInterface, que basicamente cria uma interface de rede para realizar requisições POST contra um backend servido no mesmo domínio da aplicação em execução. Seria algo assim:

E, para executar uma query, faríamos:

Se tiver interesse, leia mais sobre a camada de network do Apollo Client.

Aqui, porém, não temos GraphQL no backend, e portanto vamos criar uma interface de rede personalizada para resolver as queries diretamente no navegador, usando o schema e os resolvers criados anteriormente. Não é algo simples, veja só:

Céus, o que está acontecendo aqui?

Primeiro, instanciamos o ApolloClient passando nosso networkInterface personalizado. Ele consiste de um objeto com o método query disponível. Esse método será chamado toda vez que uma query for ser resolvida. O método recebe um único argumento: um objeto do tipo Request Interface.

Segundo, usamos um método auxiliar disponibilizado pelo próprio apollo-client para processar o objeto de requisição e criar uma query GraphQL válida, em forma de string, similar as que estávamos definindo antes estaticamente.

Terceiro, extraímos outras informações importantes da requisição: operationName, que é o nome (opcionalmente) dado à operação; e possíveis variables que seriam fornecidas junto da query.

Por último, executamos a query contra o schema, fornecendo também um root inicial e um contexto (ambos nulos aqui, já que não precisamos deles ainda), as variáveis, e o nome da operação. A maioria dos argumentos aqui é opcional.

Trump está perplecto!

Se tiver dúvidas sobre esse último passo, dê uma olhada na documentação oficial sobre execução de queries.

Agora podemos usar nosso client como normalmente faríamos:

Último checkpoint: 5-apollo-client.

Conclusão

Isso é tudo. Espero que vocês tenham apreciado nosso devaneio no aprendizado de GraphQl e, sobretudo, espero que vocês agora sejam capazes de começar a usar GraphQL, sem mais desculpas envolvendo o pessoal do backend estar com preguiça de preparar um servidor pra você.

Cena após os créditos:

Se você está realmente só começando com GraphQL talvez você nem saiba como/onde usar esse cliente que acabamos de criar. Peço desculpas. Bom, eu imagino que se você está aqui é provável que já use React, Angular, ou mesmo Vue (se for um desenvolvedor hipster incompreendido). Se for esse o caso, tem algumas bibliotecas que vão te ajudar a seguir em frente, conectando o cliente Apollo ao seu framework favorito:

Até mais!


***
📣
Estamos contratando pessoas que desenvolvam software!
Mais informações sobre a vaga.
***