Aula 7 • Projeto 9 • Sistemas de Informacao
Protocolos de Comunicacao Web

REST, gRPC, GraphQL, WebSocket, TCP/UDP e WebTransport conectados a CQRS + MediatR + filas + telemetria.

REST gRPC GraphQL WebSocket MediatR Kafka/RabbitMQ OpenTelemetry Prometheus
Prof. Afonso Brandao • 2 horas • Marco 2026
Roteiro da aula
Parte 1
Panorama de protocolos web
Parte 2
CQRS in-process com MediatR
Parte 3
Filas para processamento assincrono
Parte 4
Telemetria com OTel e Prometheus
Objetivo: escolher o protocolo certo para cada tipo de comunicacao e garantir que o sistema seja observavel e resiliente sob carga e falhas.
Mapa de protocolos
Protocolo/Estilo Melhor para Trade-off principal
REST (HTTP) CRUD, APIs publicas e interoperabilidade Over/under fetching e contratos mais frouxos
gRPC (HTTP/2 + Protobuf) Servico-servico com baixa latencia Debug e consumo no browser exigem gateway/adaptacao
GraphQL Frontends com multiplas visoes de dados Governanca de schema e custo de queries complexas
WebSocket Tempo real full-duplex Estado de conexao e escalabilidade de conexoes abertas
TCP/UDP Sockets Protocolos custom e baixa latencia extrema Maior complexidade operacional
WebTransport (HTTP/3/QUIC) Streams + datagrams em browser moderno Ecossistema ainda em consolidacao
RESTful API

Quando usar

  • Operacoes de negocio com semantica clara de recurso.
  • Integracoes externas e documentacao via OpenAPI.
  • Cenarios em que cache HTTP traz ganho direto.
GET cacheavel PUT idempotente POST para comando

Pontos de atencao

  • Contratos devem evoluir sem quebrar clientes.
  • Timeouts e retries precisam respeitar idempotencia.
  • Nao misturar leitura pesada com escrita critica no mesmo endpoint.
gRPC

Vantagens praticas

  • Contrato tipado por .proto e serializacao eficiente.
  • Streaming client/server/bidirecional.
  • Baixa latencia para servicos internos.

Aplicacao no modulo

  • Servico de agregacao de metricas recebendo stream de eventos.
  • Gateway HTTP para traduzir chamadas do frontend.
  • MediatR no backend para desacoplar transporte da regra.
gRPC resolve bem comunicacao interna de alta frequencia. Para navegadores, geralmente combinamos com REST/GraphQL.
REST vs gRPC em .NET: caso CriarPedido
Perfeito. Vamos usar o mesmo caso nos dois: CriarPedido.

1. REST no backend .NET

Como você define

// DTO (objeto do body JSON)
public record CriarPedidoRequest(string ClienteId, List<ItemDto> Itens);
public record ItemDto(string ProdutoId, int Quantidade);
// Controller REST
[ApiController]
[Route("api/pedidos")]
public class PedidosController : ControllerBase
{
    [HttpPost]
    public IActionResult Criar([FromBody] CriarPedidoRequest req)
    {
        // regra de negocio...
        return Ok(new { pedidoId = "P123", status = "CRIADO" });
    }
}
Payload REST (body JSON)

Payload REST (o que vai no body)

POST /api/pedidos
Content-Type: application/json
{
  "clienteId": "C1",
  "itens": [
    { "produtoId": "P10", "quantidade": 2 },
    { "produtoId": "P20", "quantidade": 1 }
  ]
}

Resposta:

{
  "pedidoId": "P123",
  "status": "CRIADO"
}

Aqui o payload é JSON legível.

gRPC no backend .NET

2. gRPC no backend .NET

Como você define (contrato .proto)

syntax = "proto3";

service PedidoService {
  rpc CriarPedido (CriarPedidoRequest) returns (CriarPedidoResponse);
}

message CriarPedidoRequest {
  string cliente_id = 1;
  repeated Item itens = 2;
}

message Item {
  string produto_id = 1;
  int32 quantidade = 2;
}

message CriarPedidoResponse {
  string pedido_id = 1;
  string status = 2;
}

O .NET gera classes C# automaticamente desse .proto.

Servidor e cliente gRPC

Implementação do servidor

