Como Criar uma API Multi-Protocolo com REST, GraphQL e gRPC?

Ashley Innocent

Ashley Innocent

13 março 2026

Como Criar uma API Multi-Protocolo com REST, GraphQL e gRPC?

Em resumo

Construa APIs multi-protocolo separando a lógica de negócios das camadas de protocolo. Crie uma camada de domínio compartilhada e adicione adaptadores REST, GraphQL e gRPC por cima. A Modern PetstoreAPI demonstra esta arquitetura com modelos de dados consistentes em todos os três protocolos.

Introdução

Sua API atende a clientes web, aplicativos móveis e microsserviços internos. Clientes web querem REST para simplicidade. Aplicativos móveis querem GraphQL para reduzir a transferência de dados. Microsserviços querem gRPC para desempenho. Você constrói três APIs separadas?

Não. Você constrói uma API com três camadas de protocolo. A lógica de negócios permanece a mesma. Apenas os adaptadores de protocolo mudam. Esta é a arquitetura de API multi-protocolo.

A Modern PetstoreAPI implementa REST, GraphQL e gRPC a partir de um núcleo compartilhado. A mesma lógica da pet shop atende aos três protocolos com comportamento consistente.

💡
Se você está construindo ou testando APIs multi-protocolo, o Apidog suporta testes de REST, GraphQL e gRPC em uma única ferramenta. Você pode verificar se todos os protocolos retornam dados consistentes e testar fluxos de trabalho entre protocolos.
button

Neste guia, você aprenderá como arquitetar APIs multi-protocolo, implementar camadas de protocolo e garantir a consistência entre protocolos usando a Modern PetstoreAPI como referência.

Arquitetura Multi-Protocolo

APIs multi-protocolo separam as preocupações em camadas.

Arquitetura em Camadas

┌─────────────────────────────────────────┐
│  Camada de Protocolo (REST/GraphQL/gRPC)│
├─────────────────────────────────────────┤
│  Camada de Aplicação (Casos de Uso)     │
├─────────────────────────────────────────┤
│  Camada de Domínio (Lógica de Negócios) │
├─────────────────────────────────────────┤
│  Camada de Dados (Banco de Dados, Cache)│
└─────────────────────────────────────────┘

Camada de Protocolo: Lida com HTTP, consultas GraphQL, chamadas gRPC Camada de Aplicação: Orquestra casos de uso (criar pet, fazer pedido) Camada de Domínio: Regras de negócios (validação, cálculos) Camada de Dados: Persistência (banco de dados, cache)

Princípios Fundamentais

1. Núcleo agnóstico ao protocolo

A lógica de negócios não conhece HTTP, GraphQL ou gRPC. Ela trabalha com objetos de domínio.

2. Adaptadores de protocolo finos

As camadas de protocolo traduzem entre formatos de protocolo e objetos de domínio. Elas não contêm lógica de negócios.

3. Modelos de dados compartilhados

Todos os protocolos usam os mesmos modelos de domínio internamente, garantindo consistência.

4. Implantação independente

Cada protocolo pode ser implantado separadamente, se necessário.

Camada de Domínio Compartilhada

A camada de domínio contém a lógica de negócios compartilhada entre todos os protocolos.

Modelos de Domínio

// Modelo de domínio (agnóstico ao protocolo)
class Pet {
  id: string;
  name: string;
  species: Species;
  status: PetStatus;
  price: number;

  constructor(data: PetData) {
    this.validate(data);
    Object.assign(this, data);
  }

  validate(data: PetData): void {
    if (!data.name || data.name.length < 2) {
      throw new ValidationError('Name must be at least 2 characters');
    }
    if (data.price < 0) {
      throw new ValidationError('Price cannot be negative');
    }
  }

  adopt(userId: string): Order {
    if (this.status !== PetStatus.AVAILABLE) {
      throw new BusinessError('Pet is not available for adoption');
    }
    this.status = PetStatus.ADOPTED;
    return new Order({
      petId: this.id,
      userId,
      total: this.price
    });
  }
}

Este modelo funciona para REST, GraphQL e gRPC. A validação e as regras de negócios são as mesmas.

Casos de Uso

