Chamadas RPC, REST e GraphQL: Guia Completo e Fácil de Entender

Rebecca Kovács

Rebecca Kovács

20 maio 2025

Chamadas RPC, REST e GraphQL: Guia Completo e Fácil de Entender

No desenvolvimento de software moderno, as aplicações raramente existem isoladamente. Elas se comunicam, trocam dados e acionam ações umas nas outras, formando vastos ecossistemas interconectados. Essa comunicação é orquestrada por Interfaces de Programação de Aplicações (APIs), que definem as regras e protocolos de como diferentes componentes de software interagem. Ao longo das décadas, vários estilos arquiteturais e protocolos surgiram para facilitar essa comunicação entre serviços. Entre os mais proeminentes estão Remote Procedure Calls (RPC), Representational State Transfer (REST) e GraphQL.

Compreender esses três paradigmas é crucial para qualquer desenvolvedor ou arquiteto que projete sistemas distribuídos. Cada um vem com sua própria filosofia, pontos fortes, fracos e casos de uso ideais. Este artigo tem como objetivo explicar claramente RPC, REST e GraphQL, aprofundando-se em seus conceitos centrais, mecânicas operacionais, benefícios, desvantagens e os cenários onde cada um se destaca.

💡
Quer uma ótima ferramenta de Teste de API que gera Documentação de API bonita?

Quer uma plataforma integrada, tudo-em-um, para sua Equipe de Desenvolvimento trabalhar em conjunto com produtividade máxima?

Apidog entrega todas as suas demandas e substitui o Postman a um preço muito mais acessível!
button

A Base: Comunicação Cliente-Servidor

Antes de mergulhar nos detalhes, é essencial entender o modelo fundamental que todos eles atendem: a comunicação cliente-servidor. Neste modelo, um cliente (por exemplo, um navegador web, um aplicativo móvel, outro servidor) requer alguns dados ou deseja executar uma ação. Concomitantemente, um servidor (uma máquina ou processo remoto) hospeda os dados ou a lógica para executar a ação. O cliente envia uma requisição para o servidor, e o servidor envia de volta uma resposta. Os mecanismos que estamos prestes a discutir – RPC, REST e GraphQL – são diferentes maneiras de estruturar essas requisições e respostas.

RPC: Invocando Funções Através de Redes

O que é RPC?

Remote Procedure Call representa um dos paradigmas mais antigos e diretos para comunicação entre processos. A ideia fundamental é fazer com que uma requisição a um servidor remoto pareça e opere muito como uma chamada de função ou procedimento local. A aplicação cliente invoca o que parece ser uma função local (o "procedimento"), mas a execução dessa função realmente ocorre em um servidor remoto. As complexidades da comunicação de rede são cuidadosamente abstraídas, conferindo à programação distribuída um ar de simplicidade semelhante à programação tradicional, em máquina única.

Como o RPC Funciona:

O processo RPC se desenrola através de uma sequência de etapas coordenadas, projetadas para tornar a execução remota transparente. Inicialmente, o cliente possui um "stub" ou "proxy" para o procedimento remoto. Este stub espelha a assinatura do procedimento remoto real. Quando a aplicação cliente chama este stub, a lógica não é executada localmente. Em vez disso, o stub do cliente pega os parâmetros passados para a função e os "empacota" ou "serializa". Este passo crítico converte os parâmetros de sua representação na memória para um formato adequado para transmissão em rede, como binário, XML ou JSON.

Após o empacotamento, esses parâmetros serializados, acompanhados por um identificador para o procedimento específico a ser invocado, são enviados através da rede para o servidor. No lado do servidor, um "skeleton" ou stub do lado do servidor aguarda e recebe a requisição de entrada. Este skeleton do servidor então assume a tarefa de "desempacotar" ou "desserializar" os dados recebidos, transformando-os de volta nos parâmetros que o procedimento do servidor real espera.