public class PedidoGrpcService : PedidoService.PedidoServiceBase
{
    public override Task<CriarPedidoResponse> CriarPedido(
        CriarPedidoRequest request, ServerCallContext context)
    {
        // regra de negocio...
        return Task.FromResult(new CriarPedidoResponse
        {
            PedidoId = "P123",
            Status = "CRIADO"
        });
    }
}

Chamada do cliente gRPC

var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new PedidoService.PedidoServiceClient(channel);

var resp = await client.CriarPedidoAsync(new CriarPedidoRequest
{
    ClienteId = "C1",
    Itens = { new Item { ProdutoId = "P10", Quantidade = 2 },
              new Item { ProdutoId = "P20", Quantidade = 1 } }
});
Então qual é o payload no gRPC?

3. Então qual é o “payload” no gRPC?

Logicamente é o mesmo dado (cliente, itens, etc).

A diferença é o formato na rede:

  1. REST envia texto JSON.
  2. gRPC envia bytes em Protocol Buffers (binário).

Ou seja:

  1. No REST você “enxerga” o payload fácil no Postman.
  2. No gRPC o payload real não é amigável para leitura humana, mas é menor e mais rápido.
4. Resumo mental simples
1. REST: “envio uma carta em texto (JSON) para uma URL”.
2. gRPC: “faço uma chamada de método (CriarPedido) com objeto tipado, e a rede leva isso em binário”.
GraphQL e WebSocket

GraphQL

Cliente pede exatamente os campos necessarios.

  • Excelente para telas ricas de dashboard.
  • Schema central para evolucao controlada.

WebSocket

Canal persistente full-duplex para tempo real.

  • Atualizacao live de cards e alertas.
  • Evita polling agressivo.

Combinacao comum

GraphQL para leitura + WebSocket para subscription/eventos.

  • Modelo ideal para interfaces responsivas.
  • Requer controle de autenticacao da conexao.
GraphQL no backend .NET

Exemplo com HotChocolate

// Program.cs
builder.Services
    .AddGraphQLServer()
    .AddQueryType<Query>()
    .AddMutationType<Mutation>();

var app = builder.Build();
app.MapGraphQL("/graphql");
app.Run();
// Tipos de entrada/saida
public record ItemDto(string ProdutoId, int Quantidade);
public record PedidoDto(string PedidoId, string ClienteId, List<ItemDto> Itens, string Status);
public record CriarPedidoInput(string ClienteId, List<ItemDto> Itens);

public class Query
{
    public PedidoDto PedidoPorId(string id) =>
        new("P123", "C1", new List<ItemDto> { new("P10", 2), new("P20", 1) }, "CRIADO");
}

public class Mutation
{
    public PedidoDto CriarPedido(CriarPedidoInput input) =>
        new("P123", input.ClienteId, input.Itens, "CRIADO");
}
Payload GraphQL (query)

Request HTTP para GraphQL

POST /graphql
Content-Type: application/json
{
  "query": "query Pedido($id: String!) { pedidoPorId(id: $id) { pedidoId clienteId status itens { produtoId quantidade } } }",
  "variables": {
    "id": "P123"
  }
}

Resposta:

{
  "data": {
    "pedidoPorId": {
      "pedidoId": "P123",
      "clienteId": "C1",
      "status": "CRIADO",
      "itens": [
        { "produtoId": "P10", "quantidade": 2 },
        { "produtoId": "P20", "quantidade": 1 }
      ]
    }
  }
}
Payload GraphQL (mutation)

Criando um pedido (mesmo caso do REST/gRPC)

POST /graphql
Content-Type: application/json
{
  "query": "mutation Criar($input: CriarPedidoInput!) { criarPedido(input: $input) { pedidoId status clienteId } }",
  "variables": {
    "input": {
      "clienteId": "C1",
      "itens": [
        { "produtoId": "P10", "quantidade": 2 },
        { "produtoId": "P20", "quantidade": 1 }
      ]
    }
  }
}

Resposta:

{
  "data": {
    "criarPedido": {
      "pedidoId": "P123",
      "status": "CRIADO",
      "clienteId": "C1"
    }
  }
}
REST vs GraphQL (mesmo payload)

REST

  • Voce chama endpoints diferentes.
  • Ex.: /api/pedidos/{id}, /api/clientes/{id}.
  • Resposta vem no formato definido pelo backend.

