Artigo

Você Não Precisa Escolher Entre REST, gRPC e GraphQL

8 min de leitura

Existe uma pergunta que aparece em quase toda discussão de arquitetura: "REST, gRPC ou GraphQL?". E na maioria das vezes, a resposta vem carregada de opinião forte — como se você precisasse jurar lealdade a um protocolo e abandonar o resto.

A real é que essa pergunta tá errada. Os três existem pra resolver problemas diferentes. E a decisão de qual usar deveria ser tão pragmática quanto escolher entre um martelo e uma chave de fenda. Você não pergunta "qual ferramenta é melhor?" — você olha pro parafuso e pega a certa.

Nesse artigo, vou destrinchar o que cada protocolo faz por baixo dos panos, onde cada um se encaixa de verdade, e como você pode (e provavelmente deveria) usar mais de um na mesma aplicação.


O que tá por baixo: como cada protocolo funciona

Antes de falar de quando usar, vale entender como cada um funciona. Porque é aí que a decisão fica óbvia.

REST: texto sobre HTTP/1.1

REST opera sobre HTTP/1.1 na grande maioria dos casos. A comunicação é feita em texto (JSON, geralmente): o client serializa um objeto em string, manda pela rede, e o server desserializa de volta pra objeto. O caminho de volta é o mesmo processo invertido.

O modelo é request-response: uma requisição, uma resposta, conexão encerrada (ou reutilizada via keep-alive, mas o fluxo é o mesmo). Cada recurso tem uma URL, cada operação tem um verbo HTTP. Simples, previsível, stateless.

Essa simplicidade é proposital. O HTTP já te dá cache nativo por URL, status codes padronizados, headers pra controle de acesso, negociação de conteúdo. E como JSON é texto legível, debugar é abrir o DevTools e olhar. Qualquer dev, em qualquer linguagem, consegue consumir uma API REST em minutos.

gRPC: binário sobre HTTP/2

gRPC funciona numa camada completamente diferente. A comunicação usa Protocol Buffers — um formato binário onde você define um schema (arquivo .proto) que descreve a estrutura exata dos dados: tipos, campos, ordem. Esse schema é compilado e gera código automaticamente no client e no server, independente da linguagem.

1syntax = "proto3"; 2 3service UserService { 4 rpc GetUser (UserRequest) returns (UserResponse); 5 rpc StreamOrders (UserRequest) returns (stream Order); 6} 7 8message UserRequest { 9 string id = 1; 10} 11 12message UserResponse { 13 string name = 1; 14 string email = 2; 15} 16 17message Order { 18 string id = 1; 19 double total = 2; 20}

O resultado é um payload binário que pode ser 3x a 10x menor que o equivalente em JSON. Não tem chaves, não tem aspas, não tem nomes de campo repetidos — só dados compactados na ordem que o schema definiu.

Além disso, gRPC roda sobre HTTP/2, que permite multiplexação: múltiplos streams na mesma conexão TCP. Na prática, isso significa que um client pode disparar várias chamadas simultâneas sem abrir novas conexões, e o server pode mandar dados de volta de forma contínua — streaming bidirecional real, sem gambiarra.

GraphQL: query language sobre HTTP

GraphQL é uma linguagem de consulta. O server expõe um schema tipado (types, queries, mutations, subscriptions), e o client manda uma query declarativa dizendo exatamente que dados quer:

1query { 2 user(id: "123") { 3 name 4 email 5 orders(last: 3) { 6 id 7 total 8 } 9 notifications(unread: true) { 10 message 11 } 12 } 13}

O server resolve cada campo usando resolvers — funções que sabem buscar aquele dado específico — e retorna um JSON com exatamente a estrutura que o client pediu.

Tudo passa por um único endpoint (geralmente /graphql, via POST). Não tem URL por recurso, não tem verbo HTTP com semântica. A inteligência tá na query, não na rota.


Onde cada um brilha (e onde tropeça)

REST: o canivete suíço

Brilha quando:

  • Você precisa de uma API pública que terceiros vão consumir. REST é universalmente entendido — todo mundo sabe fazer um GET.
  • O domínio é CRUD simples: criar, ler, atualizar, deletar recursos bem definidos.
  • Você quer cache HTTP nativo. Um GET em /users/123 com header Cache-Control funciona out-of-the-box em CDNs, proxies reversos, browsers.
  • O time é pequeno e você controla frontend e backend. Não precisa de mais complexidade.

Tropeça quando:

  • O client precisa de flexibilidade nos dados. Você acaba criando endpoints específicos (/users/123/summary, /users/123/full) ou aceitando query params pra filtrar campos — e isso vira uma bagunça rápido.
  • A comunicação é entre serviços internos com alto volume. JSON é verboso, serialização é cara, e HTTP/1.1 não multiplica bem.
  • Você precisa de streaming real. Dá pra fazer Server-Sent Events ou WebSocket por cima, mas aí você tá saindo do REST.

