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).

Sobre este encontro

Protocolos de Comunicação Web · Prof. Afonso

Objetivo de aprendizagem

Ao final do encontro, o estudante deve ser capaz de aplicar ao projeto os conceitos de Protocolos de Comunicação Web. Escopo do encontro: Entenda HTTP, WebSockets e outros protocolos para comunicação web.

Estratégia do encontro

Exposição dialogada dos conceitos, alternada com aplicação guiada ao projeto do grupo, e fechamento com verificação do entendimento.

Estrutura do encontro

  1. Introducao: Protocolo e Decisao de Arquitetura
  2. 1. Mapa de Protocolos e Criterios de Escolha
  3. 2. REST no ASP.NET Core em Profundidade
  4. 3. gRPC no ASP.NET Core em Profundidade
  5. 4. GraphQL no ASP.NET Core em Profundidade
  6. 5. Estrategia de Testing (Black Box Primeiro)
  7. 6. CQRS com MediatR e Filas
  8. 7. Observabilidade Operacional com OpenTelemetry + Prometheus