GraphQL

  • Voce chama um endpoint so: /graphql.
  • Escolhe os campos no corpo da query.
  • Resposta vem no formato pedido pelo cliente.
Resumo mental simples: GraphQL e "me devolva exatamente isso". REST e "me devolva o que esse endpoint foi desenhado para devolver".
Estrategias de testing por tecnologia
Tecnologia O que validar primeiro Testes principais Risco comum
REST Contrato HTTP, status code e validacao Unit + Integration + Contract Quebrar clientes por mudanca de payload
GraphQL Schema, resolvers e autorizacao por campo Schema snapshot + Integration + E2E de query N+1 e exposicao indevida de dados
gRPC Compatibilidade .proto e codigos de erro Contract + Integration + teste de streaming Breaking change de campo/mensagem
MediatR Comportamento de command/query handler Unit de handler + teste de pipeline behavior Regra dispersa fora do handler
Filas Idempotencia, retry e DLQ Integration com broker + teste de falha Duplicidade e perda silenciosa de mensagem
Exemplos de casos de teste por situacao
Situacao Caso de teste Resultado esperado
REST - payload invalido POST /api/pedidos sem clienteId HTTP 400 com mensagem de validacao
GraphQL - campo nao autorizado Query pedindo campo sensivel sem permissao Erro GraphQL de autorizacao e campo bloqueado
gRPC - deadline excedido Chamada com timeout curto em metodo lento Status DeadlineExceeded
MediatR - validacao de command Command com dados inconsistentes no pipeline behavior Falha de validacao sem executar o handler
Fila - processamento duplicado Reentrega da mesma mensagem para o consumidor Nenhuma duplicidade no banco (idempotencia)
Fila - falha persistente Consumidor falha ate esgotar retries Mensagem enviada para DLQ + metrica incrementada
Testing de REST e GraphQL no .NET

REST (WebApplicationFactory)

  • Teste endpoint, status code, headers e payload.
  • Valide cenarios de erro (400/404/409).
  • Inclua contrato com OpenAPI em CI.
var res = await client.PostAsJsonAsync("/api/pedidos", req);
res.StatusCode.Should().Be(HttpStatusCode.OK);
var body = await res.Content.ReadFromJsonAsync<PedidoResponse>();
body!.Status.Should().Be("CRIADO");

GraphQL (query + mutation)

  • Teste schema e autorizacao por campo sensivel.
  • Valide query permitida e query bloqueada.
  • Meça performance para evitar N+1.
var payload = new {
  query = "query { pedidoPorId(id:\"P123\"){ pedidoId status } }"
};
var res = await client.PostAsJsonAsync("/graphql", payload);
res.EnsureSuccessStatusCode();
Caso: GraphQL com campo nao autorizado
Situacao: Query pedindo campo sensivel sem permissao.
Esperado: Erro GraphQL de autorizacao e campo bloqueado.

Request (simplificado)

POST /graphql
Content-Type: application/json

{
  "query": "query { usuario(id:\"U1\") { id nome salario } }"
}

Observacao: salario e um campo sensivel.

Resposta esperada

{
  "errors": [
    {
      "message": "Nao autorizado para acessar o campo 'salario'.",
      "path": ["usuario", "salario"]
    }
  ],
  "data": {
    "usuario": {
      "id": "U1",
      "nome": "Ana",
      "salario": null
    }
  }
}
Testing de gRPC, MediatR e Filas

gRPC

  • Teste unary: 1 requisicao -> 1 resposta (como um endpoint REST simples).
  • Teste streaming: cliente e/ou servidor trocam varias mensagens no mesmo canal.
  • Valide deadlines/cancellation.
  • Fixe regras de versao no .proto (sem break).
Contract-first StatusCode Streaming

MediatR

  • Unit test de handler com dependencias mockadas.
  • Teste pipeline behaviors (validacao/log).
  • Separe testes de command e query.
Handler unitario Behavior test Sem transporte

Filas

  • Teste consumidor idempotente (reprocessar sem duplicar).
  • Force falha para validar retry e DLQ.
  • Verifique ordenacao/chaves quando aplicavel.
Retry DLQ Idempotencia
Regra pratica: manter ~70% unitarios, ~20% integracao e ~10% E2E para equilibrio entre velocidade e confiabilidade.
CQRS com MediatR (in-process)