Com os parâmetros reconstruídos com sucesso, o skeleton do servidor chama o procedimento designado no servidor, passando-lhe os parâmetros desempacotados. Uma vez que o procedimento conclui sua execução, seu valor de retorno, juntamente com quaisquer exceções encontradas, são empacotados pelo skeleton do servidor. Esta resposta serializada é então transmitida de volta através da rede para o stub do cliente. Ao receber a resposta, o stub do cliente a desempacota, convertendo os dados de volta em um valor de retorno que a aplicação cliente pode prontamente entender. Finalmente, o stub do cliente retorna este valor para o código de chamada original, completando assim a ilusão de que uma chamada de função local foi realizada.

Principais Características do RPC:

APIs RPC são tipicamente orientadas a ações. Elas são projetadas em torno de verbos ou comandos, como addUser(userDetails) ou calculatePrice(itemId, quantity). O foco principal é em "quais ações você pode realizar".

Tradicionalmente, clientes e servidores em sistemas RPC exibem acoplamento forte. O cliente frequentemente precisa de conhecimento explícito dos nomes de funções específicas e das assinaturas de parâmetros precisas disponíveis no servidor. Consequentemente, modificações no lado do servidor frequentemente necessitam de mudanças correspondentes no lado do cliente.

Frameworks RPC comumente fornecem ferramentas para gerar stubs de cliente e skeletons de servidor em várias linguagens de programação a partir de uma Linguagem de Definição de Interface (IDL) compartilhada. Exemplos de IDLs incluem CORBA IDL, Protocol Buffers (.proto files) ou Apache Thrift IDL. Essa capacidade de geração de código facilita a interoperabilidade.

Em relação à eficiência, muitos protocolos RPC, particularmente aqueles que empregam formatos binários, são projetados para desempenho ótimo em termos de tamanho de dados e velocidade de processamento.

Evolução: gRPC

Embora implementações RPC anteriores como XML-RPC ou Java RMI tivessem certas limitações, o paradigma RPC experimentou um ressurgimento significativo com o advento de frameworks modernos como gRPC (Google RPC). gRPC introduz aprimoramentos substanciais. Ele predominantemente usa Protocol Buffers como sua IDL e para serialização de mensagens. Protocol Buffers oferecem um mecanismo agnóstico de linguagem, neutro em plataforma, extensível para serialização de dados estruturados, frequentemente descrito como uma alternativa mais compacta, rápida e simples ao XML.

Além disso, o gRPC opera sobre HTTP/2, o que permite recursos avançados como multiplexação (permitindo múltiplas requisições e respostas sobre uma única conexão), capacidades de server push e compressão de cabeçalho. Esses recursos contribuem coletivamente para melhor desempenho e latência reduzida.

Uma força notável do gRPC é seu suporte para vários modos de streaming. Isso inclui unário (um padrão simples de requisição-resposta), streaming de servidor (onde o cliente envia uma requisição e o servidor responde com um stream de mensagens), streaming de cliente (onde o cliente envia um stream de mensagens e o servidor emite uma única resposta) e streaming bidirecional (onde tanto o cliente quanto o servidor podem enviar um stream de mensagens independentemente).

Finalmente, o gRPC fornece ferramentas robustas para geração de código, permitindo a criação automática de código de cliente e servidor em uma infinidade de linguagens de programação populares.

Prós do RPC (especialmente RPC moderno como gRPC):

Contras do RPC:

Quando Usar RPC:

Considere RPC para comunicação interna de microsserviços onde desempenho e baixa latência são objetivos de design críticos. Também é adequado para aplicações que exigem streaming de dados complexo e de alto desempenho. Se um contrato claramente definido e fortemente tipado entre serviços for desejado, o RPC oferece vantagens significativas. Ambientes poliglota, onde a geração de código para múltiplas linguagens pode otimizar o desenvolvimento, também se beneficiam do RPC. Por fim, em ambientes com restrição de rede, onde a eficiência do tamanho da mensagem é primordial, o RPC, particularmente o gRPC com Protocol Buffers, é um forte candidato.

REST: Recursos e Hipermídia

O que é REST?

REST, ou Representational State Transfer, não é um protocolo ou um padrão rígido, mas sim um estilo arquitetural para projetar aplicações em rede. Foi meticulosamente definido por Roy Fielding em sua dissertação de doutorado em 2000. O REST habilmente aproveita os recursos e protocolos existentes do HTTP, enfatizando um modo de comunicação sem estado (stateless), cliente-servidor e cacheável. O conceito central gira em torno de recursos (entidades de dados) sendo identificados de forma única por URLs, e interações com esses recursos sendo realizadas usando métodos HTTP padrão.

