← Blog
·11 blog.minutes

Design de API: REST vs GraphQL vs gRPC — Como Escolher

REST, GraphQL e gRPC resolvem problemas diferentes. Este guia compara suas filosofias de design, trade-offs e casos de uso ideais para que você tome uma decisão informada para sua próxima API.

Toda aplicação moderna se comunica com outras aplicações através de APIs. A questão não é mais se deve construir uma API, mas qual estilo de API construir. REST tem sido o padrão por mais de uma década. GraphQL surgiu como uma resposta à inflexibilidade do REST. gRPC adota uma abordagem completamente diferente, construída sobre HTTP/2 e buffers de protocolo. Escolher entre eles requer entender não apenas a sintaxe, mas a filosofia de design subjacente que cada um representa.

Este guia detalha cada protocolo sob uma perspectiva de design: como você estrutura recursos ou esquemas, como os clientes interagem com sua API, como você lida com versionamento e paginação, e como requisitos de tempo real afetam a decisão. Ao final, você terá um framework para escolher a ferramenta certa para suas restrições específicas.

REST: Design orientado a recursos que a web entende

REST — Transferência de Estado Representacional — não é um protocolo. É um estilo arquitetural definido por Roy Fielding em sua tese de doutorado de 2000. A ideia central é que você modele seu domínio como recursos, cada um identificado por uma URL, e manipule esses recursos através de um conjunto uniforme de verbos HTTP: GET, POST, PUT, PATCH e DELETE.

Um bom design de API REST é design orientado a recursos. Você não projeta endpoints em torno de ações — você projeta endpoints em torno de substantivos. Em vez de /criarUsuario ou /obterUsuarioPorId, você projeta POST /usuarios e GET /usuarios/:id. Isso parece uma pequena distinção, mas afeta profundamente como a API escala, como é documentada e como os clientes aprendem a usá-la.

Um endpoint REST bem projetado para um recurso de usuário se parece com isto:

GET /users/42
Accept: application/json

Response 200:
{
  "id": 42,
  "name": "Ada Lovelace",
  "email": "ada@example.com",
  "role": "admin",
  "createdAt": "2025-11-14T09:00:00Z"
}

A beleza do REST está em sua simplicidade. A URL identifica o recurso, o método HTTP identifica a operação e o corpo da resposta contém a representação. Todo cliente HTTP em todas as linguagens já entende este contrato. Cache funciona de imediato através de cabeçalhos HTTP. Ferramentas como OpenAPI (antigo Swagger) permitem gerar documentação, SDKs de cliente e stubs de servidor a partir de um único arquivo de esquema.

O REST enfrenta problemas quando os clientes precisam de diferentes formatos de dados. Um cliente mobile pode precisar apenas do nome e função do usuário, enquanto um cliente de dashboard precisa do perfil completo com dados organizacionais aninhados. Com REST, você constrói múltiplos endpoints ou força todo cliente a baixar a representação completa e descartar o que não precisa. Este é o problema de over-fetching, e foi a principal motivação para o GraphQL.

GraphQL: Deixe o cliente descrever exatamente o que precisa

GraphQL, desenvolvido pelo Meta e lançado em 2015, adota a abordagem oposta. Em vez de o servidor definir respostas fixas, o cliente envia uma consulta que descreve exatamente os dados que deseja, e o servidor retorna exatamente aquela forma. Um endpoint, qualquer formato de resposta.

Um esquema GraphQL define os tipos e relacionamentos no seu domínio. O cliente compõe consultas contra este esquema, solicitando apenas os campos que precisa. O mesmo conceito de recursos aninhados do REST torna-se campos aninhados em uma consulta GraphQL, mas o cliente controla a profundidade e a seleção.

// Schema GraphQL (SDL)
type User {
  id: ID!
  name: String!
  email: String!
  role: Role!
  posts: [Post!]!
}

type Post {
  id: ID!
  title: String!
  body: String!
}

enum Role { USER ADMIN MODERATOR }

type Query {
  user(id: ID!): User
}