// Caso de uso (agnóstico ao protocolo)
class AdoptPetUseCase {
  constructor(
    private petRepository: PetRepository,
    private orderRepository: OrderRepository
  ) {}

  async execute(petId: string, userId: string): Promise<Order> {
    const pet = await this.petRepository.findById(petId);
    if (!pet) {
      throw new NotFoundError('Pet not found');
    }

    const order = pet.adopt(userId);
    await this.petRepository.save(pet);
    await this.orderRepository.save(order);

    return order;
  }
}

Este caso de uso funciona independentemente de ser chamado por REST, GraphQL ou gRPC.

Camada de Protocolo REST

A camada REST traduz requisições HTTP para operações de domínio.

Controller REST

// Adaptador REST
class PetsController {
  constructor(private adoptPetUseCase: AdoptPetUseCase) {}

  async adoptPet(req: Request, res: Response): Promise<void> {
    try {
      const { petId } = req.params;
      const { userId } = req.body;

      const order = await this.adoptPetUseCase.execute(petId, userId);

      res.status(201).json({
        id: order.id,
        petId: order.petId,
        userId: order.userId,
        total: order.total,
        status: order.status
      });
    } catch (error) {
      this.handleError(error, res);
    }
  }

  private handleError(error: Error, res: Response): void {
    if (error instanceof NotFoundError) {
      res.status(404).json({
        type: 'https://petstoreapi.com/errors/not-found',
        title: 'Not Found',
        status: 404,
        detail: error.message
      });
    } else if (error instanceof ValidationError) {
      res.status(400).json({
        type: 'https://petstoreapi.com/errors/validation-error',
        title: 'Validation Error',
        status: 400,
        detail: error.message
      });
    } else {
      res.status(500).json({
        type: 'https://petstoreapi.com/errors/internal-error',
        title: 'Internal Server Error',
        status: 500
      });
    }
  }
}

Rotas REST

app.post('/v1/pets/:petId/adopt', (req, res) =>
  petsController.adoptPet(req, res)
);

Endpoints REST da Modern PetstoreAPI

Camada de Protocolo GraphQL

A camada GraphQL traduz consultas GraphQL para operações de domínio.

Esquema GraphQL

type Pet {
  id: ID!
  name: String!
  species: Species!
  status: PetStatus!
  price: Float!
}

type Order {
  id: ID!
  petId: ID!
  userId: ID!
  total: Float!
  status: OrderStatus!
}

type Mutation {
  adoptPet(petId: ID!, userId: ID!): Order!
}

Resolver GraphQL

// Adaptador GraphQL
const resolvers = {
  Mutation: {
    adoptPet: async (
      _parent: any,
      args: { petId: string; userId: string },
      context: Context
    ): Promise<Order> => {
      try {
        return await context.adoptPetUseCase.execute(
          args.petId,
          args.userId
        );
      } catch (error) {
        throw new GraphQLError(error.message, {
          extensions: {
            code: error instanceof NotFoundError ? 'NOT_FOUND' :
                  error instanceof ValidationError ? 'BAD_USER_INPUT' :
                  'INTERNAL_SERVER_ERROR'
          }
        });
      }
    }
  }
};

Requisição GraphQL

mutation {
  adoptPet(
    petId: "019b4132-70aa-764f-b315-e2803d882a24"
    userId: "user-123"
  ) {
    id
    total
    status
  }
}

Esquema GraphQL da Modern PetstoreAPI

Camada de Protocolo gRPC

A camada gRPC traduz mensagens do Protocol Buffer para operações de domínio.

Definição do Protocol Buffer

syntax = "proto3";

package petstore.v1;

service PetService {
  rpc AdoptPet(AdoptPetRequest) returns (AdoptPetResponse);
}

message AdoptPetRequest {
  string pet_id = 1;
  string user_id = 2;
}

message AdoptPetResponse {
  string order_id = 1;
  string pet_id = 2;
  string user_id = 3;
  double total = 4;
  string status = 5;
}

Implementação do Serviço gRPC

// Adaptador gRPC
class PetServiceImpl implements IPetService {
  constructor(private adoptPetUseCase: AdoptPetUseCase) {}