Princípios Fundamentais do REST (Restrições):

O estilo arquitetural REST é definido por várias restrições orientadoras:

Um princípio fundamental é a Arquitetura Cliente-Servidor. Isso impõe uma clara separação de preocupações. O cliente é responsável pela interface do usuário e aspectos da experiência do usuário, enquanto o servidor gerencia o armazenamento de dados, a lógica de negócio e a provisão da própria API.

Outra restrição crucial é a Ausência de Estado (Statelessness). Cada requisição enviada de um cliente para o servidor deve encapsular todas as informações necessárias para que o servidor entenda e processe essa requisição. O servidor não retém nenhum contexto do cliente (estado de sessão) entre requisições individuais. Qualquer estado pertinente a uma sessão é mantido no lado do cliente.

A Cacheabilidade também é um princípio chave. As respostas geradas pelo servidor devem definir explicitamente se são cacheáveis ou não cacheáveis. Isso permite que clientes e sistemas intermediários (como Content Delivery Networks ou CDNs) armazenem respostas em cache, o que pode melhorar significativamente o desempenho e a escalabilidade.

Sistemas REST são projetados como um Sistema em Camadas. Isso significa que um cliente tipicamente não pode determinar se está conectado diretamente ao servidor final ou a um intermediário (como um balanceador de carga ou proxy) ao longo do caminho de comunicação. Servidores intermediários podem reforçar a escalabilidade do sistema facilitando o balanceamento de carga e fornecendo caches compartilhados.

A restrição de Interface Uniforme é, sem dúvida, o que mais distingue o REST e serve para simplificar e desacoplar a arquitetura. Essa restrição é subdividida em várias sub-restrições.

Primeiro, Identificação de Recursos: Todos os recursos conceituais são identificados dentro das requisições usando URIs (Uniform Resource Identifiers), tipicamente URLs. Por exemplo, /users/123 identifica de forma única um recurso de usuário específico.

Segundo, Manipulação de Recursos Através de Representações: Clientes interagem com recursos não invocando métodos diretamente neles, mas trocando representações desses recursos. Uma representação pode estar em vários formatos, como JSON, XML ou HTML. O cliente indica seu(s) formato(s) preferido(s) usando cabeçalhos Accept, enquanto o servidor especifica o formato da representação enviada usando o cabeçalho Content-Type.

Terceiro, Mensagens Auto-Descritivas: Cada mensagem trocada deve conter informações suficientes para descrever como deve ser processada. Por exemplo, cabeçalhos HTTP como Content-Type e Content-Length fornecem metadados sobre o corpo da mensagem, e códigos de status informam o cliente sobre o resultado de sua requisição.

Quarto, Hipermídia como Motor do Estado da Aplicação (HATEOAS): Este princípio, frequentemente considerado o aspecto mais sofisticado e às vezes o menos implementado do REST, dita que as respostas do servidor devem incluir links (hipermídia). Esses links guiam o cliente indicando quais ações ele pode realizar em seguida ou quais recursos relacionados ele pode acessar. Isso permite que os clientes naveguem na API dinamicamente, em vez de depender de URIs codificadas. Por exemplo, uma resposta para um recurso de usuário pode incluir links para visualizar seus pedidos ou atualizar os detalhes de seu perfil.

Uma restrição opcional é o Código Sob Demanda. Isso permite que servidores estendam ou personalizem temporariamente a funcionalidade de um cliente transferindo código executável, como snippets de JavaScript.

Como o REST Funciona:

Em um sistema RESTful, tudo é conceitualizado como um recurso (por exemplo, um usuário, um produto, um pedido). Cada recurso é identificado de forma única por uma URI. Por exemplo, GET /users pode recuperar uma lista de usuários, enquanto GET /users/123 recupera o usuário específico com ID 123.

