Pular para o conteúdo
B
Bradata
APIarquiteturamicrosserviçosbackend

REST vs GraphQL vs gRPC em 2026: qual arquitetura de API para sistemas empresariais

Comparativo técnico entre REST, GraphQL e gRPC para sistemas corporativos. Microsserviços, monólito modular e event-driven com padrões reais.

Por Bradata··11 min de leitura

A escolha de protocolo de API define o teto de escalabilidade do seu sistema

Toda empresa que constrói software corporativo — seja ERP, plataforma SaaS ou sistema de integração — enfrenta uma decisão arquitetônica fundamental nos primeiros sprints: qual protocolo de comunicação adotar entre serviços e entre frontend e backend.

Em 2026, três opções dominam o mercado enterprise:

  • REST (HTTP + JSON) — o padrão consolidado
  • GraphQL (query language sobre HTTP) — o queridinho dos frontends complexos
  • gRPC (Protocol Buffers sobre HTTP/2) — o cavalo de corrida da comunicação serviço-a-serviço

A resposta correta raramente é "só um". Sistemas empresariais maduros combinam os três em camadas diferentes. Este post analisa quando usar cada um, com padrões que aplicamos em projetos reais na Bradata.

REST: o padrão que ainda resolve 80% dos casos

REST continua sendo a escolha mais sensata para a maioria das APIs públicas e internas. Os motivos são pragmáticos:

  • Universalidade: qualquer linguagem, framework ou ferramenta sabe consumir REST
  • Cache nativo: headers HTTP (ETag, Cache-Control) funcionam sem configuração extra
  • Tooling maduro: Swagger/OpenAPI, Postman, curl — zero fricção para debugging
  • Semântica clara: GET lê, POST cria, PUT atualiza, DELETE remove

Quando REST brilha

  • APIs públicas consumidas por terceiros (parceiros, integradores)
  • CRUD simples com recursos bem definidos (usuários, pedidos, produtos)
  • Sistemas onde cache HTTP é diferencial (catálogos, conteúdo estático)
  • Equipes com desenvolvedores de níveis variados de experiência

Quando REST começa a doer

O problema clássico do REST aparece quando o frontend precisa de dados de múltiplos recursos numa única tela:

GET /api/pedidos/123
GET /api/pedidos/123/itens
GET /api/pedidos/123/cliente
GET /api/pedidos/123/pagamentos
GET /api/pedidos/123/notas-fiscais

Cinco requests para montar uma tela. Isso é o problema de under-fetching — cada endpoint retorna uma fatia do dado, e o frontend precisa orquestrar múltiplas chamadas.

A solução REST tradicional é criar endpoints agregados (GET /api/pedidos/123/completo), mas isso gera endpoints ad-hoc que crescem sem controle. É exatamente onde GraphQL entra.

GraphQL: consulta sob demanda para frontends complexos

GraphQL resolve o problema de under-fetching e over-fetching com uma premissa simples: o cliente define exatamente quais campos quer receber.

query PedidoCompleto($id: ID!) {
  pedido(id: $id) {
    numero
    status
    dataEmissao
    cliente {
      nome
      cnpj
      endereco { cidade estado }
    }
    itens {
      produto { nome sku }
      quantidade
      valorUnitario
    }
    pagamentos {
      metodo
      valor
      status
    }
  }
}

Uma única request. O cliente recebe exatamente o que pediu — nem mais, nem menos.

Vantagens reais em projetos empresariais

  • Redução drástica de requests em dashboards complexos (ERP, CRM, backoffice)
  • Tipagem forte com schema introspectável — o contrato é autodocumentado
  • Evolução sem versionamento: adicionar campos não quebra clientes existentes
  • Ferramentas como GraphQL Playground aceleram debugging e onboarding

Os custos que ninguém menciona no hype

GraphQL não é gratuito. Os custos reais que encontramos em produção:

  1. Complexidade de query: sem limites, um cliente pode pedir o banco inteiro numa query aninhada. É obrigatório implementar query depth limiting e query cost analysis
  2. Cache é difícil: como tudo passa por POST, cache HTTP não funciona. Você precisa de soluções como Apollo Cache, Dataloader ou Redis manual
  3. N+1 por padrão: resolvers aninhados geram N+1 queries no banco se você não usar Dataloader ou batch loading
  4. Curva de aprendizado: equipes acostumadas com REST precisam de treinamento
  5. Upload de arquivos: não é nativo — precisa de extensões como graphql-upload ou multipart