Um cliente que precisa apenas do nome do usuário e dos títulos das postagens envia uma consulta que pede exatamente esses campos:

// Consulta do cliente
query {
  user(id: 42) {
    name
    posts {
      title
    }
  }
}

// Resposta
{
  "data": {
    "user": {
      "name": "Ada Lovelace",
      "posts": [
        { "title": "Notes on the Analytical Engine" }
      ]
    }
  }
}

O princípio chave de design no GraphQL é que o esquema é o contrato. O esquema define o que é possível, e o cliente decide o que solicitar a partir das opções disponíveis. Isso elimina over-fetching, reduz o número de requisições de rede (uma única consulta pode substituir múltiplas viagens de ida e volta do REST) e dá independência às equipes de frontend em relação a mudanças no backend, porque novos requisitos do cliente nem sempre exigem novos endpoints.

GraphQL introduz complexidade própria. O desempenho das consultas é mais difícil de prever porque o cliente controla o que carrega. O problema N+1 — onde resolver campos aninhados dispara uma consulta independente ao banco para cada registro pai — requer soluções de batelada como DataLoader. Cache no nível HTTP não funciona porque toda consulta atinge o mesmo endpoint POST, então estratégias de cache em nível de aplicação são necessárias. E a curva de aprendizado para resolvers, mutations, subscriptions e tipos de entrada é mais íngreme que o modelo direto de URL-e-verbo do REST.

GraphQL dá independência às equipes de frontend em relação a mudanças no backend. Mas essa independência vem com a responsabilidade de entender as características de desempenho de cada consulta que seu cliente envia ao servidor.

gRPC: RPC de alto desempenho construído sobre HTTP/2 e protobuf

gRPC, originalmente desenvolvido pelo Google, adota outra abordagem. Em vez de recursos e consultas, gRPC modela APIs como chamadas de procedimento remoto — você define um serviço com métodos, e os clientes chamam esses métodos como se fossem funções locais. A principal diferença técnica é que gRPC usa Protocol Buffers (protobuf) para serialização em vez de JSON, e HTTP/2 para transporte em vez de HTTP/1.1.

Uma definição de serviço protobuf não se parece com um endpoint REST ou um esquema GraphQL:

syntax = "proto3";

service UserService {
  rpc GetUser (GetUserRequest) returns (User);
  rpc ListUsers (ListUsersRequest) returns (ListUsersResponse);
  rpc CreateUser (CreateUserRequest) returns (User);
  rpc StreamUserUpdates (StreamRequest) returns (stream UserUpdate);
}

message GetUserRequest {
  int32 id = 1;
}

message User {
  int32 id = 1;
  string name = 2;
  string email = 3;
  Role role = 4;
  string created_at = 5;
}

enum Role { ADMIN = 0; USER = 1; }

message StreamRequest {}

message UserUpdate {
  User user = 1;
  string event_type = 2;
}

Protobuf serializa para um formato binário compacto que é significativamente menor que JSON e mais rápido de analisar. Combinado com o multiplexamento do HTTP/2 — múltiplos fluxos em uma única conexão — gRPC alcança latência drasticamente menor e maior throughput que REST ou GraphQL para comunicação de alto volume. Isso torna o gRPC a escolha dominante para comunicação entre microsserviços, onde cada milissegundo de overhead de serialização e cada byte na rede importam.

gRPC também suporta nativamente quatro tipos de streaming: unário (uma requisição, uma resposta), server-streaming (uma requisição, fluxo de respostas), client-streaming (fluxo de requisições, uma resposta) e bidirecional (ambos os lados transmitem simultaneamente). Isso o torna a opção mais forte para APIs em tempo real entre os três protocolos.

O trade-off é que gRPC é mais difícil de usar a partir de navegadores. Clientes de navegador não podem acessar serviços gRPC diretamente porque não têm controle refinado sobre frames HTTP/2. gRPC-Web existe como uma alternativa, mas adiciona complexidade. Mensagens protobuf não são legíveis por humanos em trânsito, o que torna a depuração mais difícil — você precisa de ferramentas como grpcurl ou um serviço de reflection para inspecionar o tráfego. E o ecossistema para documentação de API é menos maduro que OpenAPI ou o sistema de introspecção do GraphQL.