Métodos HTTP (Verbos) padrão são empregados para realizar ações nesses recursos. GET é usado para recuperar um recurso. POST tipicamente cria um novo recurso ou pode ser usado para acionar um processo, com dados para o novo recurso enviados no corpo da requisição. PUT é usado para atualizar um recurso existente, geralmente exigindo uma substituição completa dos dados do recurso, e é idempotente (múltiplas requisições idênticas têm o mesmo efeito que uma única requisição). DELETE remove um recurso. PATCH permite atualizações parciais em um recurso existente. HEAD recupera metadados sobre um recurso, similar a GET, mas sem o corpo da resposta. OPTIONS é usado para obter informações sobre as opções de comunicação para o recurso alvo.

Códigos de Status, que fazem parte do padrão HTTP, são usados para indicar o resultado de uma requisição. Exemplos incluem 200 OK, 201 Created para criação bem-sucedida, 400 Bad Request para erros do cliente, 404 Not Found quando um recurso não existe, e 500 Internal Server Error para problemas no lado do servidor.

Em relação aos Formatos de Dados, JSON (JavaScript Object Notation) tornou-se o formato mais prevalente para troca de dados em APIs REST devido à sua natureza leve e facilidade de análise. No entanto, XML, HTML ou até mesmo texto simples também podem ser utilizados.

Prós do REST:

Contras do REST:

Quando Usar REST:

REST é uma excelente escolha para APIs públicas onde ampla adoção, facilidade de integração e interoperabilidade são importantes. É adequado para aplicações centradas em recursos onde operações CRUD (Criar, Ler, Atualizar, Excluir) padrão em entidades formam o modo principal de interação. Se aproveitar o cache HTTP for crucial para desempenho e escalabilidade, o alinhamento do REST com os padrões HTTP é uma vantagem significativa. Situações que exigem ausência de estado e escalabilidade horizontal também se beneficiam muito do estilo arquitetural RESTful. Além disso, quando a descobrabilidade através de hipermídia (HATEOAS) é desejada para permitir que os clientes naveguem dinamicamente na API, o REST fornece a estrutura para isso.

GraphQL: Uma Linguagem de Consulta para Sua API

O que é GraphQL?

GraphQL é uma linguagem de consulta especificamente projetada para APIs, e também engloba um runtime do lado do servidor para executar essas consultas usando um sistema de tipos que você define para seus dados. Originalmente desenvolvido pelo Facebook e posteriormente de código aberto em 2015, o GraphQL foi concebido para abordar diretamente algumas das limitações inerentes observadas em arquiteturas RESTful, notadamente os problemas gêmeos de over-fetching (buscar dados em excesso) e under-fetching (buscar dados insuficientes). Ele capacita os clientes a solicitar precisamente os dados que precisam, nem mais nem menos, tipicamente dentro de um único ciclo de requisição-resposta.

Conceitos Centrais do GraphQL:

A arquitetura do GraphQL é construída sobre vários conceitos fundamentais.

Um pilar é a Schema Definition Language (SDL). APIs GraphQL são rigorosamente definidas por um sistema de tipos forte. O servidor publica um schema que descreve meticulosamente todos os tipos de dados que um cliente tem permissão para consultar, bem como as intrincadas relações que existem entre esses tipos de dados. Este schema serve como um contrato vinculante entre o cliente e o servidor. Dentro da SDL, você define várias construções:

Outra característica distintiva é o uso típico de um Único Endpoint. Ao contrário do REST, que comumente emprega múltiplas URLs para representar diferentes recursos e operações, APIs GraphQL geralmente expõem apenas um endpoint (por exemplo, /graphql). Todas as requisições, sejam elas queries para buscar dados, mutations para modificar dados ou subscriptions para atualizações em tempo real, são direcionadas a este endpoint singular, geralmente via uma requisição HTTP POST.

Central para o poder do GraphQL é o conceito de Consultas Especificadas pelo Cliente. A aplicação cliente constrói uma string de consulta que especifica explicitamente exatamente quais dados ela requer. Isso pode incluir não apenas campos em um objeto primário, mas também campos em objetos relacionados, atravessando relações de dados complexas. O servidor então processa essa consulta e responde com um objeto JSON cuja estrutura espelha precisamente a estrutura da consulta submetida pelo cliente.

