Skip to main content
LadeStack LogoLadeStack
Architecture 4 min de leitura 2 de setembro de 2024

REST vs GraphQL: Escolhendo o Modelo Ideal de API para Ambientes de Produção

Avaliação arquitetural aprofundada comparando REST e GraphQL. Cache HTTP em redes CDN, otimização de payload, resolução do problema N+1 e o padrão DataLoader.

Comparativo Arquitetural entre REST e GraphQL

O debate em torno da escolha entre REST (Representational State Transfer) e GraphQL amadureceu além de disputas conceituais para se consolidar como uma criteriosa avaliação de engenharia, pautada em padrões reais de acesso a dados, estratégias de cache e heterogeneidade de clientes. Tratar o GraphQL como um substituto universal para o REST desconsidera premissas operacionais profundas de cada arquitetura.

Neste artigo, avaliamos o modelo orientado a recursos do REST frente ao modelo orientado a grafos do GraphQL, desvendamos como erradicar o problema N+1 com o DataLoader e analisamos o comportamento do cache HTTP em borda (Edge CDNs).


Modelos Arquiteturais: Recursos vs Grafos

Ambas as abordagens tratam a distribuição de dados sob óticas complementares, porém opostas:

REST (Orientado a Recursos):
GET /api/v1/users/42          ──► [Dados do Usuário]
GET /api/v1/users/42/orders   ──► [Lista de Pedidos]
GET /api/v1/products/808      ──► [Detalhes do Produto]
(Múltiplas idas e voltas na rede ou endpoints compostos inchados)

GRAPHQL (Orientado a Grafos):
POST /graphql
{
  user(id: "42") {
    name
    orders { id total product { title price } }
  }
}                             ──► [Payload sob medida em uma única ida e volta]

O Modelo REST

Estrutura o sistema em recursos isolados, identificados por URIs estáveis e manipulados por métodos HTTP padrão (GET, POST, PUT, DELETE).

  • Pontos Fortes: Aderência natural ao protocolo HTTP, ecossistema maduro, URLs determinísticas e integração imediata com redes CDN.
  • Pontos Fracos: Tendência ao Over-fetching (recebimento de dados desnecessários) e ao Under-fetching (múltiplas requisições em cascata para compor uma única tela).

O Modelo GraphQL

Introduz um esquema estático fortemente tipado e uma linguagem de consulta declarativa, permitindo que a aplicação consumidora solicite estritamente os campos necessários.

  • Pontos Fortes: Erradicação de tráfego excedente, consolidação de relacionamentos complexos em uma única requisição e contrato rigoroso de interface.
  • Pontos Fracos: Perda do cache HTTP baseado em rotas, vulnerabilidade a consultas profundamente aninhadas e risco crônico do gargalo N+1.

O Campo de Batalha do Cache: Edge CDN vs Cache Normalizado de Cliente

Em cenários com alto volume de leituras simultâneas, a eficiência do cache determina o custo e a escalabilidade do sistema.

REST: Cache de Borda Gratuito via CDNs

Como requisições de leitura no REST utilizam URIs individuais com o método GET, nós de borda (Cloudflare, AWS CloudFront) realizam o cache das respostas sem esforço:

HTTP/1.1 200 OK
Cache-Control: public, max-age=3600, stale-while-revalidate=60
ETag: W/"33a64df551425fcc55e4d42a148795d9f25f89d4"
Content-Type: application/json

Uma resposta atendida diretamente na borda é resolvida em milissegundos, poupando totalmente os servidores de aplicação e as instâncias de banco de dados.

GraphQL: A Complexidade das Requisições POST

Como consultas GraphQL são tradicionalmente transmitidas via HTTP POST para um endpoint único (/graphql), proxies intermediários não conseguem validar o frescor dos dados avaliando apenas o caminho da URL. As aplicações clientes precisam manter caches normalizados em memória (Apollo Client) ou utilizar consultas persistidas automatizadas (APQ).


Eliminando o Problema N+1 com DataLoader

Em servidores GraphQL com implementação ingênua, a resolução de relacionamentos aninhados dispara dezenas de consultas consecutivas ao banco (problema N+1). A solução arquitetural padrão é o agrupamento em lote (batching) com o DataLoader:

import DataLoader from 'dataloader';
import { db } from './database';

interface Order {
  id: string;
  userId: string;
  total: number;
}

export function createOrderLoader() {
  return new DataLoader<string, Order[]>(async (userIds: readonly string[]) => {
    // Unifica em uma única consulta SQL: SELECT * FROM orders WHERE user_id = ANY($1)
    const orders = await db.query(
      `SELECT * FROM orders WHERE user_id = ANY($1)`,
      [userIds]
    );

    const orderMap = new Map<string, Order[]>();
    for (const userId of userIds) {
      orderMap.set(userId, []);
    }
    for (const order of orders) {
      orderMap.get(order.userId)?.push(order);
    }

    return userIds.map((id) => orderMap.get(id) || []);
  });
}

Critérios de Decisão para Produção

Escolha REST quando:

  1. APIs Públicas e Integração de Terceiros: Desenvolvedores externos conectam-se utilizando bibliotecas HTTP universais sem necessidade de ferramental GraphQL.
  2. Cargas Massivas de Leitura com Amplo Cache em CDN: Portais de notícias, catálogos públicos de comércio eletrônico e plataformas de conteúdo.
  3. Manipulação de Arquivos Binários: Uploads multipart de vídeos, imagens de alta resolução e processamento de documentos PDF.

Escolha GraphQL quando:

  1. Ambiente Multi-Plataforma Heterogêneo (Mobile / Web / Wearables): Cada cliente necessita de conjuntos de atributos rigorosamente customizados.
  2. Dashboards e Telas de Gestão Relacional: Interfaces que unificam dados de múltiplos microsserviços em uma única visualização.
  3. Agilidade em Ciclos de Produto no Frontend: O time de interface pode adicionar campos às telas sem demandar alterações imediatas no backend.

More Engineering Articles