Como eles se comparam em preocupações práticas

Escolher entre REST, GraphQL e gRPC raramente é uma decisão puramente técnica. A escolha certa depende de quem são seus clientes, que tipo de dados eles precisam e das restrições de sua rede e infraestrutura. Aqui está como cada protocolo se compara nas preocupações práticas que mais importam em produção.

Versionamento de API

REST lida com versionamento através da URL ou do cabeçalho Accept. /v1/usuarios e /v2/usuarios podem coexistir indefinidamente, permitindo que os clientes migrem no seu próprio ritmo. Isso é simples e testado em batalha, mas incentiva a duplicação — o endpoint v2 frequentemente duplica a maior parte da lógica do v1 com poucas alterações. GraphQL evita versionamento completamente evoluindo o esquema. Campos obsoletos são decorados com uma diretiva @deprecated e permanecem no esquema até que todo cliente tenha migrado. Isso funciona bem quando você controla todos os clientes, mas pode causar atrito em APIs públicas onde os clientes atualizam lentamente. O esquema protobuf do gRPC é compatível com versões futuras por design — você pode adicionar campos sem quebrar clientes existentes, e campos obsoletos são removidos após um período de migração. Esta é a estratégia de versionamento mais elegante das três, mas requer disciplina para nunca renomear ou remover um campo sem um ciclo de depreciação.

Padrões de paginação

A paginação REST é tipicamente feita com paginação baseada em cursor usando um campo nextCursor, ou paginação baseada em offset com parâmetros page e limit. O princípio de design é que a resposta contém um link ou token de próximo, e o cliente o segue. A paginação GraphQL usa a especificação Relay Connection, que envolve listas em edges com cursores e informações de página — mais verboso, mas mais consistente que abordagens REST ad-hoc. A paginação gRPC é tratada manualmente nas mensagens de requisição e resposta, geralmente com campos page_token e page_size. Não há padrão, mas o esquema protobuf torna o contrato explícito.

  • REST: paginação baseada em cursor com nextCursor na resposta é o padrão recomendado para APIs de produção
  • GraphQL: a especificação Relay Connection fornece um modelo de paginação padronizado com hasNextPage, hasPreviousPage e cursores
  • gRPC: a paginação é definida em suas mensagens proto; um padrão comum é incluir page_token e page_size na requisição e next_page_token na resposta

Autenticação e autorização

Os três protocolos dependem da mesma segurança de transporte subjacente. REST tipicamente usa tokens Bearer no cabeçalho Authorization. GraphQL segue o mesmo padrão — como todas as requisições passam por um único endpoint POST, o token é validado na camada GraphQL ou em um middleware. gRPC usa interceptadores para anexar metadados de autenticação a cada chamada, geralmente na forma de tokens JWT transportados em cabeçalhos de metadados gRPC. Nenhum dos três protocolos prescreve um método de autenticação específico — a escolha entre OAuth2, chaves de API ou autenticação baseada em sessão é ortogonal ao estilo da API.

Limitação de taxa

A limitação de taxa é mais simples com REST porque cada endpoint representa uma operação delimitada. Você conta requisições por endpoint por cliente e retorna 429 Too Many Requests quando o limite é excedido. GraphQL torna a limitação de taxa mais difícil porque uma única consulta pode disparar quantidades vastamente diferentes de trabalho — uma consulta por um campo pode custar uma busca no banco, enquanto uma consulta com relações profundamente aninhadas pode custar cinquenta. APIs GraphQL tipicamente implementam limitação de taxa baseada em custo, onde cada campo tem um peso e o custo total da consulta é calculado antes da execução. A limitação de taxa do gRPC é similar ao REST, mas opera no nível do método — você conta chamadas RPC por método por cliente, com a consideração adicional de que chamadas de streaming consomem recursos por sua duração, não apenas por sua iniciação.

