REST vs GraphQL vs tRPC: Como Escolher a Arquitetura da Tua API

REST vs GraphQL vs tRPC: Como Escolher a Arquitetura da Tua API

A Febre do GraphQL: Como uma Promessa de Simplicidade Trouxe Complexidade

Em 2016, o mundo do desenvolvimento web foi inundado pelo entusiasmo em torno do GraphQL. Criado pela Meta para substituir o REST, prometia resolver dois problemas clássicos: o over-fetching (receber cinquenta campos da base de dados quando só precisavas do primeiro nome) e o under-fetching (fazer três pedidos seguidos para obter o perfil, as encomendas e as moradas).

Equipas inteiras deitaram fora os seus endpoints REST e reescreveram tudo em GraphQL.

Passados alguns anos, o entusiasmo inicial deu lugar a uma ressaca técnica:

  • A Cache de HTTP Foi Destruída: Como todas as pesquisas do GraphQL viajam como pedidos POST para um único endereço (/graphql), os proxies de borda como o Nginx e as CDNs deixaram de conseguir guardar respostas em cache. Os clientes foram obrigados a instalar bibliotecas pesadas como o Apollo Client, acrescentando 45KB de código JavaScript ao browser.
  • O Problema das Consultas N+1: Listar 40 artigos e os respetivos autores resultava em 41 consultas separadas à base de dados SQL, exigindo camadas complexas de empacotamento com o DataLoader.
  • Ataques de Consultas Profundas: Qualquer utilizador podia enviar consultas com ciclos infinitos (utilizador { amigos { amigos { amigos ... } } }), esgotando a memória do servidor num piscar de olhos.

O CICLO DE SOBRE-ENGENHARIA DO GRAPHQL

    1. Adotar GraphQL para resolver o over-fetching
    1. Perder a cache de HTTP na borda (Tudo passa por POST /graphql)
    1. Sofrer com problemas N+1 na BD (Obriga a programar DataLoaders)
    1. Adicionar Apollo Client pesado (Mais 45KB de bundle no telemóvel!)
  1. Programar limitadores de profundidade contra ataques de DoS (Resultado: Uma arquitetura frágil e 5 vezes mais difícil de manter!)

Para manteres as tuas aplicações fiéis aos princípios de anti-over-engineering, precisas de analisar de forma pragmática as três opções reais do mercado: REST, GraphQL e tRPC.

A Revolução do tRPC: Tipagem Total Sem Esquemas Nem Compilações

Nos dias de hoje, uma enorme percentagem dos projetos digitais é construída em TypeScript de ponta a ponta: interfaces em React, Astro ou Next.js a comunicar com servidores em Fastify ou Node.js dentro de um monorepo partilhado.

Neste cenário moderno, tanto o REST como o GraphQL obrigam a um trabalho redundante:

  • No REST, tens de escrever especificações em Swagger/OpenAPI e gerar tipos.
  • No GraphQL, tens de manter ficheiros .graphql e correr o graphql-codegen.

O tRPC (TypeScript Remote Procedure Call) elimina esse desperdício aproveitando a inferência natural do próprio compilador de TypeScript:

INFERÊNCIA DE TIPOS DE PONTA A PONTA COM TRPC

  • Router no Backend (Fastify / Express): export const appRouter = router({ obterUtilizador: publicProcedure
  • .input(z.object({ id: z.string() }))
  • .query(async ({ input }) => ({ id: input.id, nome: “Ana”, perfil: “admin” })) export type AppRouter = typeof appRouter; // Exporta APENAS o tipo estático! (0 bytes)
  • (Tipagem Automática sem Compilação no Monorepo)
  • Frontend na Tua Aplicação Web: const { data } = trpc.obterUtilizador.useQuery({ id: “89” });
  • // data.nome é automaticamente uma string!
  • // data.perfil é automaticamente “admin”!
  • // ZERO GERAÇÃO DE CÓDIGO! AUTO-COMPLETE PERFEITO NO EDITOR!

Com o tRPC, não partilhas código compilado nem bibliotecas pesadas entre frontend e backend. Partilhas apenas o tipo estático type AppRouter. Se mudares o nome de um campo na base de dados de nome para nomeCompleto, o teu editor de código assinala imediatamente a vermelho as linhas afetadas no frontend em tempo real!

Como Criar uma Rota com Validação Segura no tRPC

Vê como podes estruturar uma rota simples e robusta no tRPC combinada com a biblioteca de validação Zod:

// src/server/routers/encomendaRouter.ts
import { router, publicProcedure } from '../trpc.js';
import { z } from 'zod';
import { db } from '../../db/postgres.js';

export const encomendaRouter = router({
  // Consulta validada com tipagem rigorosa
  obterPorId: publicProcedure
    .input(
      z.object({
        encomendaId: z.string().uuid(),
      })
    )
    .query(async ({ input }) => {
      const resultado = await db.query(
        'SELECT id, valor_total, estado FROM encomendas WHERE id = $1',
        [input.encomendaId]
      );
      
      if (!resultado.rows[0]) {
        throw new Error('Encomenda não encontrada');
      }

      return resultado.rows[0];
    }),

  // Mutação para gravação de novos registos
  criarEncomenda: publicProcedure
    .input(
      z.object({
        artigos: z.array(z.object({ sku: z.string(), quantidade: z.number().min(1) })),
        cupao: z.string().optional(),
      })
    )
    .mutation(async ({ input }) => {
      // Processa a compra...
      return { sucesso: true, id: 'enc_4502' };
    }),
});

No teu frontend, chamar esta função é tão natural como chamar uma função local, acelerando o desenvolvimento das tuas web apps.

Onde o REST Tradicional Continua a Ser Imbatível

Apesar do sucesso do tRPC, o REST clássico continua a ser a escolha certa em três cenários incontornáveis:

  1. APIs Públicas para Clientes Externos: Se estás a desenhar uma API para ser consumida por clientes em Python, Android, iOS nativo ou PHP, o tRPC não serve porque exige TypeScript. O REST com OpenAPI é a linguagem universal de programação.
  2. Cache Agressiva na Borda da Rede: Uma rota RESTful como GET /api/v1/catalogo/destaques pode ser guardada em cache no Nginx e na Cloudflare com cabeçalhos Cache-Control: public, max-age=3600. A resposta é entregue em 2 milissegundos sem nunca acordar o teu servidor backend.
  3. Envio de Ficheiros Pesados: Fazer uploads de fotos ou vídeos por multipart HTTP é limpo e eficiente em REST, ao passo que tentar passar binários dentro de mutations de GraphQL ou tRPC exige conversões lentas em Base64.
  • CACHE NA BORDA: REST vs GRAPHQL / TRPC
  • Pedido REST Tradicional: GET /api/v1/produtos → [Cache Nginx / Cloudflare: RESPOSTA EM 2ms!] (Zero carga no servidor! Velocidade máxima para websites de alta performance)
  • Pedido GraphQL ou tRPC: POST /graphql → Bypassa a cache padrão de HTTP da borda (Obriga sempre a executar código no servidor backend!)

Esta facilidade de cache torna o REST insubstituível na construção de websites de alta performance.

Matriz de Decisão: REST vs GraphQL vs tRPC

Para escolheres a melhor solução técnica segundo os padrões da WebXtek, consulta esta matriz comparativa:

MATRIZ DE DECISÃO TÉCNICA

CRITÉRIO REST (OpenAPI) GRAPHQL TRPC
Tipo de Equipa Várias Linguagens Equipas Grandes / Múlt TypeScript Full-Stack
Segurança de Tipos Manual ou Codegen Esquema com Codegen Automática e Imediata
Cache Nativa de HTTP Perfeita e Imediata Muito Complexa Por URL de Consulta
Peso no Cliente Zero (Fetch nativo) Alto (Apollo Client) Mínimo (< 2KB)
Complexidade Backend Baixa e Previsível Alta (DataLoaders) Baixa (Funções puras)
Melhor Aplicação APIs Públicas / Media Grandes Redes Heterog. SaaS Rápido / B2B

Podes analisar projetos com Docker e exemplos de código no repositório de suporte no GitHub.

Boas Práticas Operacionais: Consultas Persistidas e Padronização de Erros

Seja qual for a tecnologia que escolheres no teu projeto, deves aplicar estas três regras de engenharia:

  1. Nunca Deixes o GraphQL Aberto ao Público: Se precisares de usar GraphQL, ativa o mecanismo de consultas persistidas (Persisted Queries). Os clientes registam as consultas autorizadas durante o deploy e o servidor bloqueia qualquer código arbitrário enviado em tempo de execução.
  2. Gera Documentação OpenAPI a Partir do tRPC: Se usares tRPC mas mais tarde precisares de partilhar endpoints com parceiros externos, podes usar o pacote trpc-openapi, que gera a documentação do Swagger automaticamente sem duplicares rotas.
  3. Padroniza as Respostas de Erro: Usa a norma internacional RFC 7807 (Problem Details) para devolveres erros com formato uniforme em todas as rotas da tua aplicação.

Ao escolheres a arquitetura da tua API com base em necessidades reais e não nas modas passageiras das redes sociais, evitas complexidade desnecessária e entregas uma aplicação rápida, escalável e fácil de manter.

Na prática, aplicas exatamente estes padrões operacionais em setores exigentes como saas empresarial b2b e especialistas em devops e arquitetura cloud. Quando alinhas a tua estrutura através de web apps e websites de alta performance, transformas boas práticas técnicas numa vantagem competitiva real e mensurável para o teu negócio.

[+] [ INDEX_DIRECTORY ] 14 tópicos ▼
[ SYSTEM.FAQ ]

Perguntas Frequentes

Qual é a diferença fundamental entre REST, GraphQL e tRPC?

O REST disponibiliza URLs fixos associados a verbos HTTP. O GraphQL usa um único endpoint POST flexível onde o cliente escolhe os campos exatos. O tRPC oferece tipagem estrita de ponta a ponta em TypeScript sem esquemas manuais nem passos de compilação de código.

Porque é que o GraphQL não substituiu o REST como muitos previam?

O GraphQL quebra a cache nativa de HTTP (como a do Nginx e CDNs), cria problemas graves de consultas N+1 na base de dados (exigindo bibliotecas pesadas como DataLoader), aumenta o peso do JavaScript no cliente e expõe o backend a ataques de exaustão de consultas profundas.

Quando é que o tRPC é a melhor escolha técnica?

O tRPC é imbatível quando desenvolves aplicações full-stack com TypeScript (como Next.js, Astro ou Fastify) onde a mesma equipa controla o frontend e o backend num monorepo. Elimina completamente a necessidade de sincronizar tipos e documentar endpoints manuais.

O REST tradicional ainda faz sentido em projetos modernos?

Sim. O REST continua a ser a melhor opção para APIs públicas acessíveis por várias linguagens (Python, apps móveis nativas) e sistemas com alto volume de tráfego que dependem da cache nativa de HTTP nas bordas da rede.

> INICIAR_PROJETO

Precisa de um website que transmita confiança, apareça na pesquisa e dê mais força à sua presença digital? Comece a conversa aqui.