Padrão que usamos na Bradata

Em projetos com GraphQL, adotamos o padrão BFF (Backend for Frontend) com GraphQL:

  • O GraphQL server fica na camada BFF, consumindo microsserviços REST ou gRPC internos
  • Cada frontend (web admin, app mobile, portal do cliente) tem seu próprio schema ou usa persisted queries para limitar o que pode ser consultado
  • Rate limiting por complexidade de query, não por request

Isso dá ao frontend a flexibilidade do GraphQL sem expor a complexidade dos serviços internos.

gRPC: o protocolo de alta performance para comunicação interna

gRPC usa Protocol Buffers (protobuf) para serialização binária e HTTP/2 para transporte. O resultado é comunicação entre serviços com latência significativamente menor que REST/JSON.

Características técnicas

AspectoREST/JSONgRPC/Protobuf
SerializaçãoTexto (JSON)Binário (protobuf)
TransporteHTTP/1.1 ou 2HTTP/2 obrigatório
StreamingWorkaround (SSE, WebSocket)Nativo (4 tipos)
ContratoOpenAPI (opcional).proto (obrigatório)
Tamanho payloadMaior (texto)Menor (binário compacto)
Suporte browserNativoPrecisa de proxy (grpc-web)

Quando gRPC faz sentido

  • Comunicação serviço-a-serviço em microsserviços (onde latência importa)
  • Streaming bidirecional (IoT, telemetria, chat, real-time)
  • Sistemas poliglotas — .proto gera código para Go, Java, Python, C#, Node.js automaticamente
  • Alto throughput — milhões de mensagens por segundo entre serviços

Quando evitar gRPC

  • APIs consumidas diretamente por browsers (sem grpc-web proxy)
  • Equipes pequenas sem experiência com protobuf
  • Sistemas simples que não precisam de performance extrema
  • Debugging rápido (protobuf binário não é legível como JSON)

A verdade: sistemas empresariais maduros combinam os três

Em projetos complexos que desenvolvemos na Bradata, a arquitetura típica combina protocolos por camada:

┌─────────────────────────────────────────────┐
│  Frontends (Web, Mobile, Portal)            │
│  ↕ GraphQL ou REST                          │
├─────────────────────────────────────────────┤
│  API Gateway / BFF Layer                    │
│  ↕ gRPC (interno) ou REST (legado)          │
├─────────────────────────────────────────────┤
│  Microsserviços                             │
│  ↔ gRPC (sync) + Event Bus (async)          │
├─────────────────────────────────────────────┤
│  Bancos de dados, caches, filas             │
└─────────────────────────────────────────────┘
  • Frontend → Backend: GraphQL para dashboards complexos, REST para operações simples
  • Serviço → Serviço (síncrono): gRPC para performance
  • Serviço → Serviço (assíncrono): mensageria (RabbitMQ, Kafka, SQS)

Microsserviços vs Monólito Modular: a decisão que importa mais

Antes de escolher o protocolo, a pergunta anterior é: seu sistema precisa de microsserviços?

A resposta é quase sempre não para o MVP e primeiros anos de operação. O padrão que recomendamos:

Monólito modular primeiro

Um monólito modular é um sistema que roda como um único deploy mas é organizado internamente em módulos independentes com fronteiras claras:

src/
├── modules/
│   ├── pedidos/
│   │   ├── domain/
│   │   ├── application/
│   │   ├── infrastructure/
│   │   └── api/
│   ├── financeiro/
│   │   ├── domain/
│   │   ├── application/
│   │   ├── infrastructure/
│   │   └── api/
│   ├── estoque/
│   └── fiscal/
├── shared/
│   ├── auth/
│   ├── events/
│   └── database/
└── main.ts

Regras fundamentais do monólito modular:

  1. Módulos nunca acessam tabelas de outros módulos diretamente
  2. Comunicação entre módulos é via eventos internos ou interfaces públicas
  3. Cada módulo tem seu próprio domínio, use cases e repositórios
  4. O banco pode ser compartilhado, mas schemas são separados por módulo

Quando migrar para microsserviços

