Todos os artigos
82 artigos · atualizado semanalmente Veja nossas Ferramentas
Todos os artigos
Comparativos

GraphQL vs REST: quando GraphQL vale (e quando não vale)

Overfetching, N+1, caching e complexidade operacional: por que a maioria das APIs não precisa de GraphQL, e quando ele realmente faz sentido.

COVER · Comparativos

Você leu o hype, assistiu às talks da GraphQL conf, e agora está convicto de que sua API REST está ultrapassada. Antes de migrar tudo, vale a pena entender por que a maioria das APIs que conheço — inclusive as que escalam — ainda roda em REST sem dificuldade. GraphQL resolve problemas reais, mas costuma resolver problemas que você ainda não tem.

O que é overfetching e underfetching (e por que importa de verdade)

Overfetching é quando o endpoint retorna mais campos do que o cliente precisa. Underfetching é quando ele retorna menos, e o cliente precisa fazer várias requisições para montar uma resposta completa.

Esses dois problemas existem. Mas antes de assumir que GraphQL é a solução, vale mapear o quanto eles estão custando de verdade na sua API.

Overfetching de REST normalmente é resolvido com query params simples:

GET /users/42?fields=id,name,email

Não é tão elegante quanto uma query GraphQL, mas funciona, e qualquer desenvolvedor entende sem ler documentação. Se o payload extra é de 200 bytes, provavelmente não justifica trocar a stack inteira.

Underfetching é o caso mais legítimo para GraphQL. Se o frontend precisa de dados de users, orders e products para montar uma tela, REST precisa de três requests ou de um endpoint específico de composição. GraphQL resolve isso com uma única query. Esse ganho é real — principalmente em mobile com conexão ruim.

O problema é que a maioria das aplicações tem telas com dados razoavelmente previsíveis. Se você controla o frontend e o backend, é possível criar endpoints específicos por tela (BFF — Backend for Frontend) que resolvem underfetching sem GraphQL.

O problema do N+1 (e como ele se manifesta dos dois lados)

O problema N+1 aparece quando você busca uma lista de entidades e depois faz uma query separada para cada item da lista. É o pesadelo de qualquer ORM mal configurado.

Em GraphQL, o N+1 é quase uma armadilha embutida. Se você tem um resolver de users que retorna 50 usuários, e cada usuário tem um resolver de orders, você vai disparar 50 queries de pedidos — a menos que implemente DataLoader ou alguma estratégia de batching.

// Resolver sem DataLoader — N+1 garantido
const resolvers = {
  User: {
    orders: (user) => db.orders.findAll({ where: { userId: user.id } })
  }
}

Em REST, o N+1 geralmente aparece na implementação de um endpoint de composição malfeito, mas é mais visível e mais fácil de diagnosticar porque está concentrado em um lugar.

DataLoader resolve o N+1 em GraphQL, mas é mais uma coisa para implementar, testar e manter. É complexidade que não existia antes.

Caching: onde REST leva vantagem clara

Esse é um dos pontos onde REST ganha de forma inequívoca: o modelo de cache do HTTP foi construído para requisições GET com URLs estáticas.

Um GET /products/42 é cacheável por CDN, pelo browser, por um proxy reverso. Você configura Cache-Control, ETag, e boa parte da infraestrutura já sabe o que fazer.

GraphQL envia tudo via POST para um único endpoint (/graphql). POST não é cacheável por padrão. Você pode usar persisted queries, Apollo Client com cache normalization, ou HTTP GET para queries simples — mas todos esses são workarounds para um problema que REST não tem.

Se a sua API serve conteúdo público e você quer colocar uma CDN na frente, GraphQL vai exigir trabalho extra. REST vai funcionar naturalmente.

A complexidade que ninguém menciona nos posts de introdução

GraphQL não é só "escrever queries mais flexíveis". É um sistema inteiro que você precisa operar:

Schema e tipos obrigatórios. Você precisa definir um schema fortemente tipado antes de implementar qualquer coisa. É bom para documentação, mas é overhead real no começo.

Segurança de queries. Um cliente pode enviar uma query profunda e circular que derruba seu servidor:

{
  users {
    friends {
      friends {
        friends {
          friends { id }
        }
      }
    }
  }
}

Você precisa implementar depth limiting, query complexity analysis e rate limiting por complexidade. REST tem o mesmo problema em tese, mas na prática é muito mais difícil de acionar por acidente.

Monitoramento. Com REST, você monitora endpoints. GET /users com latência alta — você sabe onde olhar. Com GraphQL, tudo vai para /graphql. Você precisa de tracing por operação (Apollo Studio, Grafana com plugins específicos) para entender o que está lendo.

Erros. GraphQL retorna HTTP 200 mesmo quando a query falhou parcialmente. Um campo pode ser null porque não existe ou porque o resolver lançou exceção. Você precisa olhar o campo errors na resposta:

{
  "data": { "user": null },
  "errors": [{ "message": "User not found", "path": ["user"] }]
}

Isso quebra o modelo mental de HTTP status codes que qualquer dev já conhece. Para referência rápida de status codes numa API REST, uso o HTTP Status Codes quando preciso confirmar a semântica correta de 204 vs 200 com corpo vazio.

Quando GraphQL faz sentido de verdade

Não sou contra GraphQL. Tenho contexto onde ele é a escolha certa:

Múltiplos clientes com necessidades diferentes. Se você tem um app mobile, um web e um parceiro externo, todos consumindo dados com formatos radicalmente diferentes, um schema GraphQL com queries flexíveis pode ser melhor do que manter três versões de endpoints REST ou um endpoint genérico que tenta servir a todos.

Produto com UI altamente dinâmica. Dashboards configuráveis pelo usuário, construtores de relatório, casos onde o cliente realmente não sabe de antemão quais campos vai precisar. Esse é o caso de uso onde a flexibilidade do GraphQL compensa o overhead.

Time grande com frontends independentes. Quando o time de iOS, o time de Android e o time web trabalham de forma relativamente independente e precisam iterar rápido sem depender do backend para cada campo novo.

Federação de microserviços. O modelo de GraphQL Federation é genuinamente poderoso para expor um grafo unificado de dados que vive em serviços distintos. Se você tem 10 microserviços e precisa de uma interface unificada para o frontend, Federation é uma solução elegante.

Quando REST basta (a maioria dos casos)

Se sua API tem recursos bem definidos com operações CRUD previsíveis, REST funciona. Se você controla o frontend, pode criar endpoints específicos por necessidade. Se a equipe não tem experiência com GraphQL, o custo de aprendizado e operação não se paga rapidinho.

Veja o post REST: princípios e boas práticas para um guia prático de como estruturar uma API REST que não vira bagunça com o tempo — antes de decidir que precisa de GraphQL porque a sua API REST atual está mal desenhada.

Uma API REST mal estruturada não é argumento para adotar GraphQL. É argumento para estruturar melhor a API REST.

Perguntas frequentes

GraphQL é mais rápido que REST?

Não necessariamente. Em redes lentas, uma query GraphQL que substitui múltiplos requests pode ser mais eficiente. Mas em requests simples, REST com cache de CDN vai ser mais rápido do que qualquer solução GraphQL. A performance depende do caso de uso — não existe resposta universal.

GraphQL é o futuro das APIs?

GraphQL existe desde 2015, foi open-sourceado pelo Facebook em 2015 e é amplamente usado. Mas o "futuro" das APIs em 2026 parece mais distribuído: REST ainda domina em volume bruto, GraphQL tem espaço consolidado em produtos com UI complexa, e gRPC cresce em comunicação interna entre microserviços. Nenhum dos três vai sumir.

Posso usar GraphQL e REST juntos na mesma aplicação?

Sim, e é comum. Uma arquitetura que vi funcionar bem: GraphQL para a interface do produto (onde a flexibilidade importa), REST para integrações externas e webhooks (onde a previsibilidade e o cache importam), e gRPC para comunicação entre serviços internos. Não existe obrigação de escolher um único paradigma.

O problema de N+1 do GraphQL é grave em produção?

É grave se você não tratar. DataLoader é o padrão da indústria para resolver isso em Node.js, e existem equivalentes em outras linguagens. O ponto é: você precisa saber que o problema existe e implementar a solução ativamente. Em REST, o equivalente seria um endpoint de listagem que faz joins ineficientes — também é grave, mas geralmente mais fácil de identificar no code review.

REST ou GraphQL: a decisão correta depende do problema

Minha posição depois de trabalhar com os dois em produção: comece com REST. Se você estiver resolvendo um dos problemas específicos que GraphQL foi desenhado para resolver — múltiplos clientes com necessidades divergentes, UI altamente dinâmica, federação de microserviços — vale o investimento. Caso contrário, você está adicionando complexidade operacional para resolver um problema que você não tem.

A maioria das APIs que ficam lentas, difíceis de manter ou inconsistentes não ficaram assim por causa do paradigma. Ficaram assim por causa de decisões ruins de design que você pode tomar igualmente mal em GraphQL ou em REST.

RD
Autor
Rafael Duarte
Desenvolvedor backend com passagem por fintech e SaaS B2B — trabalhou em times que escalaram APIs de zero a milhões de requisições. Carrega cicatrizes de produção suficientes para ter opiniões fortes sobre ferramentas, padrões e decisões de arquitetura. Não é acadêmico: leu a RFC do UUID quando precisou escolher entre v4 e v7 para uma tabela de alta escrita.
Ver perfil