APIs em tempo real e streaming

REST pode lidar com atualizações em tempo real através de WebSockets ou Server-Sent Events (SSE), mas nenhum deles faz parte da especificação REST — são protocolos separados acoplados junto à API HTTP. GraphQL tem subscriptions, que são parte integrante da especificação. Um cliente assina um evento e recebe atualizações através de uma conexão WebSocket sempre que o evento ocorre. gRPC tem a história mais forte de tempo real com seu streaming bidirecional nativo sobre HTTP/2. Uma única chamada gRPC pode transmitir dados em ambas as direções simultaneamente, o que é ideal para dashboards em tempo real, aplicações de chat e sistemas orientados a eventos. Se comunicação em tempo real é um requisito primário, o streaming do gRPC é a opção mais madura e de melhor desempenho, seguido pelas subscriptions do GraphQL, seguido por REST mais WebSockets.

Documentação e experiência do desenvolvedor

REST tem o ecossistema de documentação mais forte graças ao OpenAPI (antigo Swagger). Uma especificação OpenAPI descreve cada endpoint, parâmetro de requisição, esquema de resposta e método de autenticação em um arquivo YAML ou JSON legível por máquina. Ferramentas como Swagger UI renderizam isso em uma página de documentação interativa, e geradores de código produzem SDKs de cliente para dezenas de linguagens. A maturidade deste ecossistema significa que um novo desenvolvedor pode ir da leitura de uma especificação OpenAPI à realização de sua primeira chamada de API bem-sucedida em minutos.

GraphQL tem introspecção — um sistema embutido onde você consulta o esquema da API através de um endpoint especial. Ferramentas como GraphiQL e Apollo Studio Explorer permitem que desenvolvedores naveguem pelo esquema, escrevam consultas com autocomplete e vejam documentação inline. Esta é uma ótima experiência para desenvolvedores que já sabem que sua API existe, mas não ajuda com a descoberta por mecanismos de busca ou marketplaces de API externos da mesma forma que uma especificação OpenAPI.

gRPC depende de arquivos proto como sua fonte da verdade. O arquivo proto é tanto o esquema quanto a documentação. Ferramentas como protoc-gen-doc geram documentação de referência a partir de arquivos proto, e a reflection do gRPC permite que clientes descubram serviços dinamicamente. A experiência do desenvolvedor para gRPC está melhorando, mas ainda fica atrás do REST e GraphQL em maturidade de ferramentas, especialmente fora do ecossistema de microsserviços.

Quando usar cada um

REST é a escolha certa quando sua API é consumida por desenvolvedores externos, quando você precisa de máxima interoperabilidade e quando seus clientes precisam de cache HTTP padrão. É o padrão mais seguro porque toda linguagem, framework e proxy entende HTTP. Se você está construindo uma API pública, comece com REST.

GraphQL é a escolha certa quando sua API tem múltiplos tipos de cliente com diferentes requisitos de dados, quando equipes de frontend precisam se mover independentemente de mudanças no backend e quando você quer reduzir o número de requisições de rede. Ele se destaca em aplicações voltadas ao consumidor com clientes mobile e web que precisam de diferentes formatos dos mesmos dados.

gRPC é a escolha certa para comunicação interna entre microsserviços, para sistemas de alto throughput onde o overhead de serialização importa e para aplicações de streaming em tempo real. Se você está construindo um sistema onde ambas as pontas estão sob seu controle e o desempenho é a principal preocupação, gRPC é a opção mais forte.

Nenhum desses protocolos é mutuamente exclusivo. Uma arquitetura de produção comum usa gRPC para comunicação serviço-a-serviço atrás do firewall, expõe um gateway GraphQL que agrega dados de múltiplos serviços gRPC e fornece uma API REST para clientes externos. A questão não é qual protocolo usar em todos os lugares — é qual protocolo usar para cada interface no seu sistema. Entender a filosofia de design por trás de cada um lhe dá o julgamento para fazer essa escolha corretamente.