A migração para microsserviços faz sentido quando:

  • Um módulo específico precisa escalar independentemente (ex: módulo de processamento de NF-e que tem picos de carga)
  • Equipes diferentes precisam deployar independentemente (mais de 15-20 devs no mesmo codebase)
  • Um módulo precisa de stack diferente (ex: módulo de ML em Python, resto em Node.js)
  • Requisitos de resiliência: a falha de um módulo não pode derrubar o sistema inteiro

Se nenhuma dessas condições existe, microsserviços são complexidade prematura — você paga o custo de rede distribuída, observabilidade, deploy orquestrado e eventual consistency sem colher os benefícios.

Event-Driven Architecture: comunicação assíncrona entre domínios

Independente de usar monólito modular ou microsserviços, event-driven architecture (EDA) é o padrão que mais melhora a manutenibilidade de sistemas empresariais.

O problema que EDA resolve

Em um ERP, quando um pedido é aprovado, diversas coisas precisam acontecer:

  • Financeiro gera a fatura
  • Estoque reserva os itens
  • Logística agenda a entrega
  • Fiscal emite a NF-e
  • CRM atualiza o histórico do cliente

Sem EDA, o serviço de pedidos chama diretamente cada um desses módulos. Resultado: acoplamento forte, cascata de falhas, e o serviço de pedidos vira um "deus" que conhece todos os outros.

Com EDA

O serviço de pedidos publica um evento PedidoAprovado e não sabe (nem precisa saber) quem consome:

// Serviço de Pedidos - apenas publica o evento
await eventBus.publish('pedido.aprovado', {
  pedidoId: '123',
  clienteId: '456',
  itens: [...],
  valorTotal: 15000.00,
  timestamp: new Date().toISOString()
});

// Cada módulo consome independentemente
// financeiro/handlers/pedido-aprovado.handler.ts
@EventHandler('pedido.aprovado')
async gerarFatura(event: PedidoAprovadoEvent) {
  await this.faturaService.criar(event.pedidoId, event.valorTotal);
}

// estoque/handlers/pedido-aprovado.handler.ts
@EventHandler('pedido.aprovado')
async reservarItens(event: PedidoAprovadoEvent) {
  await this.estoqueService.reservar(event.itens);
}

Padrões de EDA que aplicamos

Event Notification: evento leve que notifica que algo aconteceu. O consumidor busca os detalhes se precisar.

Event-Carried State Transfer: evento carrega todos os dados necessários. O consumidor não precisa consultar o produtor. Ideal para microsserviços onde latência de rede importa.

Event Sourcing: em vez de salvar o estado atual, salva-se a sequência de eventos que levou ao estado. Útil para auditoria, compliance e sistemas financeiros onde rastreabilidade é obrigatória.

CQRS (Command Query Responsibility Segregation): separa modelos de leitura e escrita. Combinado com event sourcing, permite views materializadas otimizadas para cada tipo de consulta.

API Gateway: o ponto de entrada unificado

Em arquiteturas com múltiplos serviços, o API Gateway é a camada que unifica:

  • Autenticação e autorização centralizadas
  • Rate limiting por cliente/plano
  • Roteamento para o serviço correto
  • Transformação de payloads (agregação, filtragem)
  • Observabilidade (logs, métricas, traces distribuídos)

Opções que avaliamos em projetos

GatewayMelhor paraConsiderações
KongMicrosserviços complexosOpen source, plugins ricos, Lua
AWS API GatewayServerless na AWSIntegração nativa Lambda, custo por request
TraefikDocker/KubernetesAuto-discovery, config via labels
Custom (Express/Fastify)Monólito modularTotal controle, sem dependência externa

Para a maioria dos projetos empresariais brasileiros, um API Gateway customizado com Express ou Fastify é suficiente nos primeiros anos. A migração para Kong ou Traefik faz sentido quando o número de serviços passa de 8-10.

Versionamento de API: estratégias para não quebrar clientes

APIs empresariais precisam evoluir sem quebrar integrações existentes. Três estratégias:

URL versioning (mais comum)

GET /api/v1/pedidos
GET /api/v2/pedidos

Simples, explícito, fácil de rotear no gateway. O custo é manter duas versões rodando simultaneamente.

Header versioning