Como o GraphQL Funciona:

A interação em um sistema GraphQL segue um fluxo bem definido. Começa com a Definição do Schema, onde o servidor define suas capacidades de dados usando a SDL do GraphQL.

Subsequentemente, a Consulta do Cliente é construída. O cliente formula uma string de consulta GraphQL, detalhando os campos de dados específicos que ele precisa. Por exemplo:GraphQL

query GetUserDetails {
  user(id: "123") {
    id
    name
    email
    posts { # Fetch related posts
      title
      content
    }
  }
}

Esta consulta é então enviada em uma Requisição para o Servidor, geralmente como um payload JSON dentro de uma requisição HTTP POST, direcionada ao único endpoint GraphQL.

Ao receber a requisição, o Processamento do Servidor começa. Isso envolve várias sub-etapas. O servidor primeiro Analisa e Valida a consulta de entrada, verificando sua sintaxe e garantindo que ela esteja em conformidade com o schema definido. Se válida, a consulta passa para a Execução. O servidor executa a consulta invocando funções "resolver". Cada campo definido no schema GraphQL é suportado por uma função resolver correspondente. Um resolver é um pedaço de código responsável por buscar os dados para seu campo específico. Esses resolvers podem recuperar dados de várias fontes, como bancos de dados, outras APIs internas ou externas, ou até mesmo dados estáticos.

Finalmente, o servidor formula e envia uma Resposta para o Cliente. Esta resposta é um objeto JSON cuja estrutura espelha a forma da consulta original, contendo apenas os dados que foram explicitamente solicitados. Para a consulta de exemplo acima, a resposta pode parecer com:JSON

{
  "data": {
    "user": {
      "id": "123",
      "name": "Alice Wonderland",
      "email": "alice@example.com",
      "posts": [
        {
          "title": "My First Post",
          "content": "Hello world!"
        },
        {
          "title": "GraphQL is Cool",
          "content": "Learning about GraphQL..."
        }
      ]
    }
  }
}

Prós do GraphQL:

Contras do GraphQL:

Quando Usar GraphQL:

GraphQL é particularmente adequado para aplicações com clientes diversos, como aplicações web, aplicativos móveis e dispositivos IoT, todos os quais podem ter requisitos de dados variados e específicos. Ele brilha em situações onde minimizar a transferência de dados e reduzir o número de viagens de ida e volta na rede são críticos, por exemplo, em aplicações móveis operando em redes lentas ou não confiáveis. Para sistemas complexos onde os clientes precisam buscar dados de múltiplas fontes subjacentes ou navegar por relações de recursos profundamente aninhadas, o GraphQL oferece uma solução elegante. Se um contrato de API fortemente tipado, capacidades robustas de autodocumentação e evoluibilidade da API são altamente valorizados, o GraphQL oferece esses benefícios. Aplicações que exigem atualizações em tempo real via subscriptions podem aproveitar o suporte nativo do GraphQL para este recurso. Em última análise, o GraphQL é uma excelente escolha quando você deseja dar aos clientes mais poder e flexibilidade na forma como buscam dados, adaptando as requisições às suas necessidades precisas.

RPC vs. REST vs. GraphQL: Um Olhar Comparativo

CaracterísticaRPC (ex: gRPC)RESTGraphQL
ParadigmaOrientado a Ação/FunçãoOrientado a RecursoLinguagem de consulta de dados
EndpointsMúltiplos endpoints (um por procedimento)Múltiplos endpoints (um por recurso/coleção)Tipicamente um único endpoint (/graphql)
Busca de DadosServidor dita os dados retornados por procedimentoServidor dita os dados retornados por recursoCliente dita exatamente quais dados são necessários
Over/Under FetchingPropenso a ambos, baseado no design do procedimentoProblema comum (over-fetching/under-fetching)Resolve over/under-fetching
Uso de HTTPPode usar HTTP/2 (gRPC), ou outros transportesDepende muito de métodos HTTP, códigos de statusTipicamente usa HTTP POST, único endpoint

Explore more

Pratique o design de API no Apidog

Descubra uma forma mais fácil de construir e usar APIs