Ir para o conteúdo principal
APIs REST vs GraphQL: Escolhendo a Arquitetura Certa para Escalar
5 min de leitura
May 2, 2025 (1y ago)

APIs REST vs GraphQL: Escolhendo a Arquitetura Certa para Escalar

A escolha de arquitetura de API afeta manutenção, performance e velocidade de desenvolvimento. Veja quando cada abordagem faz mais sentido.

ArquiteturaDesenvolvimento Web

Por que essa decisão importa mais do que parece

Troca de arquitetura de API em produção é um dos trabalhos mais caros que existem em software. Você muda o contrato entre front-end e back-end, precisa migrar clientes existentes, atualizar documentação e — na maioria das vezes — fazer os dois sistemas coexistirem por meses durante a transição.

Escolher certo no início poupa meses de retrabalho. E a escolha certa não é uma questão de preferência — é uma questão de caso de uso.

REST: o padrão e por que ainda domina

REST (Representational State Transfer) organiza a API em torno de recursos. Cada recurso tem uma URL, e as operações são os verbos HTTP: GET, POST, PUT, PATCH, DELETE.

GET    /users          → lista usuários
GET    /users/123      → busca usuário por ID
POST   /users          → cria usuário
PATCH  /users/123      → atualiza parcialmente
DELETE /users/123      → remove

Por que REST ainda é a escolha padrão:

  • Cacheable por natureza: GET requests são cacheadas por browsers, CDNs e proxies sem configuração extra
  • Fácil de debugar: qualquer ferramenta (curl, Postman, insomnia) funciona out of the box
  • Sem overhead de runtime: não há uma camada de query language a ser processada
  • Modelo mental simples: qualquer desenvolvedor entende sem treinamento específico

Onde REST sofre:

O problema clássico de REST é over-fetching e under-fetching. Você busca um usuário e recebe 30 campos quando só precisava de 3. Ou precisa de dados de usuário + posts + comentários e faz 3 requests separados.

// 3 requests para montar uma tela de perfil
const user = await fetch('/users/123');
const posts = await fetch('/users/123/posts');
const comments = await fetch('/users/123/comments');

Isso pode ser resolvido com endpoints dedicados (/users/123/profile-summary) mas isso começa a criar acoplamento entre back-end e front-end.

GraphQL: flexibilidade com trade-offs

GraphQL é uma query language para APIs. O cliente especifica exatamente quais dados quer, e o servidor retorna apenas isso.

query {
  user(id: "123") {
    name
    email
    posts(last: 5) {
      title
      publishedAt
    }
  }
}

Um único request retorna exatamente o que foi pedido. Sem over-fetching. Sem under-fetching.

Onde GraphQL brilha:

  • Múltiplos clientes com necessidades diferentes: app mobile quer menos dados do que o dashboard web
  • Desenvolvimento paralelo de front e back-end: o schema é o contrato, o front-end não precisa esperar o back-end criar um endpoint novo
  • Consultas complexas com relações: buscar dados relacionados sem waterfall de requests

Os trade-offs reais:

// N+1 problem em GraphQL sem DataLoader
// Para 100 posts, isso faz 101 queries no banco
users {
  name
  posts {
    title
    author { name }  // 1 query por post
  }
}

GraphQL exige atenção extra com o N+1 problem (resolvido com DataLoader/batching), cache (não funciona com HTTP cache nativo da mesma forma que REST) e segurança (queries maliciosas podem derrubar o servidor sem um sistema de query cost).

Comparação direta

Critério REST GraphQL
Curva de aprendizado Baixa Média
Cache nativo ✅ HTTP cache ❌ Requer configuração
Over/under-fetching Comum Resolvido por design
N+1 problem Não se aplica Requer solução explícita
Tooling Maduro e universal Bom, mas mais específico
Versionamento Via URL (/v1, /v2) Evolução do schema
Ideal para APIs públicas, CRUD simples BFFs, múltiplos clientes

Quando escolher REST

  • API pública ou consumida por terceiros: REST é mais fácil de documentar e consumir sem ferramentas específicas
  • Operações simples de CRUD: criar, ler, atualizar, deletar sem relações complexas
  • Time sem experiência com GraphQL: a curva de aprendizado de GraphQL tem um custo real
  • Necessidade de cache HTTP nativo: CDNs e browsers cacheiam GET requests automaticamente

Quando escolher GraphQL

  • BFF (Backend for Frontend): uma camada de API que serve múltiplos clientes (web, mobile, TV) com necessidades diferentes
  • Produto com domínio complexo: muitas entidades relacionadas onde o cliente frequentemente precisa de dados de múltiplas entidades juntos
  • Times de front-end autônomos: quando os times de front não querem depender do back-end para cada nova tela
  • Subscriptions em tempo real: GraphQL tem suporte nativo para subscriptions via WebSocket

A terceira opção que muita gente ignora

tRPC é uma solução elegante para projetos full-stack com TypeScript nos dois lados. Sem schema, sem geração de código — o contrato de tipos é inferido diretamente das funções do back-end.

// server
const appRouter = router({
  userById: procedure
    .input(z.string())
    .query(({ input }) => db.user.findUnique({ where: { id: input } })),
});
 
// client — com autocompletar e tipagem completa
const user = await trpc.userById.query("123");

Se você tem Next.js + Node.js com TypeScript nos dois lados, tRPC elimina a necessidade de definir tipos manualmente entre front e back. A DX é excelente.

Nossa posição

Usamos REST para a maioria dos projetos — especialmente APIs consumidas por terceiros ou projetos com operações principalmente CRUD. GraphQL entra quando o produto tem um domínio complexo com múltiplos clientes, como um SaaS com dashboard web + app mobile + API pública. tRPC usamos em projetos full-stack com Next.js onde a autonomia do tipo no front-end é prioridade.

A escolha errada não é catastrófica — pode ser migrada. Mas é caro. Vale pensar bem antes.

Precisa de ajuda para definir a arquitetura de back-end do seu projeto? Fale com nosso time.