GET /api/pedidos
Accept: application/vnd.bradata.v2+json

URL limpa, mas menos visível. Pode confundir ferramentas de cache.

Evolution sem versão (GraphQL style)

Adicionar campos novos sem remover os antigos. Deprecar campos com @deprecated. O schema é versionado implicitamente.

Em projetos na Bradata, preferimos URL versioning com sunset headers: a versão antiga retorna um header Sunset: <data> informando quando será desligada, dando tempo para os consumidores migrarem.

Tratamento de erros: padrão RFC 7807 Problem Details

APIs empresariais precisam de erros consistentes e informativos. O padrão RFC 7807 define um formato estruturado:

{
  "type": "https://api.bradata.com/errors/pedido-duplicado",
  "title": "Pedido duplicado",
  "status": 409,
  "detail": "Já existe um pedido com número NF-2026-001234 para o cliente 456",
  "instance": "/api/v1/pedidos",
  "extensions": {
    "pedidoExistente": "789",
    "timestamp": "2026-06-03T14:30:00Z",
    "traceId": "abc-123-def-456"
  }
}

O traceId é essencial para correlacionar erros entre serviços em arquiteturas distribuídas.

Observabilidade: os três pilares em APIs distribuídas

Não existe arquitetura de microsserviços funcional sem observabilidade. Os três pilares:

Logs estruturados

Logs em JSON com correlação por traceId:

{
  "level": "error",
  "service": "pedidos",
  "traceId": "abc-123",
  "message": "Falha ao reservar estoque",
  "pedidoId": "123",
  "erro": "Estoque insuficiente para SKU-789",
  "timestamp": "2026-06-03T14:30:00Z"
}

Métricas (RED method)

  • Rate: requests por segundo por endpoint
  • Errors: taxa de erro por endpoint e código de status
  • Duration: latência por endpoint (p50, p95, p99)

Traces distribuídos

OpenTelemetry para rastrear uma request desde o frontend até o banco de dados, passando por todos os serviços intermediários. Ferramentas como Jaeger ou Grafana Tempo visualizam o trace completo.

Checklist de decisão para seu próximo projeto

Use este framework para tomar a decisão arquitetônica:

Protocolo de API:

  • API pública ou integrações com terceiros → REST com OpenAPI
  • Dashboard ou frontend complexo com múltiplas entidades → GraphQL (BFF)
  • Comunicação interna entre serviços com requisito de performance → gRPC
  • Real-time ou streaming → gRPC streaming ou WebSocket

Arquitetura de serviços:

  • Equipe menor que 15 devs e sistema em crescimento → Monólito modular
  • Módulos com requisitos de escala ou stack diferentes → Microsserviços gradual
  • Precisa de auditoria completa e rastreabilidade → Event Sourcing + CQRS
  • Módulos com domínios independentes → Event-driven (mesmo dentro de monólito)

Complexidade operacional que você está disposto a assumir:

  • Monólito modular: 1 deploy, 1 banco, observabilidade simples
  • Microsserviços: N deploys, N bancos, service mesh, tracing distribuído, eventual consistency

A Bradata aplica esses padrões em projetos que vão desde ERPs sob medida até plataformas SaaS multi-tenant. A experiência mostra que começar simples e evoluir gradualmente — monólito modular com eventos internos, migrando módulos para microsserviços conforme a necessidade aparece — é o caminho que gera menos retrabalho e mais valor no curto e longo prazo.

Conclusão: arquitetura é sobre trade-offs, não sobre hype

A tentação de adotar a arquitetura mais sofisticada é real. Microsserviços com gRPC, event sourcing, CQRS e Kubernetes parecem impressionantes no diagrama. Mas complexidade arquitetônica tem custo operacional proporcional.

O melhor sistema é aquele que resolve o problema do negócio com a menor complexidade acidental possível. REST resolve a maioria dos casos. GraphQL resolve frontends complexos. gRPC resolve comunicação interna de alto volume. Monólito modular resolve os primeiros anos. Microsserviços resolvem escala organizacional e técnica.

A arte está em saber quando adicionar cada camada — e essa decisão depende do contexto do negócio, do tamanho da equipe e do estágio do produto, não de tendências de mercado.

Precisa de um talento tech agora?

Fale com a Bradata e receba uma proposta em 24 horas úteis.