gRPC: a via expressa entre serviços

Brilha quando:

  • Dois (ou mais) backends precisam conversar com baixa latência e alto throughput. O formato binário e HTTP/2 fazem diferença real quando são milhões de requests por minuto.
  • Você precisa de contrato forte. O arquivo .proto é a fonte de verdade — se o schema muda, o código gerado quebra em compilação, não em runtime. Zero surpresa.
  • O cenário pede streaming: IoT mandando telemetria contínua, pipelines de dados financeiros, logs em tempo real. gRPC suporta streaming unidirecional e bidirecional nativamente.
  • Você trabalha num ambiente poliglota. Um serviço em Go conversando com outro em C# e outro em Python. O protobuf gera o client correto pra cada linguagem a partir do mesmo schema.

Tropeça quando:

  • Precisa funcionar no browser. gRPC-Web existe, mas é um proxy extra na frente — funciona, mas não é o uso ideal.
  • Você quer debugar rápido. Não dá pra abrir o DevTools e ler o payload. Precisa de ferramentas como grpcurl ou reflection.
  • O time não tem familiaridade com protobufs e o overhead de aprendizado não se justifica pra complexidade do projeto.

GraphQL: o contrato flexível

Brilha quando:

  • Você tem múltiplos clientes com necessidades diferentes do mesmo backend. Um app mobile que precisa de 3 campos, um dashboard web que precisa de 20, uma smart TV que precisa de 5 — todos consultam o mesmo schema.
  • O frontend muda rápido. Em vez de pedir pro backend criar um endpoint novo a cada feature, o frontend ajusta a query e segue.
  • Seu domínio tem relações profundas entre entidades. Buscar um usuário com seus pedidos, com os itens de cada pedido, com o fornecedor de cada item — numa query só, sem N+1 de requisições HTTP.

Tropeça quando:

  • A complexidade migra pro server. Cada campo precisa de um resolver. Uma query aninhada demais pode disparar centenas de consultas ao banco (o famoso N+1 problem do GraphQL). Sem rate limiting e depth limiting, um client mal-intencionado (ou só descuidado) pode derrubar o server.
  • Cache fica difícil. REST cacheia por URL — simples, nativo. GraphQL manda tudo por POST no mesmo endpoint, então cache HTTP não funciona. Ferramentas como Apollo Client e Relay resolvem no client, mas é mais infraestrutura.
  • Você tem um frontend e um backend, ambos no mesmo time. O overhead de manter um schema GraphQL, escrever resolvers, configurar tooling... pra quê? Um REST bem feito resolve com muito menos cerimônia.

Na prática: misturando protocolos

O cenário mais comum em aplicações de escala média/grande não é escolher um protocolo — é usar cada um onde faz sentido.

┌──────────────┐       REST/GraphQL       ┌──────────────────┐
│   Browser /  │ ◄──────────────────────► │   API Gateway /  │
│   Mobile App │                          │   BFF            │
└──────────────┘                          └────────┬─────────┘
                                                   │
                                            gRPC   │   gRPC
                                    ┌──────────────┼──────────────┐
                                    ▼              ▼              ▼
                              ┌──────────┐  ┌──────────┐  ┌──────────┐
                              │ Service A│  │ Service B│  │ Service C│
                              │ (Users)  │  │ (Orders) │  │ (Notify) │
                              └──────────┘  └──────────┘  └──────────┘
  • REST na camada externa, expondo APIs públicas e documentadas
  • GraphQL como BFF (Backend For Frontend) quando os clients têm necessidades muito diferentes
  • gRPC na comunicação interna entre microsserviços, onde performance importa e ninguém tá debugando no browser

Não tem nada de errado em ter os três rodando na mesma aplicação. Na real, é sinal de que você tá fazendo escolhas intencionais em vez de seguir hype.


O framework de decisão

Se você tiver que resumir numa regra simples:

  1. Comece com REST. Sério. Pra 80% dos cenários, resolve. É simples, todo mundo conhece, tem tooling maduro.
  2. Quando a dor aparecer, reaja. Se a comunicação entre serviços tá lenta e o payload tá grande demais, olha pro gRPC. Se os frontends estão pedindo endpoints custom toda semana, olha pro GraphQL.
  3. Não adote por moda. gRPC num projeto com dois endpoints é overengineering. GraphQL pra servir um CRUD simples é complexidade desnecessária.

A pergunta nunca deveria ser "qual é o melhor protocolo?" — deveria ser "qual é o problema que eu preciso resolver agora?"

Quem aprende a pensar assim para de ser dev que segue tutorial e começa a tomar decisão de arquitetura.

Racoelho

Conteúdo sobre desenvolvimento, tecnologia e desafios de programação para impulsionar sua carreira em tech.

Conecte-se

© 2024- 2026 Racoelho. Todos os direitos reservados.

v3.0.14 • Build: 2025-12-04