Ícone do site Taller

REST vs GraphQL – Repensando as requisições a APIs Web

Nesta série, iremos explorar alguns dos principais pontos negativos do modelo tradicional de desenvolvimento de API’s web, mais especificamente quando desejamos buscar dados no servidor, e iremos analisar de que forma o GraphQL pode nos ajudar a construir API’s mais genéricas e focadas nos tipos de clientes que irão consumi-las.

Importante!

Nós não temos a intenção de influenciá-lo a usar qualquer ferramenta ou tecnologia. Na verdade, nosso maior objetivo é fazê-lo pensar de uma forma diferente em relação à construção de API’s web. E nunca é demais lembrar: não existem balas de prata quando se trata de desenvolvimento web. E, no final das contas, você quem irá decidir o que usar, quando usar e como usar, de acordo com o problema que você tem em mãos.

Por que escolhemos o REST como ponto de comparação?…

Apesar do nível atual dos requisitos das aplicações estarem dificultando a aplicação pura do REST, o modelo sugerido por Roy Fielding ainda é a arquitetura mais utilizada como base na criação de novas API’s. Na verdade, mais do que explicitar prováveis fragilidades do paradigma REST, esta série tem como principal objetivo demonstrar como o GraphQL pode nos ajudar a contornar situações propostas por um novo cenário de requisitos.

Quando Roy Fielding publicou sua dissertação, há quase vinte anos atrás, o cenário era totalmente diferente do atual. Por exemplo, é incomparável a adoção ao uso de smartphones e internet dos dias atuais à daquela época.  E, apesar de termos evoluído em aspectos como velocidade de conexões e capacidade de armazenamento e processamento, uma enxurrada de novos requisitos surgiram: novos tipos de conexões, inúmeros dispositivos e suas diferentes formas de se conectar e exibir conteúdo, por exemplo.

Motivado pelo aumento da complexidade dos requisitos de seus aplicativos mobile, o time de desenvolvedores do Facebook lançou, em 2012, o GraphQL, a quem eles descreveram como uma Linguagem de consulta de dados, com o intuito de facilitar principalmente a vida dos desenvolvedores de produtos que iriam consumir suas APIs. Para saber mais, clique aqui.

Na primeira parte desta série, nós vamos demonstrar como a arquitetura REST pode ser limitada em alguns cenários, e como pode se tornar custoso utilizá-la para atender alguns requisitos. Para melhor contextualizar, tomaremos como base uma aplicação simples: Lista de contatos.

Abaixo, uma representação de como nossas entidades se relacionam.

E, com esta modelagem como referência, vamos idealizar a interface para a versão que será visualizada em computadores, da nossa lista de contatos:

Nesta versão, iremos exibir todos os nossos contatos. Para cada contato, iremos listar os Telefones, Endereços, E-mails e as Informações Pessoais.

Simples, não?

Então, com esta interface em mente, vamos declarar alguns endpoints. Para este exemplo, iremos utilizar o framework Express.

Com estas rotas definidas, nós podemos montar a nossa tela inicial. Vamos supor que em nossa base de dados, tenhamos apenas um contato cadastrado, e que este contato, possui um telefone, um email e um endereço associados a ele.

Bem, é aí que começam a aparecer algumas cascas de banana em nosso caminho…

Seguindo esta estrutura de rotas, e com os dados que supomos acima, para montar a nossa interface nós iremos precisar de 4 requisições: uma que busca as pessoas, e como temos apena um registro, mais três requisições para buscar seus e-mails, endereços e telefones, totalizando 4 requisições. Veja, em um cenário simples, e com uma quantidade de dados muito abaixo da realidade dos grandes sistemas, nós já conseguimos identificar que fazemos um esforço proporcionalmente maior do que o resultado que conseguimos e desejamos exibir.

Sim, existem algumas alternativas para o cenário acima, como por exemplo, inserir, dentro do método que “resolve” a url ‘/pessoas’, todos os dados relacionados a cada pessoa (e-mails, telefones e endereços), reduzindo assim a uma requisição por registro de pessoa. Porém, esta solução traz consigo vários problemas:

  1. Alto acoplamento e baixa coesão;
  2. O código tende a ficar mais difícil de manter na medida que a aplicação evolui;
  3. Uma mudança na modelagem de dados pode causar grandes dores de cabeça, só para citar alguns.

Pode ser uma solução cara, quando se trata de sistemas mais complexos, não acha?

Agora, vamos explorar mais um cenário hipotético, e bem comum: a versão mobile de nossa interface. E, como já é de se esperar, ela não irá exibir todos os dados que são exibidos na nossa versão desktop.

Como podemos ver, não iremos exibir a foto do contato nem seus endereços, e iremos exibir apenas o email e telefone principais. Os dados não exibidos na versão mobile da lista de contatos, serão exibidos na tela de detalhes do contato.

É nítido que estamos desperdiçando dados, não é? Imagine pedir uma pizza, e ter que desperdiçar alguns ingredientes por simplesmente não poder excluí-los na hora de pedir! E para nós, desenvolvedores, este é um aspecto simplesmente impossível de ignorar. A performance aqui possui um papel fundamental não somente para a experiência do usuário, mas também para a reputação de sua aplicação. Mais uma vez: estamos explorando um cenário muito simples. Imagina o que a galera do Facebook enfrentou, hein?

Fazendo outra solução paliativa…

Assim como o puxadinho que fizemos no cenário das rotas (e não soou nada legal, né?), centralizando dados relacionais em uma rota para uma entidade específica, aqui também podemos nos arriscar.

Será que se passássemos os campos que desejamos exibir, como parâmetros das URLS, nosso problema seria resolvido? Pode ser que sim, mas inevitavelmente estaríamos criando outros: e se, por conta de regras do negócio, um campo é adicionado ou removido? Ou até mesmo muda de tipo? Além de arriscado, isso pode ocasionar o surgimento de uma complexidade desnecessária tanto em seu back end como no front, para os clientes que fossem requisitar dados de sua API.

Que tal, então, criarmos endpoints específicos para atender a este tipo de dispositivo, algo do tipo:

Genial, né? Claro que não! E, se por um acaso o nosso aplicativo encontrar espaço mercado de Smart TVS? E no mercado de Smartwatches? Daria um trabalho monstruoso, além de gastarmos uma bela grana, não é?

Bem, está claro que os puxadinhos não são a solução, e apenas nos ajudariam a criar um ambiente caótico, difícil e custoso de manter e escalar.

Mas, e aí, Eric!? Qual seria a solução?

Como dissemos no início da postagem, nossa maior intenção é instigar você, leitor, a refletir sobre os problemas aqui apresentados e tentar contextualizá-los em cenários de maior escala.

Se tornou praticamente impossível desenvolver APIs web sem levar em consideração os inúmeros tipos de dispositivos que irão consumi-las.

Nas duas próximas etapas desta série, iremos introduzir os principais conceitos do GraphQL e como ele possibilita ao cliente requisitar dados de forma menos custosa, mais assertiva e contextual, evitando desperdícios e o surgimento de complexidades desnecessárias.

Espero que tenham gostado! Até mais, pessoal!

 

Sair da versão mobile