  async adoptPet(
    call: ServerUnaryCall<AdoptPetRequest, AdoptPetResponse>,
    callback: sendUnaryData<AdoptPetResponse>
  ): Promise<void> {
    try {
      const { petId, userId } = call.request;

      const order = await this.adoptPetUseCase.execute(petId, userId);

      callback(null, {
        orderId: order.id,
        petId: order.petId,
        userId: order.userId,
        total: order.total,
        status: order.status
      });
    } catch (error) {
      callback({
        code: error instanceof NotFoundError ? status.NOT_FOUND :
              error instanceof ValidationError ? status.INVALID_ARGUMENT :
              status.INTERNAL,
        message: error.message
      });
    }
  }
}

Serviço gRPC da Modern PetstoreAPI

Como a Modern PetstoreAPI Implementa Multi-Protocolo

A Modern PetstoreAPI demonstra a arquitetura multi-protocolo com exemplos reais.

Visão Geral da Arquitetura

Modern PetstoreAPI
├── Camada de Domínio
│   ├── Pet (entidade)
│   ├── Order (entidade)
│   └── Casos de Uso
│       ├── CreatePet
│       ├── AdoptPet
│       └── PlaceOrder
├── Camada REST
│   ├── /v1/pets
│   ├── /v1/orders
│   └── especificação OpenAPI 3.2
├── Camada GraphQL
│   ├── Resolvers de consulta
│   ├── Resolvers de mutação
│   └── Esquema GraphQL
└── Camada gRPC
    ├── PetService
    ├── OrderService
    └── Definições .proto

Modelos de Dados Consistentes

Todos os protocolos retornam os mesmos dados:

REST:

{
  "id": "019b4132-70aa-764f-b315-e2803d882a24",
  "name": "Fluffy",
  "species": "CAT"
}

GraphQL:

{
  "data": {
    "pet": {
      "id": "019b4132-70aa-764f-b315-e2803d882a24",
      "name": "Fluffy",
      "species": "CAT"
    }
  }
}

gRPC:

{
  pet_id: "019b4132-70aa-764f-b315-e2803d882a24"
  name: "Fluffy"
  species: CAT
}

Mesmos dados, formatos diferentes.

Validação Compartilhada

A validação ocorre na camada de domínio, então todos os protocolos impõem as mesmas regras:

// Validação de domínio (compartilhada)
if (name.length < 2) {
  throw new ValidationError('Name must be at least 2 characters');
}

REST retorna:

{
  "type": "https://petstoreapi.com/errors/validation-error",
  "status": 400,
  "detail": "Name must be at least 2 characters"
}

GraphQL retorna:

{
  "errors": [{
    "message": "Name must be at least 2 characters",
    "extensions": {"code": "BAD_USER_INPUT"}
  }]
}

gRPC retorna:

code: INVALID_ARGUMENT
message: "Name must be at least 2 characters"

Mesma validação, formatos de erro específicos do protocolo.

Testando APIs Multi-Protocolo com Apidog

Apidog suporta o teste dos três protocolos.

Testar Endpoint REST

POST https://petstoreapi.com/v1/pets/019b4132-70aa-764f-b315-e2803d882a24/adopt
Content-Type: application/json

{
  "userId": "user-123"
}

Testar Mutação GraphQL

mutation {
  adoptPet(
    petId: "019b4132-70aa-764f-b315-e2803d882a24"
    userId: "user-123"
  ) {
    id
    total
  }
}

Testar Serviço gRPC

grpc.petstore.v1.PetService/AdoptPet
{
  "pet_id": "019b4132-70aa-764f-b315-e2803d882a24",
  "user_id": "user-123"
}

Verificar Consistência

Teste se todos os três protocolos retornam os mesmos dados:

  1. Chamar o endpoint REST
  2. Chamar a mutação GraphQL
  3. Chamar o serviço gRPC
  4. Comparar os resultados

O Apidog pode automatizar este teste entre protocolos.

Estratégias de Implantação

Estratégia 1: Serviço Único

Implante todos os protocolos em um único serviço:

┌─────────────────────────┐
│  Serviço PetstoreAPI    │
│  ├── REST (porta 8080)  │
│  ├── GraphQL (porta 8081)│
│  └── gRPC (porta 50051) │
└─────────────────────────┘