Estrutura

  • Commands: mudam estado (write model).
  • Queries: leem estado (read model).
  • Handlers: implementam regra sem acoplar ao controller.
  • Pipeline behaviors: validacao, log, metricas, retry local.

Por que encaixa na aula de protocolos

  • Controller REST/gRPC vira adaptador de protocolo.
  • Regra de negocio permanece igual, independentemente do transporte.
  • Facilita evoluir de chamada sincrona para evento em fila.
Exemplo .NET com MediatR
// Command
public record RequestReportCommand(Guid DashboardId) : IRequest<Guid>;

// Handler
public class RequestReportHandler : IRequestHandler<RequestReportCommand, Guid>
{
    private readonly IReportQueue _queue;
    public RequestReportHandler(IReportQueue queue) => _queue = queue;

    public async Task<Guid> Handle(RequestReportCommand cmd, CancellationToken ct)
    {
        var operationId = Guid.NewGuid();
        await _queue.PublishAsync(new ReportRequested(operationId, cmd.DashboardId), ct);
        return operationId;
    }
}

// Controller REST
[HttpPost("reports")]
public async Task<IActionResult> Create([FromBody] CreateReportDto dto)
{
    var operationId = await _mediator.Send(new RequestReportCommand(dto.DashboardId));
    return Accepted($"/operations/{operationId}");
}
Filas no backend (out-of-process)

Fluxo base

  • API recebe comando e publica mensagem.
  • Broker persiste e distribui.
  • Worker .NET (BackgroundService) consome.

Tecnologias usuais

  • Kafka + Confluent.Kafka
  • RabbitMQ (AMQP)
  • MassTransit como camada de abstracao (opcional)

Padroes obrigatorios

  • Retry exponencial com jitter
  • Dead Letter Queue (DLQ)
  • Idempotencia e Outbox
Observabilidade: OpenTelemetry + Prometheus

OpenTelemetry (OTel)

  • Instrumenta traces, metrics e logs.
  • Correlacao fim-a-fim via trace-id/correlation-id.
  • Ajuda a localizar gargalo entre API, broker e worker.
Trace: latencia por span Metric: taxa e erro Log: contexto enriquecido

Prometheus

  • Scrape periodico no endpoint /metrics.
  • Series temporais para dashboards e alertas.
  • Ideal para acompanhar throughput e saude de consumidores.
Metricas minimas para fila + CQRS
Metrica Por que importa Sinal de risco
request_duration_ms (p95/p99) Experiencia do cliente no protocolo sincrono p95 crescente sem aumento de throughput
queue_depth / consumer_lag Saude do processamento assincrono Fila cresce por tempo prolongado
dlq_messages_total Erros nao recuperaveis picos apos deploy ou mudanca de schema
handler_failures_total Confiabilidade dos handlers CQRS taxa de erro acima do error budget
retry_attempts_total Instabilidade transitora de dependencias aumento continuo e latencia alta
Arquitetura final (end-to-end)
Fluxo principal Observabilidade Cliente REST/gRPC MediatR (Command) Outbox Broker (Kafka/RabbitMQ) Worker Banco / Read Model Atualizacao live via WebSocket para dashboard OpenTelemetry (API + Worker + headers de correlacao) Prometheus (/metrics) Alertas por SLO (latencia, erro, lag, DLQ)
Atividade de sala
Entrega em formato end-to-end com validacao black box
Instrucao: implementar um fluxo end-to-end em uma rota ja existente do Projeto 9 e preparar a demonstracao.
Tempo: 40 minutos para desenvolvimento + 20 minutos para apresentacao.

Requisitos da entrega

Item Descricao Criterio de aceite
Fluxo principal Codigo end-to-end funcional passando por rota ja existente do Projeto 9. Execucao completa sem quebra do fluxo.
Modelo de teste Validacao black box (entrada e saida), sem acoplamento ao internals. Evidencia de request, resposta e comportamento esperado.
Protocolo Escolha livre do grupo: REST, gRPC ou GraphQL. Justificar a escolha para o caso de uso implementado.
Camadas obrigatorias Rota -> MediatR (command/query) -> fila (quando aplicavel) -> persistencia/read model. Demonstrar passagem por cada etapa prevista.
Observabilidade Metricas Prometheus minimas para o fluxo implementado. Exibir metricas coletadas (latencia, erro, lag ou equivalente).