Prós: Implantação simples, recursos compartilhados Contras: Todos os protocolos escalam juntos

Estratégia 2: Serviços Separados

Implante cada protocolo separadamente:

┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│ Serviço REST │  │ Serviço GraphQL│  │ Serviço gRPC │
│ (porta 8080) │  │ (porta 8081) │  │ (porta 50051)│
└──────────────┘  └──────────────┘  └──────────────┘
       │                 │                  │
       └─────────────────┴──────────────────┘
                         │
                  ┌──────────────┐
                  │ Núcleo Compartilhado│
                  │   Biblioteca    │
                  └──────────────┘

Prós: Escalonamento independente, isolamento de protocolo Contras: Implantação mais complexa

Estratégia 3: Gateway de API

Use um gateway de API para rotear para backends específicos do protocolo:

                ┌─────────────┐
                │ API Gateway │
                └─────────────┘
                       │
        ┌──────────────┼──────────────┐
        │              │              │
┌───────▼──────┐ ┌────▼─────┐ ┌──────▼──────┐
│ Backend REST │ │ GraphQL  │ │ Backend gRPC│
└──────────────┘ └──────────┘ └─────────────┘

Prós: Roteamento centralizado, limitação de taxa, autenticação Contras: Latência adicional, complexidade do gateway

A Modern PetstoreAPI usa a Estratégia 1 para simplicidade.

Conclusão

APIs multi-protocolo oferecem flexibilidade aos clientes sem duplicar a lógica de negócios. Ao separar as camadas de protocolo da lógica de domínio, você pode suportar REST, GraphQL e gRPC a partir de um núcleo compartilhado.

A Modern PetstoreAPI demonstra esta arquitetura com modelos de dados consistentes, validação compartilhada e adaptadores específicos do protocolo. Quer os clientes usem REST para simplicidade, GraphQL para flexibilidade ou gRPC para desempenho, eles acessam a mesma pet shop com as mesmas regras de negócio.

Teste suas APIs multi-protocolo com Apidog para garantir a consistência entre os protocolos. Explore a Modern PetstoreAPI para ver a arquitetura multi-protocolo em ação.

button

Perguntas Frequentes

Preciso dar suporte aos três protocolos?

Não. Comece com REST para APIs públicas. Adicione GraphQL se os clientes precisarem de busca de dados flexível. Adicione gRPC para microsserviços internos. Adicione protocolos apenas quando tiver um caso de uso claro.

Como mantenho os protocolos consistentes?

Compartilhe a lógica de negócios em uma camada de domínio. Os adaptadores de protocolo devem apenas traduzir formatos, não conter regras de negócios. Teste todos os protocolos para verificar se retornam os mesmos dados.

Posso versionar os protocolos de forma independente?

Sim. REST pode estar na v2 enquanto GraphQL está na v1. Mas isso cria complexidade. Tente manter os protocolos sincronizados sempre que possível.

Como faço a autenticação em todos os protocolos?

Use a mesma autenticação em todos os protocolos. REST usa tokens Bearer em cabeçalhos. GraphQL usa os mesmos tokens. gRPC usa metadados. A camada de domínio valida os tokens da mesma forma.

E quanto a WebSocket e SSE?

WebSocket e SSE são protocolos de transporte, não protocolos de API. Você pode adicioná-los junto com REST/GraphQL/gRPC para atualizações em tempo real. A Modern PetstoreAPI inclui ambos.

Como documento APIs multi-protocolo?

Use OpenAPI para REST, esquema GraphQL para GraphQL e arquivos .proto para gRPC. A Modern PetstoreAPI fornece todos os três em https://docs.petstoreapi.com/

Posso usar bancos de dados diferentes para protocolos diferentes?

Sim, mas isso cria desafios de consistência. É melhor usar a mesma camada de dados para todos os protocolos. Deixe que os adaptadores de protocolo lidem com as diferenças de formato.

Como testo APIs multi-protocolo?

Use o Apidog para testar todos os protocolos em uma única ferramenta. Crie conjuntos de testes que verifiquem a consistência entre os protocolos. Teste se REST, GraphQL e gRPC retornam os mesmos dados para as mesmas operações.

Pratique o design de API no Apidog

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